feat(report): 报表图表管理
1.报表管理(样品进度报表,检测项目数据,样品领样记录,设备使用记录)
2.数字化语音看板
3.智能图表
已添加67个文件
已修改3个文件
4341 ■■■■■ 文件已修改
pom.xml 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
report-server/pom.xml 52 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
report-server/src/main/java/com/ruoyi/report/controller/DashboardController.java 82 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
report-server/src/main/java/com/ruoyi/report/controller/NormalDistributionController.java 61 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
report-server/src/main/java/com/ruoyi/report/controller/PassRateController.java 71 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
report-server/src/main/java/com/ruoyi/report/controller/ReportDeviceRecordController.java 55 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
report-server/src/main/java/com/ruoyi/report/controller/SampleProgressController.java 62 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
report-server/src/main/java/com/ruoyi/report/controller/SampleRecordController.java 54 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
report-server/src/main/java/com/ruoyi/report/controller/SpcChartController.java 70 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
report-server/src/main/java/com/ruoyi/report/controller/TestItemDataController.java 73 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
report-server/src/main/java/com/ruoyi/report/controller/WorkStatisticsController.java 53 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
report-server/src/main/java/com/ruoyi/report/dto/DashboardDto.java 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
report-server/src/main/java/com/ruoyi/report/dto/DeviceRecordDto.java 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
report-server/src/main/java/com/ruoyi/report/dto/NormalDistributionDto.java 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
report-server/src/main/java/com/ruoyi/report/dto/PassRateDto.java 41 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
report-server/src/main/java/com/ruoyi/report/dto/SampleProgressDto.java 36 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
report-server/src/main/java/com/ruoyi/report/dto/SampleRecordDto.java 33 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
report-server/src/main/java/com/ruoyi/report/dto/SpcChartDto.java 41 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
report-server/src/main/java/com/ruoyi/report/dto/TestItemDataDto.java 41 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
report-server/src/main/java/com/ruoyi/report/dto/WorkStatisticsDto.java 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
report-server/src/main/java/com/ruoyi/report/mapper/DashboardMapper.java 78 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
report-server/src/main/java/com/ruoyi/report/mapper/NormalDistributionMapper.java 31 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
report-server/src/main/java/com/ruoyi/report/mapper/PassRateMapper.java 41 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
report-server/src/main/java/com/ruoyi/report/mapper/ReportDeviceRecordMapper.java 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
report-server/src/main/java/com/ruoyi/report/mapper/SampleProgressMapper.java 33 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
report-server/src/main/java/com/ruoyi/report/mapper/SampleRecordMapper.java 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
report-server/src/main/java/com/ruoyi/report/mapper/SpcChartMapper.java 32 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
report-server/src/main/java/com/ruoyi/report/mapper/TestItemDataMapper.java 37 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
report-server/src/main/java/com/ruoyi/report/mapper/WorkStatisticsMapper.java 32 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
report-server/src/main/java/com/ruoyi/report/service/DashboardService.java 46 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
report-server/src/main/java/com/ruoyi/report/service/NormalDistributionService.java 34 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
report-server/src/main/java/com/ruoyi/report/service/PassRateService.java 39 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
report-server/src/main/java/com/ruoyi/report/service/ReportDeviceRecordService.java 31 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
report-server/src/main/java/com/ruoyi/report/service/SampleProgressService.java 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
report-server/src/main/java/com/ruoyi/report/service/SampleRecordService.java 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
report-server/src/main/java/com/ruoyi/report/service/SpcChartService.java 39 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
report-server/src/main/java/com/ruoyi/report/service/TestItemDataService.java 41 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
report-server/src/main/java/com/ruoyi/report/service/WorkStatisticsService.java 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
report-server/src/main/java/com/ruoyi/report/service/impl/DashboardServiceImpl.java 107 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
report-server/src/main/java/com/ruoyi/report/service/impl/NormalDistributionServiceImpl.java 193 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
report-server/src/main/java/com/ruoyi/report/service/impl/PassRateServiceImpl.java 122 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
report-server/src/main/java/com/ruoyi/report/service/impl/ReportDeviceRecordServiceImpl.java 61 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
report-server/src/main/java/com/ruoyi/report/service/impl/SampleProgressServiceImpl.java 125 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
report-server/src/main/java/com/ruoyi/report/service/impl/SampleRecordServiceImpl.java 89 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
report-server/src/main/java/com/ruoyi/report/service/impl/SpcChartServiceImpl.java 267 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
report-server/src/main/java/com/ruoyi/report/service/impl/TestItemDataServiceImpl.java 144 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
report-server/src/main/java/com/ruoyi/report/service/impl/WorkStatisticsServiceImpl.java 103 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
report-server/src/main/java/com/ruoyi/report/vo/DashboardOverviewVo.java 42 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
report-server/src/main/java/com/ruoyi/report/vo/DeviceRecordVo.java 54 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
report-server/src/main/java/com/ruoyi/report/vo/NormalDistributionVo.java 42 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
report-server/src/main/java/com/ruoyi/report/vo/ParetoVo.java 23 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
report-server/src/main/java/com/ruoyi/report/vo/RankingVo.java 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
report-server/src/main/java/com/ruoyi/report/vo/SampleProgressVo.java 57 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
report-server/src/main/java/com/ruoyi/report/vo/SampleRecordVo.java 48 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
report-server/src/main/java/com/ruoyi/report/vo/SpcResultVo.java 58 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
report-server/src/main/java/com/ruoyi/report/vo/TaskCalendarVo.java 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
report-server/src/main/java/com/ruoyi/report/vo/TestItemDataVo.java 57 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
report-server/src/main/java/com/ruoyi/report/vo/WorkStatisticsVo.java 36 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
report-server/src/main/resources/mapper/DashboardMapper.xml 164 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
report-server/src/main/resources/mapper/NormalDistributionMapper.xml 57 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
report-server/src/main/resources/mapper/PassRateMapper.xml 126 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
report-server/src/main/resources/mapper/ReportDeviceRecordMapper.xml 73 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
report-server/src/main/resources/mapper/SampleProgressMapper.xml 98 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
report-server/src/main/resources/mapper/SampleRecordMapper.xml 67 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
report-server/src/main/resources/mapper/SpcChartMapper.xml 57 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
report-server/src/main/resources/mapper/TestItemDataMapper.xml 132 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
report-server/src/main/resources/mapper/WorkStatisticsMapper.xml 87 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/pom.xml 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/resources/application-druid.yml 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/resources/report_chart_sql.sql 177 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pom.xml
@@ -278,6 +278,13 @@
                <version>${ruoyi.version}</version>
            </dependency>
            <!--报表图表模块-->
            <dependency>
                <groupId>com.ruoyi</groupId>
                <artifactId>report-server</artifactId>
                <version>${ruoyi.version}</version>
            </dependency>
            <!-- minio -->
            <dependency>
                <groupId>io.minio</groupId>
@@ -392,6 +399,7 @@
        <module>cnas-device</module>
        <module>cnas-process</module>
        <module>cnas-personnel</module>
        <module>report-server</module>
    </modules>
    <packaging>pom</packaging>
report-server/pom.xml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,52 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>ruoyi</artifactId>
        <groupId>com.ruoyi</groupId>
        <version>3.8.9</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <artifactId>report-server</artifactId>
    <dependencies>
        <!-- é€šç”¨å·¥å…·-->
        <dependency>
            <groupId>com.ruoyi</groupId>
            <artifactId>ruoyi-common</artifactId>
        </dependency>
        <!-- æ ¸å¿ƒæ¨¡å—-->
        <dependency>
            <groupId>com.ruoyi</groupId>
            <artifactId>ruoyi-framework</artifactId>
        </dependency>
        <!--基础模块-->
        <dependency>
            <groupId>com.ruoyi</groupId>
            <artifactId>basic-server</artifactId>
        </dependency>
        <!-- ç³»ç»Ÿæ¨¡å—-->
        <dependency>
            <groupId>com.ruoyi</groupId>
            <artifactId>ruoyi-system</artifactId>
        </dependency>
        <!--业务模块-->
        <dependency>
            <groupId>com.ruoyi</groupId>
            <artifactId>inspect-server</artifactId>
        </dependency>
    </dependencies>
    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>
</project>
report-server/src/main/java/com/ruoyi/report/controller/DashboardController.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,82 @@
package com.ruoyi.report.controller;
import com.ruoyi.common.core.domain.Result;
import com.ruoyi.report.dto.DashboardDto;
import com.ruoyi.report.service.DashboardService;
import com.ruoyi.report.vo.DashboardOverviewVo;
import com.ruoyi.report.vo.RankingVo;
import com.ruoyi.report.vo.TaskCalendarVo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Map;
/**
 * æ•°å­—化语音看板控制器
 */
@RequestMapping("/report/dashboard")
@RestController
@AllArgsConstructor
@Api(tags = "数字化语音看板")
public class DashboardController {
    private DashboardService dashboardService;
    /**
     * èŽ·å–çœ‹æ¿æ¦‚è§ˆæ•°æ®
     */
    @ApiOperation(value = "获取看板概览数据")
    @GetMapping("/overview")
    public Result overview(DashboardDto dto) {
        return Result.success(dashboardService.getOverview(dto));
    }
    /**
     * åŽ†å²15天数据
     */
    @ApiOperation(value = "历史15天数据")
    @GetMapping("/history15Days")
    public Result history15Days(DashboardDto dto) {
        return Result.success(dashboardService.getHistory15Days(dto));
    }
    /**
     * æœªæ¥15天任务
     */
    @ApiOperation(value = "未来15天任务")
    @GetMapping("/future15Days")
    public Result future15Days(DashboardDto dto) {
        return Result.success(dashboardService.getFuture15Days(dto));
    }
    /**
     * æäº¤æŽ’行
     */
    @ApiOperation(value = "提交排行")
    @GetMapping("/ranking")
    public Result ranking(DashboardDto dto) {
        return Result.success(dashboardService.getRanking(dto));
    }
    /**
     * æ£€éªŒç»“果统计
     */
    @ApiOperation(value = "检验结果统计")
    @GetMapping("/insResult")
    public Result insResult(DashboardDto dto) {
        return Result.success(dashboardService.getInsResult(dto));
    }
    /**
     * èŽ·å–è¯­éŸ³æ’­æŠ¥é˜Ÿåˆ—
     */
    @ApiOperation(value = "获取语音播报队列")
    @GetMapping("/voiceQueue")
    public Result voiceQueue() {
        return Result.success(dashboardService.getVoiceQueue());
    }
}
report-server/src/main/java/com/ruoyi/report/controller/NormalDistributionController.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,61 @@
package com.ruoyi.report.controller;
import com.ruoyi.common.core.domain.Result;
import com.ruoyi.report.dto.NormalDistributionDto;
import com.ruoyi.report.service.NormalDistributionService;
import com.ruoyi.report.vo.NormalDistributionVo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletResponse;
/**
 * æ­£æ€åˆ†å¸ƒå›¾æŽ§åˆ¶å™¨
 */
@RequestMapping("/chart/normalDistribution")
@RestController
@AllArgsConstructor
@Api(tags = "正态分布图")
public class NormalDistributionController {
    private NormalDistributionService normalDistributionService;
    /**
     * æ­£æ€åˆ†å¸ƒåˆ†æž
     */
    @ApiOperation(value = "正态分布分析")
    @PostMapping("/analyze")
    public Result analyze(@RequestBody NormalDistributionDto dto) {
        return Result.success(normalDistributionService.analyze(dto));
    }
    /**
     * å¯¼å‡ºåˆ†æžæ•°æ®
     */
    @ApiOperation(value = "导出分析数据")
    @GetMapping("/export")
    public void export(NormalDistributionDto dto, HttpServletResponse response) {
        normalDistributionService.export(dto, response);
    }
    /**
     * æŸ¥è¯¢å¯é€‰æ£€æµ‹é¡¹
     */
    @ApiOperation(value = "查询可选检测项")
    @GetMapping("/itemNames")
    public Result getItemNames(NormalDistributionDto dto) {
        return Result.success(normalDistributionService.getItemNames(dto));
    }
    /**
     * æŸ¥è¯¢å¯é€‰æ ·å“åç§°åˆ—表
     */
    @ApiOperation(value = "查询可选样品名称列表")
    @GetMapping("/projectList")
    public Result getProjectList(NormalDistributionDto dto) {
        return Result.success(normalDistributionService.getSampleNames(dto));
    }
}
report-server/src/main/java/com/ruoyi/report/controller/PassRateController.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,71 @@
package com.ruoyi.report.controller;
import com.ruoyi.common.core.domain.Result;
import com.ruoyi.report.dto.PassRateDto;
import com.ruoyi.report.service.PassRateService;
import com.ruoyi.report.vo.ParetoVo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Map;
/**
 * åˆæ ¼çŽ‡ç»Ÿè®¡æŽ§åˆ¶å™¨
 */
@RequestMapping("/chart/passRate")
@RestController
@AllArgsConstructor
@Api(tags = "合格率统计")
public class PassRateController {
    private PassRateService passRateService;
    /**
     * åŽŸææ–™åˆæ ¼çŽ‡
     */
    @ApiOperation(value = "原材料合格率")
    @GetMapping("/rawMaterial")
    public Result rawMaterial(PassRateDto dto) {
        return Result.success(passRateService.getRawMaterialPassRate(dto));
    }
    /**
     * ä¾›åº”商不合格统计
     */
    @ApiOperation(value = "供应商不合格统计")
    @GetMapping("/supplier")
    public Result supplier(PassRateDto dto) {
        return Result.success(passRateService.getSupplierUnqualified(dto));
    }
    /**
     * å¸•累托图数据
     */
    @ApiOperation(value = "帕累托图数据")
    @GetMapping("/pareto")
    public Result pareto(PassRateDto dto) {
        return Result.success(passRateService.getPareto(dto));
    }
    /**
     * å·¥åºåˆæ ¼çއ
     */
    @ApiOperation(value = "工序合格率")
    @GetMapping("/process")
    public Result process(PassRateDto dto) {
        return Result.success(passRateService.getProcessPassRate(dto));
    }
    /**
     * æœºå°ä¸åˆæ ¼ç»Ÿè®¡
     */
    @ApiOperation(value = "机台不合格统计")
    @GetMapping("/machine")
    public Result machine(PassRateDto dto) {
        return Result.success(passRateService.getMachineUnqualified(dto));
    }
}
report-server/src/main/java/com/ruoyi/report/controller/ReportDeviceRecordController.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,55 @@
package com.ruoyi.report.controller;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.common.core.domain.Result;
import com.ruoyi.report.dto.DeviceRecordDto;
import com.ruoyi.report.service.ReportDeviceRecordService;
import com.ruoyi.report.vo.DeviceRecordVo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
import java.util.Map;
/**
 * è®¾å¤‡ä½¿ç”¨è®°å½•控制器
 */
@RequestMapping("/report/deviceRecord")
@RestController
@AllArgsConstructor
@Api(tags = "设备使用记录报表")
public class ReportDeviceRecordController {
    private ReportDeviceRecordService reportDeviceRecordService;
    /**
     * åˆ†é¡µæŸ¥è¯¢è®¾å¤‡ä½¿ç”¨è®°å½•
     */
    @ApiOperation(value = "分页查询设备使用记录")
    @GetMapping("/page")
    public Result page(DeviceRecordDto dto, Page page) {
        return Result.success(reportDeviceRecordService.pageDeviceRecord(page, dto));
    }
    /**
     * è®¾å¤‡ä½¿ç”¨ç»Ÿè®¡
     */
    @ApiOperation(value = "设备使用统计")
    @GetMapping("/statistics")
    public Result statistics(DeviceRecordDto dto) {
        return Result.success(reportDeviceRecordService.getStatistics(dto));
    }
    /**
     * å¯¼å‡ºè®°å½•
     */
    @ApiOperation(value = "导出记录")
    @GetMapping("/export")
    public void export(DeviceRecordDto dto, HttpServletResponse response) {
        reportDeviceRecordService.exportDeviceRecord(dto, response);
    }
}
report-server/src/main/java/com/ruoyi/report/controller/SampleProgressController.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,62 @@
package com.ruoyi.report.controller;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.common.core.domain.Result;
import com.ruoyi.report.dto.SampleProgressDto;
import com.ruoyi.report.service.SampleProgressService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletResponse;
import java.util.Map;
/**
 * æ ·å“è¿›åº¦æŠ¥è¡¨æŽ§åˆ¶å™¨
 */
@RequestMapping("/report/sampleProgress")
@RestController
@AllArgsConstructor
@Api(tags = "样品进度报表")
public class SampleProgressController {
    private SampleProgressService sampleProgressService;
    /**
     * åˆ†é¡µæŸ¥è¯¢æ ·å“è¿›åº¦
     */
    @ApiOperation(value = "分页查询样品进度")
    @GetMapping("/page")
    public Result page(SampleProgressDto dto, Page page) {
        return Result.success(sampleProgressService.pageSampleProgress(page, dto));
    }
    /**
     * æŸ¥è¯¢æ ·å“è¿›åº¦ç»Ÿè®¡
     */
    @ApiOperation(value = "查询样品进度统计")
    @GetMapping("/statistics")
    public Result statistics(SampleProgressDto dto) {
        return Result.success(sampleProgressService.getStatistics(dto));
    }
    /**
     * å¯¼å‡ºæ ·å“è¿›åº¦æŠ¥è¡¨
     */
    @ApiOperation(value = "导出样品进度报表")
    @GetMapping("/export")
    public void export(SampleProgressDto dto, HttpServletResponse response) {
        sampleProgressService.exportSampleProgress(dto, response);
    }
    /**
     * æŸ¥è¯¢è¿›åº¦å¯è§†åŒ–数据
     */
    @ApiOperation(value = "查询进度可视化数据")
    @GetMapping("/chart")
    public Result getChartData(SampleProgressDto dto) {
        return Result.success(sampleProgressService.getChartData(dto));
    }
}
report-server/src/main/java/com/ruoyi/report/controller/SampleRecordController.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,54 @@
package com.ruoyi.report.controller;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.common.core.domain.Result;
import com.ruoyi.report.dto.SampleRecordDto;
import com.ruoyi.report.service.SampleRecordService;
import com.ruoyi.report.vo.SampleRecordVo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
/**
 * æ ·å“é¢†æ ·è®°å½•控制器
 */
@RequestMapping("/report/sampleRecord")
@RestController
@AllArgsConstructor
@Api(tags = "样品领样记录")
public class SampleRecordController {
    private SampleRecordService sampleRecordService;
    /**
     * åˆ†é¡µæŸ¥è¯¢é¢†æ ·è®°å½•
     */
    @ApiOperation(value = "分页查询领样记录")
    @GetMapping("/page")
    public Result page(SampleRecordDto dto, Page page) {
        return Result.success(sampleRecordService.pageSampleRecord(page, dto));
    }
    /**
     * æŸ¥è¯¢æ ·å“æµè½¬è®°å½•
     */
    @ApiOperation(value = "查询样品流转记录")
    @GetMapping("/flow")
    public Result flow(@RequestParam Long sampleId) {
        return Result.success(sampleRecordService.getFlowRecord(sampleId));
    }
    /**
     * å¯¼å‡ºè®°å½•
     */
    @ApiOperation(value = "导出记录")
    @GetMapping("/export")
    public void export(SampleRecordDto dto, HttpServletResponse response) {
        sampleRecordService.exportSampleRecord(dto, response);
    }
}
report-server/src/main/java/com/ruoyi/report/controller/SpcChartController.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,70 @@
package com.ruoyi.report.controller;
import com.ruoyi.common.core.domain.Result;
import com.ruoyi.report.dto.SpcChartDto;
import com.ruoyi.report.service.SpcChartService;
import com.ruoyi.report.vo.SpcResultVo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletResponse;
/**
 * SPC控制图控制器
 */
@RequestMapping("/chart/spc")
@RestController
@AllArgsConstructor
@Api(tags = "SPC控制图")
public class SpcChartController {
    private SpcChartService spcChartService;
    /**
     * SPC分析
     */
    @ApiOperation(value = "SPC分析")
    @PostMapping("/analyze")
    public Result analyze(@RequestBody SpcChartDto dto) {
        return Result.success(spcChartService.analyze(dto));
    }
    /**
     * åˆ¶ç¨‹èƒ½åŠ›åˆ†æž
     */
    @ApiOperation(value = "制程能力分析")
    @GetMapping("/capability")
    public Result capability(SpcChartDto dto) {
        return Result.success(spcChartService.getCapability(dto));
    }
    /**
     * å¯¼å‡ºåˆ†æžæ•°æ®
     */
    @ApiOperation(value = "导出分析数据")
    @GetMapping("/export")
    public void export(SpcChartDto dto, HttpServletResponse response) {
        spcChartService.export(dto, response);
    }
    /**
     * æŸ¥è¯¢å¯é€‰æ£€æµ‹é¡¹
     */
    @ApiOperation(value = "查询可选检测项")
    @GetMapping("/itemNames")
    public Result getItemNames(SpcChartDto dto) {
        return Result.success(spcChartService.getItemNames(dto));
    }
    /**
     * æŸ¥è¯¢å¯é€‰æ ·å“åç§°åˆ—表
     */
    @ApiOperation(value = "查询可选样品名称列表")
    @GetMapping("/projectList")
    public Result getProjectList(SpcChartDto dto) {
        return Result.success(spcChartService.getSampleNames(dto));
    }
}
report-server/src/main/java/com/ruoyi/report/controller/TestItemDataController.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,73 @@
package com.ruoyi.report.controller;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.common.core.domain.Result;
import com.ruoyi.report.dto.TestItemDataDto;
import com.ruoyi.report.service.TestItemDataService;
import com.ruoyi.report.vo.TestItemDataVo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
import java.util.Map;
/**
 * æ£€æµ‹é¡¹ç›®æ•°æ®æŽ§åˆ¶å™¨
 */
@RequestMapping("/report/testItemData")
@RestController
@AllArgsConstructor
@Api(tags = "检测项目数据")
public class TestItemDataController {
    private TestItemDataService testItemDataService;
    /**
     * åˆ†é¡µæŸ¥è¯¢æ£€æµ‹é¡¹ç›®æ•°æ®
     */
    @ApiOperation(value = "分页查询检测项目数据")
    @GetMapping("/page")
    public Result page(TestItemDataDto dto, Page page) {
        return Result.success(testItemDataService.pageTestItemData(page, dto));
    }
    /**
     * æŸ¥è¯¢æ£€æµ‹é¡¹ç›®è¯¦æƒ…
     */
    @ApiOperation(value = "查询检测项目详情")
    @GetMapping("/detail")
    public Result detail(@RequestParam Long sampleId) {
        return Result.success(testItemDataService.getDetail(sampleId));
    }
    /**
     * æ•°æ®æ¨ªå‘比较
     */
    @ApiOperation(value = "数据横向比较")
    @PostMapping("/compare")
    public Result compare(@RequestBody TestItemDataDto dto) {
        return Result.success(testItemDataService.compare(dto));
    }
    /**
     * å¯¼å‡ºæ•°æ®
     */
    @ApiOperation(value = "导出数据")
    @GetMapping("/export")
    public void export(TestItemDataDto dto, HttpServletResponse response) {
        testItemDataService.exportTestItemData(dto, response);
    }
    /**
     * æŸ¥è¯¢æ£€æµ‹é¡¹åç§°åˆ—表
     */
    @ApiOperation(value = "查询检测项名称列表")
    @GetMapping("/itemNames")
    public Result getItemNames(TestItemDataDto dto) {
        return Result.success(testItemDataService.getItemNames(dto));
    }
}
report-server/src/main/java/com/ruoyi/report/controller/WorkStatisticsController.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,53 @@
package com.ruoyi.report.controller;
import com.ruoyi.common.core.domain.Result;
import com.ruoyi.report.dto.WorkStatisticsDto;
import com.ruoyi.report.service.WorkStatisticsService;
import com.ruoyi.report.vo.WorkStatisticsVo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Map;
/**
 * å·¥ä½œç»Ÿè®¡æŽ§åˆ¶å™¨
 */
@RequestMapping("/chart/workStatistics")
@RestController
@AllArgsConstructor
@Api(tags = "工作统计")
public class WorkStatisticsController {
    private WorkStatisticsService workStatisticsService;
    /**
     * æŒ‰äººå‘˜ç»Ÿè®¡
     */
    @ApiOperation(value = "按人员统计")
    @GetMapping("/byUser")
    public Result byUser(WorkStatisticsDto dto) {
        return Result.success(workStatisticsService.getByUser(dto));
    }
    /**
     * åŠæ—¶çŽ‡ç»Ÿè®¡
     */
    @ApiOperation(value = "及时率统计")
    @GetMapping("/timelyRate")
    public Result timelyRate(WorkStatisticsDto dto) {
        return Result.success(workStatisticsService.getTimelyRate(dto));
    }
    /**
     * å·¥ä½œè¶‹åŠ¿å›¾
     */
    @ApiOperation(value = "工作趋势图")
    @GetMapping("/trend")
    public Result trend(WorkStatisticsDto dto) {
        return Result.success(workStatisticsService.getTrend(dto));
    }
}
report-server/src/main/java/com/ruoyi/report/dto/DashboardDto.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,24 @@
package com.ruoyi.report.dto;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
 * çœ‹æ¿æŸ¥è¯¢DTO
 */
@Data
public class DashboardDto {
    @ApiModelProperty("开始时间")
    private String startTime;
    @ApiModelProperty("结束时间")
    private String endTime;
    @ApiModelProperty("时间类型(1:本周/2:本月/3:本年)")
    private String dateType;
    @ApiModelProperty("检验类型")
    private String orderType;
}
report-server/src/main/java/com/ruoyi/report/dto/DeviceRecordDto.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,30 @@
package com.ruoyi.report.dto;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
 * è®¾å¤‡ä½¿ç”¨è®°å½•查询DTO
 */
@Data
public class DeviceRecordDto {
    @ApiModelProperty("设备编号")
    private String deviceCode;
    @ApiModelProperty("设备名称")
    private String deviceName;
    @ApiModelProperty("开始时间")
    private String startTime;
    @ApiModelProperty("结束时间")
    private String endTime;
    @ApiModelProperty("使用人")
    private String useUser;
    @ApiModelProperty("样品编号")
    private String sampleCode;
}
report-server/src/main/java/com/ruoyi/report/dto/NormalDistributionDto.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,27 @@
package com.ruoyi.report.dto;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
 * æ­£æ€åˆ†å¸ƒåˆ†æžæŸ¥è¯¢DTO
 */
@Data
public class NormalDistributionDto {
    @ApiModelProperty("检测项名称")
    private String itemName;
    @ApiModelProperty("样品名称")
    private String sampleName;
    @ApiModelProperty("开始时间")
    private String startDate;
    @ApiModelProperty("结束时间")
    private String endDate;
    @ApiModelProperty("分组数量")
    private Integer binCount;
}
report-server/src/main/java/com/ruoyi/report/dto/PassRateDto.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,41 @@
package com.ruoyi.report.dto;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.List;
/**
 * åˆæ ¼çŽ‡ç»Ÿè®¡æŸ¥è¯¢DTO
 */
@Data
public class PassRateDto {
    @ApiModelProperty("开始时间")
    private String startTime;
    @ApiModelProperty("结束时间")
    private String endTime;
    @ApiModelProperty("时间类型(1:本周/2:本月/3:本年)")
    private String dateType;
    @ApiModelProperty("检验类型(1:原材料/2:半成品/3:成品)")
    private String orderType;
    @ApiModelProperty("样品名称")
    private String sampleName;
    @ApiModelProperty("供应商名称")
    private String supplierName;
    @ApiModelProperty("工序")
    private String process;
    @ApiModelProperty("机台")
    private String machine;
    @ApiModelProperty("不合格项目列表")
    private List<String> itemNames;
}
report-server/src/main/java/com/ruoyi/report/dto/SampleProgressDto.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,36 @@
package com.ruoyi.report.dto;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
 * æ ·å“è¿›åº¦æŸ¥è¯¢DTO
 */
@Data
public class SampleProgressDto {
    @ApiModelProperty("委托编号/申请单号")
    private String entrustCode;
    @ApiModelProperty("样品编号")
    private String sampleCode;
    @ApiModelProperty("样品名称")
    private String sampleName;
    @ApiModelProperty("报告编号")
    private String reportCode;
    @ApiModelProperty("开始时间")
    private String startTime;
    @ApiModelProperty("结束时间")
    private String endTime;
    @ApiModelProperty("检测状态")
    private Integer insState;
    @ApiModelProperty("客户名称")
    private String custom;
}
report-server/src/main/java/com/ruoyi/report/dto/SampleRecordDto.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,33 @@
package com.ruoyi.report.dto;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
 * æ ·å“é¢†æ ·è®°å½•查询DTO
 */
@Data
public class SampleRecordDto {
    @ApiModelProperty("样品编号")
    private String sampleCode;
    @ApiModelProperty("样品名称")
    private String sampleName;
    @ApiModelProperty("客户名称")
    private String custom;
    @ApiModelProperty("开始时间")
    private String startTime;
    @ApiModelProperty("结束时间")
    private String endTime;
    @ApiModelProperty("领用人")
    private String receiveUser;
    @ApiModelProperty("样品ID")
    private Long sampleId;
}
report-server/src/main/java/com/ruoyi/report/dto/SpcChartDto.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,41 @@
package com.ruoyi.report.dto;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.math.BigDecimal;
/**
 * SPC分析查询DTO
 */
@Data
public class SpcChartDto {
    @ApiModelProperty("项目ID")
    private Long projectId;
    @ApiModelProperty("检测项名称")
    private String itemName;
    @ApiModelProperty("开始时间")
    private String startDate;
    @ApiModelProperty("结束时间")
    private String endDate;
    @ApiModelProperty("子组大小")
    private Integer subgroupSize;
    @ApiModelProperty("控制上限UCL")
    private BigDecimal ucl;
    @ApiModelProperty("控制下限LCL")
    private BigDecimal lcl;
    @ApiModelProperty("目标值")
    private BigDecimal targetValue;
    @ApiModelProperty("样品名称")
    private String sampleName;
}
report-server/src/main/java/com/ruoyi/report/dto/TestItemDataDto.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,41 @@
package com.ruoyi.report.dto;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.List;
/**
 * æ£€æµ‹é¡¹ç›®æ•°æ®æŸ¥è¯¢DTO
 */
@Data
public class TestItemDataDto {
    @ApiModelProperty("生产订单")
    private String productionOrder;
    @ApiModelProperty("批次号")
    private String batchNo;
    @ApiModelProperty("样品编号")
    private String sampleCode;
    @ApiModelProperty("样品名称")
    private String sampleName;
    @ApiModelProperty("开始时间")
    private String startTime;
    @ApiModelProperty("结束时间")
    private String endTime;
    @ApiModelProperty("检测状态")
    private Integer insState;
    @ApiModelProperty("检测项名称")
    private String itemName;
    @ApiModelProperty("样品ID列表(用于比较)")
    private List<Long> sampleIds;
}
report-server/src/main/java/com/ruoyi/report/dto/WorkStatisticsDto.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,27 @@
package com.ruoyi.report.dto;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
 * å·¥ä½œç»Ÿè®¡æŸ¥è¯¢DTO
 */
@Data
public class WorkStatisticsDto {
    @ApiModelProperty("开始时间")
    private String startTime;
    @ApiModelProperty("结束时间")
    private String endTime;
    @ApiModelProperty("时间类型(1:本周/2:本月/3:本年)")
    private String dateType;
    @ApiModelProperty("用户ID")
    private Long userId;
    @ApiModelProperty("部门ID")
    private Long deptId;
}
report-server/src/main/java/com/ruoyi/report/mapper/DashboardMapper.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,78 @@
package com.ruoyi.report.mapper;
import com.ruoyi.report.dto.DashboardDto;
import com.ruoyi.report.vo.RankingVo;
import com.ruoyi.report.vo.TaskCalendarVo;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
import java.util.Map;
/**
 * æ•°å­—化语音看板Mapper
 */
@Mapper
public interface DashboardMapper {
    /**
     * èŽ·å–å¾…é¢†æ ·å“æ•°
     */
    Integer getWaitReceive();
    /**
     * èŽ·å–å¾…æ£€æ ·å“æ•°
     */
    Integer getWaitInspection();
    /**
     * èŽ·å–å¾…å®¡æ ¸æ ·å“æ•°
     */
    Integer getWaitAudit();
    /**
     * èŽ·å–å¾…ç¼–åˆ¶æŠ¥å‘Šæ•°
     */
    Integer getWaitReport();
    /**
     * ä»Šæ—¥æ–°å¢žæ ·å“
     */
    Integer getTodayNewSample();
    /**
     * ä»Šæ—¥å®Œæˆæ ·å“
     */
    Integer getTodayFinished();
    /**
     * åŽ†å²N天数据
     */
    List<TaskCalendarVo> getHistoryDays(@Param("days") Integer days, @Param("dto") DashboardDto dto);
    /**
     * æœªæ¥N天任务
     */
    List<TaskCalendarVo> getFutureDays(@Param("days") Integer days, @Param("dto") DashboardDto dto);
    /**
     * æäº¤æŽ’行(原始记录)
     */
    List<RankingVo> getOriginalRecordRanking(@Param("dto") DashboardDto dto);
    /**
     * æäº¤æŽ’行(报告)
     */
    List<RankingVo> getReportRanking(@Param("dto") DashboardDto dto);
    /**
     * è¿‘30天检验结果
     */
    List<Map<String, Object>> getInsResultByDays(@Param("days") Integer days, @Param("orderType") String orderType);
    /**
     * èŽ·å–è¯­éŸ³æ’­æŠ¥é˜Ÿåˆ—
     */
    List<Map<String, Object>> getVoiceQueue();
}
report-server/src/main/java/com/ruoyi/report/mapper/NormalDistributionMapper.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,31 @@
package com.ruoyi.report.mapper;
import com.ruoyi.report.dto.NormalDistributionDto;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
import java.util.Map;
/**
 * æ­£æ€åˆ†å¸ƒå›¾Mapper
 */
@Mapper
public interface NormalDistributionMapper {
    /**
     * æŸ¥è¯¢æ£€æµ‹é¡¹æ•°æ®
     */
    List<Map<String, Object>> getItemData(@Param("dto") NormalDistributionDto dto);
    /**
     * æŸ¥è¯¢å¯é€‰æ£€æµ‹é¡¹
     */
    List<String> getItemNames(@Param("dto") NormalDistributionDto dto);
    /**
     * æŸ¥è¯¢å¯é€‰æ ·å“åç§°åˆ—表
     */
    List<String> getSampleNames(@Param("dto") NormalDistributionDto dto);
}
report-server/src/main/java/com/ruoyi/report/mapper/PassRateMapper.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,41 @@
package com.ruoyi.report.mapper;
import com.ruoyi.report.dto.PassRateDto;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
import java.util.Map;
/**
 * åˆæ ¼çŽ‡ç»Ÿè®¡Mapper
 */
@Mapper
public interface PassRateMapper {
    /**
     * åŽŸææ–™åˆæ ¼çŽ‡
     */
    List<Map<String, Object>> getRawMaterialPassRate(@Param("dto") PassRateDto dto);
    /**
     * ä¾›åº”商不合格统计
     */
    List<Map<String, Object>> getSupplierUnqualified(@Param("dto") PassRateDto dto);
    /**
     * ä¸åˆæ ¼é¡¹ç›®ç»Ÿè®¡(用于帕累托图)
     */
    List<Map<String, Object>> getUnqualifiedItemStats(@Param("dto") PassRateDto dto);
    /**
     * å·¥åºåˆæ ¼çއ
     */
    List<Map<String, Object>> getProcessPassRate(@Param("dto") PassRateDto dto);
    /**
     * æœºå°ä¸åˆæ ¼ç»Ÿè®¡
     */
    List<Map<String, Object>> getMachineUnqualified(@Param("dto") PassRateDto dto);
}
report-server/src/main/java/com/ruoyi/report/mapper/ReportDeviceRecordMapper.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,28 @@
package com.ruoyi.report.mapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.report.dto.DeviceRecordDto;
import com.ruoyi.report.vo.DeviceRecordVo;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
import java.util.Map;
/**
 * è®¾å¤‡ä½¿ç”¨è®°å½•报表Mapper
 */
@Mapper
public interface ReportDeviceRecordMapper {
    /**
     * åˆ†é¡µæŸ¥è¯¢è®¾å¤‡ä½¿ç”¨è®°å½•
     */
    Page<DeviceRecordVo> pageDeviceRecord(Page page, @Param("dto") DeviceRecordDto dto);
    /**
     * è®¾å¤‡ä½¿ç”¨ç»Ÿè®¡
     */
    List<Map<String, Object>> getStatistics(@Param("dto") DeviceRecordDto dto);
}
report-server/src/main/java/com/ruoyi/report/mapper/SampleProgressMapper.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,33 @@
package com.ruoyi.report.mapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.report.dto.SampleProgressDto;
import com.ruoyi.report.vo.SampleProgressVo;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
import java.util.Map;
/**
 * æ ·å“è¿›åº¦æŠ¥è¡¨Mapper
 */
@Mapper
public interface SampleProgressMapper {
    /**
     * åˆ†é¡µæŸ¥è¯¢æ ·å“è¿›åº¦
     */
    Page<SampleProgressVo> pageSampleProgress(Page page, @Param("dto") SampleProgressDto dto);
    /**
     * èŽ·å–ç»Ÿè®¡æ•°æ®
     */
    Map<String, Object> getStatistics(@Param("dto") SampleProgressDto dto);
    /**
     * èŽ·å–å›¾è¡¨æ•°æ®
     */
    List<Map<String, Object>> getChartData(@Param("dto") SampleProgressDto dto);
}
report-server/src/main/java/com/ruoyi/report/mapper/SampleRecordMapper.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,27 @@
package com.ruoyi.report.mapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.report.dto.SampleRecordDto;
import com.ruoyi.report.vo.SampleRecordVo;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
 * æ ·å“é¢†æ ·è®°å½•Mapper
 */
@Mapper
public interface SampleRecordMapper {
    /**
     * åˆ†é¡µæŸ¥è¯¢é¢†æ ·è®°å½•
     */
    Page<SampleRecordVo> pageSampleRecord(Page page, @Param("dto") SampleRecordDto dto);
    /**
     * æŸ¥è¯¢æ ·å“æµè½¬è®°å½•
     */
    List<SampleRecordVo> getFlowRecord(@Param("sampleId") Long sampleId);
}
report-server/src/main/java/com/ruoyi/report/mapper/SpcChartMapper.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,32 @@
package com.ruoyi.report.mapper;
import com.ruoyi.report.dto.SpcChartDto;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
/**
 * SPC控制图Mapper
 */
@Mapper
public interface SpcChartMapper {
    /**
     * æŸ¥è¯¢æ£€æµ‹é¡¹æ•°æ®
     */
    List<Map<String, Object>> getItemData(@Param("dto") SpcChartDto dto);
    /**
     * æŸ¥è¯¢å¯é€‰æ£€æµ‹é¡¹
     */
    List<String> getItemNames(@Param("dto") SpcChartDto dto);
    /**
     * æŸ¥è¯¢å¯é€‰æ ·å“åç§°åˆ—表
     */
    List<String> getSampleNames(@Param("dto") SpcChartDto dto);
}
report-server/src/main/java/com/ruoyi/report/mapper/TestItemDataMapper.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,37 @@
package com.ruoyi.report.mapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.report.dto.TestItemDataDto;
import com.ruoyi.report.vo.TestItemDataVo;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
 * æ£€æµ‹é¡¹ç›®æ•°æ®Mapper
 */
@Mapper
public interface TestItemDataMapper {
    /**
     * åˆ†é¡µæŸ¥è¯¢æ£€æµ‹é¡¹ç›®æ•°æ®
     */
    Page<TestItemDataVo> pageTestItemData(Page page, @Param("dto") TestItemDataDto dto);
    /**
     * æŸ¥è¯¢æ£€æµ‹é¡¹ç›®è¯¦æƒ…
     */
    List<TestItemDataVo> getDetail(@Param("sampleId") Long sampleId);
    /**
     * æŸ¥è¯¢æ£€æµ‹é¡¹åç§°åˆ—表
     */
    List<String> getItemNames(@Param("dto") TestItemDataDto dto);
    /**
     * æ ¹æ®æ ·å“ID列表查询检测数据
     */
    List<TestItemDataVo> listBySampleIds(@Param("sampleIds") List<Long> sampleIds);
}
report-server/src/main/java/com/ruoyi/report/mapper/WorkStatisticsMapper.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,32 @@
package com.ruoyi.report.mapper;
import com.ruoyi.report.dto.WorkStatisticsDto;
import com.ruoyi.report.vo.WorkStatisticsVo;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
import java.util.Map;
/**
 * å·¥ä½œç»Ÿè®¡Mapper
 */
@Mapper
public interface WorkStatisticsMapper {
    /**
     * æŒ‰äººå‘˜ç»Ÿè®¡
     */
    List<WorkStatisticsVo> getByUser(@Param("dto") WorkStatisticsDto dto);
    /**
     * åŠæ—¶çŽ‡ç»Ÿè®¡
     */
    List<Map<String, Object>> getTimelyRate(@Param("dto") WorkStatisticsDto dto);
    /**
     * å·¥ä½œè¶‹åŠ¿å›¾
     */
    List<Map<String, Object>> getTrend(@Param("dto") WorkStatisticsDto dto);
}
report-server/src/main/java/com/ruoyi/report/service/DashboardService.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,46 @@
package com.ruoyi.report.service;
import com.ruoyi.report.dto.DashboardDto;
import com.ruoyi.report.vo.DashboardOverviewVo;
import com.ruoyi.report.vo.RankingVo;
import com.ruoyi.report.vo.TaskCalendarVo;
import java.util.List;
import java.util.Map;
/**
 * æ•°å­—化语音看板服务接口
 */
public interface DashboardService {
    /**
     * èŽ·å–çœ‹æ¿æ¦‚è§ˆæ•°æ®
     */
    DashboardOverviewVo getOverview(DashboardDto dto);
    /**
     * åŽ†å²15天数据
     */
    List<TaskCalendarVo> getHistory15Days(DashboardDto dto);
    /**
     * æœªæ¥15天任务
     */
    List<TaskCalendarVo> getFuture15Days(DashboardDto dto);
    /**
     * æäº¤æŽ’行
     */
    List<RankingVo> getRanking(DashboardDto dto);
    /**
     * æ£€éªŒç»“果统计
     */
    Map<String, Object> getInsResult(DashboardDto dto);
    /**
     * èŽ·å–è¯­éŸ³æ’­æŠ¥é˜Ÿåˆ—
     */
    List<Map<String, Object>> getVoiceQueue();
}
report-server/src/main/java/com/ruoyi/report/service/NormalDistributionService.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,34 @@
package com.ruoyi.report.service;
import com.ruoyi.report.dto.NormalDistributionDto;
import com.ruoyi.report.vo.NormalDistributionVo;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
/**
 * æ­£æ€åˆ†å¸ƒå›¾æœåŠ¡æŽ¥å£
 */
public interface NormalDistributionService {
    /**
     * æ­£æ€åˆ†å¸ƒåˆ†æž
     */
    NormalDistributionVo analyze(NormalDistributionDto dto);
    /**
     * å¯¼å‡ºåˆ†æžæ•°æ®
     */
    void export(NormalDistributionDto dto, HttpServletResponse response);
    /**
     * æŸ¥è¯¢å¯é€‰æ£€æµ‹é¡¹
     */
    List<String> getItemNames(NormalDistributionDto dto);
    /**
     * æŸ¥è¯¢å¯é€‰æ ·å“åç§°åˆ—表
     */
    List<String> getSampleNames(NormalDistributionDto dto);
}
report-server/src/main/java/com/ruoyi/report/service/PassRateService.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,39 @@
package com.ruoyi.report.service;
import com.ruoyi.report.dto.PassRateDto;
import com.ruoyi.report.vo.ParetoVo;
import java.util.List;
import java.util.Map;
/**
 * åˆæ ¼çŽ‡ç»Ÿè®¡æœåŠ¡æŽ¥å£
 */
public interface PassRateService {
    /**
     * åŽŸææ–™åˆæ ¼çŽ‡
     */
    List<Map<String, Object>> getRawMaterialPassRate(PassRateDto dto);
    /**
     * ä¾›åº”商不合格统计
     */
    List<Map<String, Object>> getSupplierUnqualified(PassRateDto dto);
    /**
     * å¸•累托图数据
     */
    ParetoVo getPareto(PassRateDto dto);
    /**
     * å·¥åºåˆæ ¼çއ
     */
    List<Map<String, Object>> getProcessPassRate(PassRateDto dto);
    /**
     * æœºå°ä¸åˆæ ¼ç»Ÿè®¡
     */
    List<Map<String, Object>> getMachineUnqualified(PassRateDto dto);
}
report-server/src/main/java/com/ruoyi/report/service/ReportDeviceRecordService.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,31 @@
package com.ruoyi.report.service;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.report.dto.DeviceRecordDto;
import com.ruoyi.report.vo.DeviceRecordVo;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
import java.util.Map;
/**
 * è®¾å¤‡ä½¿ç”¨è®°å½•报表服务接口
 */
public interface ReportDeviceRecordService {
    /**
     * åˆ†é¡µæŸ¥è¯¢è®¾å¤‡ä½¿ç”¨è®°å½•
     */
    Page<DeviceRecordVo> pageDeviceRecord(Page page, DeviceRecordDto dto);
    /**
     * è®¾å¤‡ä½¿ç”¨ç»Ÿè®¡
     */
    List<Map<String, Object>> getStatistics(DeviceRecordDto dto);
    /**
     * å¯¼å‡ºè®°å½•
     */
    void exportDeviceRecord(DeviceRecordDto dto, HttpServletResponse response);
}
report-server/src/main/java/com/ruoyi/report/service/SampleProgressService.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,35 @@
package com.ruoyi.report.service;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.report.dto.SampleProgressDto;
import com.ruoyi.report.vo.SampleProgressVo;
import javax.servlet.http.HttpServletResponse;
import java.util.Map;
/**
 * æ ·å“è¿›åº¦æŠ¥è¡¨æœåŠ¡æŽ¥å£
 */
public interface SampleProgressService {
    /**
     * åˆ†é¡µæŸ¥è¯¢æ ·å“è¿›åº¦
     */
    Page<SampleProgressVo> pageSampleProgress(Page page, SampleProgressDto dto);
    /**
     * èŽ·å–ç»Ÿè®¡æ•°æ®
     */
    Map<String, Object> getStatistics(SampleProgressDto dto);
    /**
     * å¯¼å‡ºæŠ¥è¡¨
     */
    void exportSampleProgress(SampleProgressDto dto, HttpServletResponse response);
    /**
     * èŽ·å–å›¾è¡¨æ•°æ®
     */
    Map<String, Object> getChartData(SampleProgressDto dto);
}
report-server/src/main/java/com/ruoyi/report/service/SampleRecordService.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,30 @@
package com.ruoyi.report.service;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.report.dto.SampleRecordDto;
import com.ruoyi.report.vo.SampleRecordVo;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
/**
 * æ ·å“é¢†æ ·è®°å½•服务接口
 */
public interface SampleRecordService {
    /**
     * åˆ†é¡µæŸ¥è¯¢é¢†æ ·è®°å½•
     */
    Page<SampleRecordVo> pageSampleRecord(Page page, SampleRecordDto dto);
    /**
     * æŸ¥è¯¢æ ·å“æµè½¬è®°å½•
     */
    List<SampleRecordVo> getFlowRecord(Long sampleId);
    /**
     * å¯¼å‡ºè®°å½•
     */
    void exportSampleRecord(SampleRecordDto dto, HttpServletResponse response);
}
report-server/src/main/java/com/ruoyi/report/service/SpcChartService.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,39 @@
package com.ruoyi.report.service;
import com.ruoyi.report.dto.SpcChartDto;
import com.ruoyi.report.vo.SpcResultVo;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
/**
 * SPC控制图服务接口
 */
public interface SpcChartService {
    /**
     * SPC分析
     */
    SpcResultVo analyze(SpcChartDto dto);
    /**
     * åˆ¶ç¨‹èƒ½åŠ›åˆ†æž
     */
    SpcResultVo.Capability getCapability(SpcChartDto dto);
    /**
     * å¯¼å‡ºåˆ†æžæ•°æ®
     */
    void export(SpcChartDto dto, HttpServletResponse response);
    /**
     * æŸ¥è¯¢å¯é€‰æ£€æµ‹é¡¹
     */
    List<String> getItemNames(SpcChartDto dto);
    /**
     * æŸ¥è¯¢å¯é€‰æ ·å“åç§°åˆ—表
     */
    List<String> getSampleNames(SpcChartDto dto);
}
report-server/src/main/java/com/ruoyi/report/service/TestItemDataService.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,41 @@
package com.ruoyi.report.service;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.report.dto.TestItemDataDto;
import com.ruoyi.report.vo.TestItemDataVo;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
import java.util.Map;
/**
 * æ£€æµ‹é¡¹ç›®æ•°æ®æœåŠ¡æŽ¥å£
 */
public interface TestItemDataService {
    /**
     * åˆ†é¡µæŸ¥è¯¢æ£€æµ‹é¡¹ç›®æ•°æ®
     */
    Page<TestItemDataVo> pageTestItemData(Page page, TestItemDataDto dto);
    /**
     * æŸ¥è¯¢æ£€æµ‹é¡¹ç›®è¯¦æƒ…
     */
    List<TestItemDataVo> getDetail(Long sampleId);
    /**
     * æ•°æ®æ¨ªå‘比较
     */
    Map<String, Object> compare(TestItemDataDto dto);
    /**
     * å¯¼å‡ºæ•°æ®
     */
    void exportTestItemData(TestItemDataDto dto, HttpServletResponse response);
    /**
     * æŸ¥è¯¢æ£€æµ‹é¡¹åç§°åˆ—表
     */
    List<String> getItemNames(TestItemDataDto dto);
}
report-server/src/main/java/com/ruoyi/report/service/WorkStatisticsService.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,29 @@
package com.ruoyi.report.service;
import com.ruoyi.report.dto.WorkStatisticsDto;
import com.ruoyi.report.vo.WorkStatisticsVo;
import java.util.List;
import java.util.Map;
/**
 * å·¥ä½œç»Ÿè®¡æœåŠ¡æŽ¥å£
 */
public interface WorkStatisticsService {
    /**
     * æŒ‰äººå‘˜ç»Ÿè®¡
     */
    List<WorkStatisticsVo> getByUser(WorkStatisticsDto dto);
    /**
     * åŠæ—¶çŽ‡ç»Ÿè®¡
     */
    List<Map<String, Object>> getTimelyRate(WorkStatisticsDto dto);
    /**
     * å·¥ä½œè¶‹åŠ¿å›¾
     */
    Map<String, Object> getTrend(WorkStatisticsDto dto);
}
report-server/src/main/java/com/ruoyi/report/service/impl/DashboardServiceImpl.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,107 @@
package com.ruoyi.report.service.impl;
import com.ruoyi.report.dto.DashboardDto;
import com.ruoyi.report.mapper.DashboardMapper;
import com.ruoyi.report.service.DashboardService;
import com.ruoyi.report.vo.DashboardOverviewVo;
import com.ruoyi.report.vo.RankingVo;
import com.ruoyi.report.vo.TaskCalendarVo;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
import java.util.*;
/**
 * æ•°å­—化语音看板服务实现
 */
@Service
@AllArgsConstructor
public class DashboardServiceImpl implements DashboardService {
    private DashboardMapper dashboardMapper;
    @Override
    public DashboardOverviewVo getOverview(DashboardDto dto) {
        DashboardOverviewVo vo = new DashboardOverviewVo();
        // å¾…处理统计
        vo.setWaitReceive(dashboardMapper.getWaitReceive());
        vo.setWaitInspection(dashboardMapper.getWaitInspection());
        vo.setWaitAudit(dashboardMapper.getWaitAudit());
        vo.setWaitReport(dashboardMapper.getWaitReport());
        // ä»Šæ—¥ç»Ÿè®¡
        vo.setTodayNewSample(dashboardMapper.getTodayNewSample());
        vo.setTodayFinished(dashboardMapper.getTodayFinished());
        // è¿‘30天检验结果
        vo.setRawMaterialResult(dashboardMapper.getInsResultByDays(30, "1"));
        vo.setSemiFinishedResult(dashboardMapper.getInsResultByDays(30, "2"));
        vo.setFinishedProductResult(dashboardMapper.getInsResultByDays(30, "3"));
        return vo;
    }
    @Override
    public List<TaskCalendarVo> getHistory15Days(DashboardDto dto) {
        return dashboardMapper.getHistoryDays(15, dto);
    }
    @Override
    public List<TaskCalendarVo> getFuture15Days(DashboardDto dto) {
        return dashboardMapper.getFutureDays(15, dto);
    }
    @Override
    public List<RankingVo> getRanking(DashboardDto dto) {
        // åˆå¹¶åŽŸå§‹è®°å½•æŽ’è¡Œå’ŒæŠ¥å‘ŠæŽ’è¡Œ
        List<RankingVo> originalRanking = dashboardMapper.getOriginalRecordRanking(dto);
        List<RankingVo> reportRanking = dashboardMapper.getReportRanking(dto);
        Map<Long, RankingVo> rankingMap = new HashMap<>();
        // å¤„理原始记录排行
        for (int i = 0; i < originalRanking.size(); i++) {
            RankingVo vo = originalRanking.get(i);
            vo.setRank(i + 1);
            vo.setFinishCount(vo.getSubmitCount());
            rankingMap.put(vo.getUserId(), vo);
        }
        // å¤„理报告排行
        for (RankingVo report : reportRanking) {
            RankingVo existing = rankingMap.get(report.getUserId());
            if (existing != null) {
                existing.setFinishCount(existing.getFinishCount() + report.getSubmitCount());
            } else {
                report.setRank(0);
                report.setFinishCount(report.getSubmitCount());
                rankingMap.put(report.getUserId(), report);
            }
        }
        // æŽ’序并设置排名
        List<RankingVo> result = new ArrayList<>(rankingMap.values());
        result.sort((a, b) -> b.getFinishCount().compareTo(a.getFinishCount()));
        for (int i = 0; i < result.size(); i++) {
            result.get(i).setRank(i + 1);
        }
        return result.size() > 10 ? result.subList(0, 10) : result;
    }
    @Override
    public Map<String, Object> getInsResult(DashboardDto dto) {
        Map<String, Object> result = new HashMap<>();
        result.put("rawMaterial", dashboardMapper.getInsResultByDays(30, "1"));
        result.put("semiFinished", dashboardMapper.getInsResultByDays(30, "2"));
        result.put("finishedProduct", dashboardMapper.getInsResultByDays(30, "3"));
        return result;
    }
    @Override
    public List<Map<String, Object>> getVoiceQueue() {
        return dashboardMapper.getVoiceQueue();
    }
}
report-server/src/main/java/com/ruoyi/report/service/impl/NormalDistributionServiceImpl.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,193 @@
package com.ruoyi.report.service.impl;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import com.alibaba.excel.EasyExcel;
import com.ruoyi.framework.exception.ErrorException;
import com.ruoyi.report.dto.NormalDistributionDto;
import com.ruoyi.report.mapper.NormalDistributionMapper;
import com.ruoyi.report.service.NormalDistributionService;
import com.ruoyi.report.vo.NormalDistributionVo;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.MathContext;
import java.math.RoundingMode;
import java.util.*;
import java.util.stream.Collectors;
/**
 * æ­£æ€åˆ†å¸ƒå›¾æœåŠ¡å®žçŽ°
 */
@Service
@AllArgsConstructor
public class NormalDistributionServiceImpl implements NormalDistributionService {
    private NormalDistributionMapper normalDistributionMapper;
    @Override
    public NormalDistributionVo analyze(NormalDistributionDto dto) {
        // æŸ¥è¯¢æ•°æ®
        List<Map<String, Object>> itemData = normalDistributionMapper.getItemData(dto);
        if (CollectionUtil.isEmpty(itemData)) {
            return null;
        }
        if (itemData.size() < 10) {
            throw new ErrorException("数据量不足,至少需要10个数据点");
        }
        // èŽ·å–æ•°å€¼åˆ—è¡¨
        List<BigDecimal> values = itemData.stream()
                .map(m -> new BigDecimal((String) m.get("lastValue")))
                .sorted()
                .collect(Collectors.toList());
        // è®¡ç®—统计量
        BigDecimal min = values.get(0);
        BigDecimal max = values.get(values.size() - 1);
        BigDecimal sum = values.stream().reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal mean = sum.divide(new BigDecimal(values.size()), 10, RoundingMode.HALF_UP);
        // è®¡ç®—标准差
        BigDecimal variance = BigDecimal.ZERO;
        for (BigDecimal v : values) {
            BigDecimal diff = v.subtract(mean);
            variance = variance.add(diff.multiply(diff));
        }
        variance = variance.divide(new BigDecimal(values.size() - 1), 10, RoundingMode.HALF_UP);
        BigDecimal stdDev = sqrt(variance).setScale(6, RoundingMode.HALF_UP);
        // ç›´æ–¹å›¾åˆ†ç»„
        int binCount = dto.getBinCount() != null ? dto.getBinCount() : 10;
        BigDecimal range = max.subtract(min);
        BigDecimal binWidth = range.divide(new BigDecimal(binCount), 10, RoundingMode.HALF_UP);
        // è®¡ç®—分组边界
        List<BigDecimal> binEdges = new ArrayList<>();
        BigDecimal edge = min;
        for (int i = 0; i <= binCount; i++) {
            binEdges.add(edge.setScale(4, RoundingMode.HALF_UP));
            edge = edge.add(binWidth);
        }
        // è®¡ç®—频数
        List<Integer> frequencies = new ArrayList<>();
        for (int i = 0; i < binCount; i++) {
            BigDecimal lower = binEdges.get(i);
            BigDecimal upper = binEdges.get(i + 1);
            int count = 0;
            for (BigDecimal v : values) {
                if (v.compareTo(lower) >= 0 && (i == binCount - 1 ? v.compareTo(upper) <= 0 : v.compareTo(upper) < 0)) {
                    count++;
                }
            }
            frequencies.add(count);
        }
        // æ­£æ€åˆ†å¸ƒæ›²çº¿
        List<BigDecimal> normalX = new ArrayList<>();
        List<BigDecimal> normalY = new ArrayList<>();
        // ç”Ÿæˆæ›²çº¿ç‚¹
        BigDecimal step = range.divide(new BigDecimal(100), 10, RoundingMode.HALF_UP);
        BigDecimal x = min;
        for (int i = 0; i <= 100; i++) {
            normalX.add(x.setScale(4, RoundingMode.HALF_UP));
            // æ­£æ€åˆ†å¸ƒå…¬å¼: f(x) = (1/(σ√(2π))) * e^(-(x-μ)^2/(2σ^2))
            BigDecimal exponent = x.subtract(mean).pow(2)
                    .divide(stdDev.pow(2).multiply(new BigDecimal(2)), 10, RoundingMode.HALF_UP);
            BigDecimal expValue = BigDecimal.valueOf(Math.exp(-exponent.doubleValue()));
            BigDecimal coefficient = BigDecimal.ONE.divide(
                    stdDev.multiply(BigDecimal.valueOf(Math.sqrt(2 * Math.PI))),
                    10, RoundingMode.HALF_UP);
            BigDecimal y = coefficient.multiply(expValue)
                    .multiply(new BigDecimal(values.size()))
                    .multiply(binWidth)
                    .setScale(4, RoundingMode.HALF_UP);
            normalY.add(y);
            x = x.add(step);
        }
        // æž„建结果
        NormalDistributionVo vo = new NormalDistributionVo();
        vo.setBinEdges(binEdges);
        vo.setFrequencies(frequencies);
        vo.setNormalX(normalX);
        vo.setNormalY(normalY);
        vo.setMean(mean.setScale(4, RoundingMode.HALF_UP));
        vo.setStdDev(stdDev.setScale(4, RoundingMode.HALF_UP));
        vo.setMin(min.setScale(4, RoundingMode.HALF_UP));
        vo.setMax(max.setScale(4, RoundingMode.HALF_UP));
        vo.setSampleSize(values.size());
        return vo;
    }
    @Override
    public void export(NormalDistributionDto dto, HttpServletResponse response) {
        List<Map<String, Object>> itemData = normalDistributionMapper.getItemData(dto);
        if (CollectionUtil.isEmpty(itemData)) {
            return;
        }
        try {
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
            response.setCharacterEncoding("utf-8");
            String fileName = "正态分布分析数据_" + DateUtil.format(new Date(), "yyyyMMddHHmmss");
            response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");
            // æž„建导出数据
            List<Map<String, Object>> exportData = new ArrayList<>();
            for (Map<String, Object> item : itemData) {
                Map<String, Object> row = new HashMap<>();
                row.put("sampleCode", item.get("sampleCode"));
                row.put("sampleName", item.get("sampleName"));
                row.put("itemName", item.get("itemName"));
                row.put("lastValue", item.get("lastValue"));
                row.put("insTime", item.get("insTime"));
                exportData.add(row);
            }
            EasyExcel.write(response.getOutputStream())
                    .sheet("正态分布分析数据")
                    .doWrite(exportData);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    @Override
    public List<String> getItemNames(NormalDistributionDto dto) {
        return normalDistributionMapper.getItemNames(dto);
    }
    @Override
    public List<String> getSampleNames(NormalDistributionDto dto) {
        return normalDistributionMapper.getSampleNames(dto);
    }
    /**
     * å¹³æ–¹æ ¹è®¡ç®—
     */
    private BigDecimal sqrt(BigDecimal value) {
        BigDecimal x = value;
        BigDecimal tolerance = new BigDecimal("1E-10");
        BigDecimal guess = value.divide(BigDecimal.valueOf(2), MathContext.DECIMAL128);
        while (x.subtract(guess).abs().compareTo(tolerance) > 0) {
            x = guess;
            guess = x.add(value.divide(x, MathContext.DECIMAL128)).divide(new BigDecimal("2"), MathContext.DECIMAL128);
        }
        return guess;
    }
}
report-server/src/main/java/com/ruoyi/report/service/impl/PassRateServiceImpl.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,122 @@
package com.ruoyi.report.service.impl;
import cn.hutool.core.date.DateUtil;
import com.ruoyi.report.dto.PassRateDto;
import com.ruoyi.report.mapper.PassRateMapper;
import com.ruoyi.report.service.PassRateService;
import com.ruoyi.report.vo.ParetoVo;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
/**
 * åˆæ ¼çŽ‡ç»Ÿè®¡æœåŠ¡å®žçŽ°
 */
@Service
@AllArgsConstructor
public class PassRateServiceImpl implements PassRateService {
    private PassRateMapper passRateMapper;
    @Override
    public List<Map<String, Object>> getRawMaterialPassRate(PassRateDto dto) {
        processDateType(dto);
        return passRateMapper.getRawMaterialPassRate(dto);
    }
    @Override
    public List<Map<String, Object>> getSupplierUnqualified(PassRateDto dto) {
        processDateType(dto);
        return passRateMapper.getSupplierUnqualified(dto);
    }
    @Override
    public ParetoVo getPareto(PassRateDto dto) {
        processDateType(dto);
        List<Map<String, Object>> stats = passRateMapper.getUnqualifiedItemStats(dto);
        ParetoVo vo = new ParetoVo();
        List<String> categories = new ArrayList<>();
        List<Integer> values = new ArrayList<>();
        List<Double> cumulativePercent = new ArrayList<>();
        if (stats.isEmpty()) {
            vo.setCategories(categories);
            vo.setValues(values);
            vo.setCumulativePercent(cumulativePercent);
            return vo;
        }
        // è®¡ç®—总数
        int total = stats.stream()
                .mapToInt(m -> ((Number) m.get("unqualifiedCount")).intValue())
                .sum();
        // è®¡ç®—累计百分比
        BigDecimal cumulative = BigDecimal.ZERO;
        for (Map<String, Object> stat : stats) {
            categories.add((String) stat.get("itemName"));
            int count = ((Number) stat.get("unqualifiedCount")).intValue();
            values.add(count);
            cumulative = cumulative.add(new BigDecimal(count));
            double percent = cumulative.divide(new BigDecimal(total), 4, RoundingMode.HALF_UP)
                    .multiply(new BigDecimal(100))
                    .setScale(2, RoundingMode.HALF_UP)
                    .doubleValue();
            cumulativePercent.add(percent);
        }
        vo.setCategories(categories);
        vo.setValues(values);
        vo.setCumulativePercent(cumulativePercent);
        return vo;
    }
    @Override
    public List<Map<String, Object>> getProcessPassRate(PassRateDto dto) {
        processDateType(dto);
        return passRateMapper.getProcessPassRate(dto);
    }
    @Override
    public List<Map<String, Object>> getMachineUnqualified(PassRateDto dto) {
        processDateType(dto);
        return passRateMapper.getMachineUnqualified(dto);
    }
    /**
     * å¤„理时间类型
     */
    private void processDateType(PassRateDto dto) {
        if (dto.getStartTime() != null && dto.getEndTime() != null) {
            return;
        }
        String dateType = dto.getDateType();
        if (dateType == null || dateType.isEmpty()) {
            dateType = "2"; // é»˜è®¤æœ¬æœˆ
        }
        Date now = new Date();
        switch (dateType) {
            case "1": // æœ¬å‘¨
                dto.setStartTime(DateUtil.format(DateUtil.beginOfWeek(now), "yyyy-MM-dd HH:mm:ss"));
                dto.setEndTime(DateUtil.format(DateUtil.endOfWeek(now), "yyyy-MM-dd HH:mm:ss"));
                break;
            case "2": // æœ¬æœˆ
                dto.setStartTime(DateUtil.format(DateUtil.beginOfMonth(now), "yyyy-MM-dd HH:mm:ss"));
                dto.setEndTime(DateUtil.format(DateUtil.endOfMonth(now), "yyyy-MM-dd HH:mm:ss"));
                break;
            case "3": // æœ¬å¹´
                dto.setStartTime(DateUtil.format(DateUtil.beginOfYear(now), "yyyy-MM-dd HH:mm:ss"));
                dto.setEndTime(DateUtil.format(DateUtil.endOfYear(now), "yyyy-MM-dd HH:mm:ss"));
                break;
        }
    }
}
report-server/src/main/java/com/ruoyi/report/service/impl/ReportDeviceRecordServiceImpl.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,61 @@
package com.ruoyi.report.service.impl;
import cn.hutool.core.date.DateUtil;
import com.alibaba.excel.EasyExcel;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.report.dto.DeviceRecordDto;
import com.ruoyi.report.mapper.ReportDeviceRecordMapper;
import com.ruoyi.report.service.ReportDeviceRecordService;
import com.ruoyi.report.vo.DeviceRecordVo;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.*;
/**
 * è®¾å¤‡ä½¿ç”¨è®°å½•报表服务实现
 */
@Service
@AllArgsConstructor
public class ReportDeviceRecordServiceImpl implements ReportDeviceRecordService {
    private ReportDeviceRecordMapper reportDeviceRecordMapper;
    @Override
    public Page<DeviceRecordVo> pageDeviceRecord(Page page, DeviceRecordDto dto) {
        return reportDeviceRecordMapper.pageDeviceRecord(page, dto);
    }
    @Override
    public List<Map<String, Object>> getStatistics(DeviceRecordDto dto) {
        return reportDeviceRecordMapper.getStatistics(dto);
    }
    @Override
    public void exportDeviceRecord(DeviceRecordDto dto, HttpServletResponse response) {
        try {
            // æŸ¥è¯¢å…¨éƒ¨æ•°æ®
            Page<DeviceRecordVo> page = new Page<>();
            page.setSize(Long.MAX_VALUE);
            Page<DeviceRecordVo> result = reportDeviceRecordMapper.pageDeviceRecord(page, dto);
            List<DeviceRecordVo> records = result.getRecords();
            // è®¾ç½®å“åº”头
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
            response.setCharacterEncoding("utf-8");
            String fileName = "设备使用记录_" + DateUtil.format(new Date(), "yyyyMMddHHmmss");
            response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");
            // ä½¿ç”¨EasyExcel导出
            EasyExcel.write(response.getOutputStream(), DeviceRecordVo.class)
                    .sheet("设备使用记录")
                    .doWrite(records);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
report-server/src/main/java/com/ruoyi/report/service/impl/SampleProgressServiceImpl.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,125 @@
package com.ruoyi.report.service.impl;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.excel.EasyExcel;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.report.dto.SampleProgressDto;
import com.ruoyi.report.mapper.SampleProgressMapper;
import com.ruoyi.report.service.SampleProgressService;
import com.ruoyi.report.vo.SampleProgressVo;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;
/**
 * æ ·å“è¿›åº¦æŠ¥è¡¨æœåŠ¡å®žçŽ°
 */
@Service
@AllArgsConstructor
public class SampleProgressServiceImpl implements SampleProgressService {
    private SampleProgressMapper sampleProgressMapper;
    @Override
    public Page<SampleProgressVo> pageSampleProgress(Page page, SampleProgressDto dto) {
        Page<SampleProgressVo> result = sampleProgressMapper.pageSampleProgress(page, dto);
        // å¤„理状态名称和进度百分比
        List<SampleProgressVo> records = result.getRecords();
        for (SampleProgressVo vo : records) {
            vo.setInsStateName(formatInsState(vo.getInsState()));
            if (vo.getTotalItems() != null && vo.getTotalItems() > 0) {
                int finished = vo.getFinishedItems() != null ? vo.getFinishedItems() : 0;
                vo.setProgressPercent((finished * 100.0) / vo.getTotalItems());
            }
        }
        return result;
    }
    @Override
    public Map<String, Object> getStatistics(SampleProgressDto dto) {
        Map<String, Object> statistics = sampleProgressMapper.getStatistics(dto);
        if (statistics == null) {
            statistics = new HashMap<>();
            statistics.put("waitInspection", 0);
            statistics.put("inspecting", 0);
            statistics.put("waitAudit", 0);
            statistics.put("finished", 0);
        }
        return statistics;
    }
    @Override
    public void exportSampleProgress(SampleProgressDto dto, HttpServletResponse response) {
        try {
            // æŸ¥è¯¢å…¨éƒ¨æ•°æ®
            Page<SampleProgressVo> page = new Page<>();
            page.setSize(Long.MAX_VALUE);
            Page<SampleProgressVo> result = sampleProgressMapper.pageSampleProgress(page, dto);
            // å¤„理数据
            List<SampleProgressVo> records = result.getRecords();
            for (SampleProgressVo vo : records) {
                vo.setInsStateName(formatInsState(vo.getInsState()));
                if (vo.getTotalItems() != null && vo.getTotalItems() > 0) {
                    int finished = vo.getFinishedItems() != null ? vo.getFinishedItems() : 0;
                    vo.setProgressPercent((finished * 100.0) / vo.getTotalItems());
                }
            }
            // è®¾ç½®å“åº”头
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
            response.setCharacterEncoding("utf-8");
            String fileName = "样品进度报表_" + DateUtil.format(new Date(), "yyyyMMddHHmmss");
            response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");
            // ä½¿ç”¨EasyExcel导出
            EasyExcel.write(response.getOutputStream(), SampleProgressVo.class)
                    .sheet("样品进度")
                    .doWrite(records);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    @Override
    public Map<String, Object> getChartData(SampleProgressDto dto) {
        List<Map<String, Object>> chartData = sampleProgressMapper.getChartData(dto);
        Map<String, Object> result = new HashMap<>();
        List<String> dates = chartData.stream()
                .map(m -> (String) m.get("date"))
                .collect(Collectors.toList());
        List<Integer> totalCounts = chartData.stream()
                .map(m -> ((Number) m.get("totalCount")).intValue())
                .collect(Collectors.toList());
        List<Integer> finishedCounts = chartData.stream()
                .map(m -> ((Number) m.get("finishedCount")).intValue())
                .collect(Collectors.toList());
        result.put("dates", dates);
        result.put("totalCounts", totalCounts);
        result.put("finishedCounts", finishedCounts);
        return result;
    }
    /**
     * æ ¼å¼åŒ–检测状态
     */
    private String formatInsState(Integer val) {
        if (val == null) return "";
        Map<Integer, String> map = new HashMap<>();
        map.put(0, "待检");
        map.put(1, "检验中");
        map.put(2, "已检验");
        map.put(3, "待审核");
        map.put(4, "审核未通过");
        map.put(5, "审核通过");
        return map.getOrDefault(val, "");
    }
}
report-server/src/main/java/com/ruoyi/report/service/impl/SampleRecordServiceImpl.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,89 @@
package com.ruoyi.report.service.impl;
import cn.hutool.core.date.DateUtil;
import com.alibaba.excel.EasyExcel;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.report.dto.SampleRecordDto;
import com.ruoyi.report.mapper.SampleRecordMapper;
import com.ruoyi.report.service.SampleRecordService;
import com.ruoyi.report.vo.SampleRecordVo;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.*;
/**
 * æ ·å“é¢†æ ·è®°å½•服务实现
 */
@Service
@AllArgsConstructor
public class SampleRecordServiceImpl implements SampleRecordService {
    private SampleRecordMapper sampleRecordMapper;
    @Override
    public Page<SampleRecordVo> pageSampleRecord(Page page, SampleRecordDto dto) {
        Page<SampleRecordVo> result = sampleRecordMapper.pageSampleRecord(page, dto);
        // å¤„理操作类型名称
        List<SampleRecordVo> records = result.getRecords();
        for (SampleRecordVo vo : records) {
            vo.setOperateTypeName(formatOperateType(vo.getOperateType()));
        }
        return result;
    }
    @Override
    public List<SampleRecordVo> getFlowRecord(Long sampleId) {
        List<SampleRecordVo> list = sampleRecordMapper.getFlowRecord(sampleId);
        for (SampleRecordVo vo : list) {
            vo.setOperateTypeName(formatOperateType(vo.getOperateType()));
        }
        return list;
    }
    @Override
    public void exportSampleRecord(SampleRecordDto dto, HttpServletResponse response) {
        try {
            // æŸ¥è¯¢å…¨éƒ¨æ•°æ®
            Page<SampleRecordVo> page = new Page<>();
            page.setSize(Long.MAX_VALUE);
            Page<SampleRecordVo> result = sampleRecordMapper.pageSampleRecord(page, dto);
            // å¤„理数据
            List<SampleRecordVo> records = result.getRecords();
            for (SampleRecordVo vo : records) {
                vo.setOperateTypeName(formatOperateType(vo.getOperateType()));
            }
            // è®¾ç½®å“åº”头
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
            response.setCharacterEncoding("utf-8");
            String fileName = "样品领样记录_" + DateUtil.format(new Date(), "yyyyMMddHHmmss");
            response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");
            // ä½¿ç”¨EasyExcel导出
            EasyExcel.write(response.getOutputStream(), SampleRecordVo.class)
                    .sheet("样品领样记录")
                    .doWrite(records);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    /**
     * æ ¼å¼åŒ–操作类型
     */
    private String formatOperateType(String val) {
        if (val == null) return "";
        Map<String, String> map = new HashMap<>();
        map.put("in", "入库");
        map.put("out", "出库");
        map.put("move", "移库");
        map.put("receive", "领用");
        map.put("return", "归还");
        return map.getOrDefault(val, val);
    }
}
report-server/src/main/java/com/ruoyi/report/service/impl/SpcChartServiceImpl.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,267 @@
package com.ruoyi.report.service.impl;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import com.alibaba.excel.EasyExcel;
import com.ruoyi.framework.exception.ErrorException;
import com.ruoyi.report.dto.SpcChartDto;
import com.ruoyi.report.mapper.SpcChartMapper;
import com.ruoyi.report.service.SpcChartService;
import com.ruoyi.report.vo.SpcResultVo;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.MathContext;
import java.math.RoundingMode;
import java.util.*;
import java.util.stream.Collectors;
/**
 * SPC控制图服务实现
 */
@Service
@AllArgsConstructor
public class SpcChartServiceImpl implements SpcChartService {
    private SpcChartMapper spcChartMapper;
    @Override
    public SpcResultVo analyze(SpcChartDto dto) {
        // æŸ¥è¯¢æ•°æ®
        List<Map<String, Object>> itemData = spcChartMapper.getItemData(dto);
        if (CollectionUtil.isEmpty(itemData)) {
            return null;
        }
        // èŽ·å–æ•°å€¼åˆ—è¡¨
        List<BigDecimal> values = itemData.stream()
                .map(m -> new BigDecimal((String) m.get("lastValue")))
                .collect(Collectors.toList());
        // å­ç»„大小,默认为5
        int subgroupSize = dto.getSubgroupSize() != null ? dto.getSubgroupSize() : 5;
        // åˆ†ç»„
        List<List<BigDecimal>> subgroups = new ArrayList<>();
        for (int i = 0; i < values.size(); i += subgroupSize) {
            int end = Math.min(i + subgroupSize, values.size());
            if (end - i >= 2) { // è‡³å°‘需要2个数据点
                subgroups.add(values.subList(i, end));
            }
        }
        if (subgroups.isEmpty()) {
            throw new ErrorException("数据不足以进行SPC分析");
        }
        // è®¡ç®—X-bar和R
        List<BigDecimal> xBarData = new ArrayList<>();
        List<BigDecimal> rData = new ArrayList<>();
        List<String> sampleLabels = new ArrayList<>();
        for (int i = 0; i < subgroups.size(); i++) {
            List<BigDecimal> subgroup = subgroups.get(i);
            BigDecimal sum = subgroup.stream().reduce(BigDecimal.ZERO, BigDecimal::add);
            BigDecimal mean = sum.divide(new BigDecimal(subgroup.size()), 10, RoundingMode.HALF_UP);
            BigDecimal max = subgroup.stream().max(BigDecimal::compareTo).orElse(BigDecimal.ZERO);
            BigDecimal min = subgroup.stream().min(BigDecimal::compareTo).orElse(BigDecimal.ZERO);
            BigDecimal range = max.subtract(min);
            xBarData.add(mean.setScale(4, RoundingMode.HALF_UP));
            rData.add(range.setScale(4, RoundingMode.HALF_UP));
            sampleLabels.add("组" + (i + 1));
        }
        // è®¡ç®—控制限
        BigDecimal xBarMean = xBarData.stream().reduce(BigDecimal.ZERO, BigDecimal::add)
                .divide(new BigDecimal(xBarData.size()), 10, RoundingMode.HALF_UP);
        BigDecimal rMean = rData.stream().reduce(BigDecimal.ZERO, BigDecimal::add)
                .divide(new BigDecimal(rData.size()), 10, RoundingMode.HALF_UP);
        // A2, D3, D4 å¸¸æ•° (针对子组大小)
        BigDecimal A2 = getA2(subgroupSize);
        BigDecimal D3 = getD3(subgroupSize);
        BigDecimal D4 = getD4(subgroupSize);
        // X-bar æŽ§åˆ¶é™
        BigDecimal xBarUcl = dto.getUcl() != null ? dto.getUcl() :
                xBarMean.add(A2.multiply(rMean)).setScale(4, RoundingMode.HALF_UP);
        BigDecimal xBarLcl = dto.getLcl() != null ? dto.getLcl() :
                xBarMean.subtract(A2.multiply(rMean)).setScale(4, RoundingMode.HALF_UP);
        // R æŽ§åˆ¶é™
        BigDecimal rUcl = D4.multiply(rMean).setScale(4, RoundingMode.HALF_UP);
        BigDecimal rLcl = D3.multiply(rMean).setScale(4, RoundingMode.HALF_UP);
        // æž„建结果
        SpcResultVo result = new SpcResultVo();
        SpcResultVo.ChartData xBarChart = new SpcResultVo.ChartData();
        xBarChart.setData(xBarData);
        xBarChart.setUcl(xBarUcl);
        xBarChart.setLcl(xBarLcl);
        xBarChart.setCl(xBarMean.setScale(4, RoundingMode.HALF_UP));
        xBarChart.setSampleLabels(sampleLabels);
        result.setXBar(xBarChart);
        SpcResultVo.ChartData rChart = new SpcResultVo.ChartData();
        rChart.setData(rData);
        rChart.setUcl(rUcl);
        rChart.setLcl(rLcl);
        rChart.setCl(rMean.setScale(4, RoundingMode.HALF_UP));
        rChart.setSampleLabels(sampleLabels);
        result.setRChart(rChart);
        // åˆ¶ç¨‹èƒ½åŠ›
        SpcResultVo.Capability capability = calculateCapability(values, dto.getUcl(), dto.getLcl());
        result.setCapability(capability);
        return result;
    }
    @Override
    public SpcResultVo.Capability getCapability(SpcChartDto dto) {
        List<Map<String, Object>> itemData = spcChartMapper.getItemData(dto);
        if (CollectionUtil.isEmpty(itemData)) {
            return null;
        }
        List<BigDecimal> values = itemData.stream()
                .map(m -> new BigDecimal((String) m.get("lastValue")))
                .collect(Collectors.toList());
        return calculateCapability(values, dto.getUcl(), dto.getLcl());
    }
    @Override
    public void export(SpcChartDto dto, HttpServletResponse response) {
        SpcResultVo result = analyze(dto);
        if (result == null) {
            return;
        }
        try {
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
            response.setCharacterEncoding("utf-8");
            String fileName = "SPC分析数据_" + DateUtil.format(new Date(), "yyyyMMddHHmmss");
            response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");
            // æž„建导出数据
            List<Map<String, Object>> exportData = new ArrayList<>();
            List<String> labels = result.getXBar().getSampleLabels();
            List<BigDecimal> xBarData = result.getXBar().getData();
            List<BigDecimal> rData = result.getRChart().getData();
            for (int i = 0; i < labels.size(); i++) {
                Map<String, Object> row = new HashMap<>();
                row.put("sampleLabel", labels.get(i));
                row.put("xBar", xBarData.get(i));
                row.put("r", rData.get(i));
                exportData.add(row);
            }
            EasyExcel.write(response.getOutputStream())
                    .sheet("SPC分析数据")
                    .doWrite(exportData);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    @Override
    public List<String> getItemNames(SpcChartDto dto) {
        return spcChartMapper.getItemNames(dto);
    }
    @Override
    public List<String> getSampleNames(SpcChartDto dto) {
        return spcChartMapper.getSampleNames(dto);
    }
    /**
     * è®¡ç®—制程能力
     */
    private SpcResultVo.Capability calculateCapability(List<BigDecimal> values, BigDecimal ucl, BigDecimal lcl) {
        if (ucl == null || lcl == null) {
            return null;
        }
        SpcResultVo.Capability capability = new SpcResultVo.Capability();
        // è®¡ç®—均值和标准差
        BigDecimal sum = values.stream().reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal mean = sum.divide(new BigDecimal(values.size()), 10, RoundingMode.HALF_UP);
        BigDecimal variance = BigDecimal.ZERO;
        for (BigDecimal v : values) {
            BigDecimal diff = v.subtract(mean);
            variance = variance.add(diff.multiply(diff));
        }
        variance = variance.divide(new BigDecimal(values.size() - 1), 10, RoundingMode.HALF_UP);
        BigDecimal stdDev = sqrt(variance);
        // è®¡ç®—Cp, Cpk
        BigDecimal USL = ucl;
        BigDecimal LSL = lcl;
        BigDecimal tolerance = USL.subtract(LSL);
        BigDecimal cp = tolerance.divide(stdDev.multiply(new BigDecimal(6)), 4, RoundingMode.HALF_UP);
        BigDecimal cpu = USL.subtract(mean).divide(stdDev.multiply(new BigDecimal(3)), 4, RoundingMode.HALF_UP);
        BigDecimal cpl = mean.subtract(LSL).divide(stdDev.multiply(new BigDecimal(3)), 4, RoundingMode.HALF_UP);
        BigDecimal cpk = cpu.min(cpl);
        capability.setCp(cp);
        capability.setCpk(cpk);
        capability.setPp(cp); // ç®€åŒ–处理
        capability.setPpk(cpk);
        return capability;
    }
    /**
     * èŽ·å–A2常数
     */
    private BigDecimal getA2(int n) {
        double[] a2Values = {0, 1.880, 1.023, 0.729, 0.577, 0.483, 0.419, 0.373, 0.337, 0.308};
        return new BigDecimal(a2Values[Math.min(n, 9)]);
    }
    /**
     * èŽ·å–D3常数
     */
    private BigDecimal getD3(int n) {
        double[] d3Values = {0, 0, 0, 0, 0, 0, 0.076, 0.136, 0.184, 0.223};
        return new BigDecimal(d3Values[Math.min(n, 9)]);
    }
    /**
     * èŽ·å–D4常数
     */
    private BigDecimal getD4(int n) {
        double[] d4Values = {0, 3.267, 2.574, 2.282, 2.114, 2.004, 1.924, 1.864, 1.816, 1.777};
        return new BigDecimal(d4Values[Math.min(n, 9)]);
    }
    /**
     * å¹³æ–¹æ ¹è®¡ç®—
     */
    private BigDecimal sqrt(BigDecimal value) {
        BigDecimal x = value;
        BigDecimal tolerance = new BigDecimal("1E-10");
        BigDecimal guess = value.divide(BigDecimal.valueOf(2), MathContext.DECIMAL128);
        while (x.subtract(guess).abs().compareTo(tolerance) > 0) {
            x = guess;
            guess = x.add(value.divide(x, MathContext.DECIMAL128)).divide(new BigDecimal("2"), MathContext.DECIMAL128);
        }
        return guess;
    }
}
report-server/src/main/java/com/ruoyi/report/service/impl/TestItemDataServiceImpl.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,144 @@
package com.ruoyi.report.service.impl;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import com.alibaba.excel.EasyExcel;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.report.dto.TestItemDataDto;
import com.ruoyi.report.mapper.TestItemDataMapper;
import com.ruoyi.report.service.TestItemDataService;
import com.ruoyi.report.vo.TestItemDataVo;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;
/**
 * æ£€æµ‹é¡¹ç›®æ•°æ®æœåŠ¡å®žçŽ°
 */
@Service
@AllArgsConstructor
public class TestItemDataServiceImpl implements TestItemDataService {
    private TestItemDataMapper testItemDataMapper;
    @Override
    public Page<TestItemDataVo> pageTestItemData(Page page, TestItemDataDto dto) {
        Page<TestItemDataVo> result = testItemDataMapper.pageTestItemData(page, dto);
        // å¤„理检测结果名称
        List<TestItemDataVo> records = result.getRecords();
        for (TestItemDataVo vo : records) {
            vo.setInsResultName(formatInsResult(vo.getInsResult()));
        }
        return result;
    }
    @Override
    public List<TestItemDataVo> getDetail(Long sampleId) {
        List<TestItemDataVo> list = testItemDataMapper.getDetail(sampleId);
        for (TestItemDataVo vo : list) {
            vo.setInsResultName(formatInsResult(vo.getInsResult()));
        }
        return list;
    }
    @Override
    public Map<String, Object> compare(TestItemDataDto dto) {
        if (CollectionUtils.isEmpty(dto.getSampleIds())) {
            return new HashMap<>();
        }
        // æŸ¥è¯¢æ•°æ®
        List<TestItemDataVo> dataList = testItemDataMapper.listBySampleIds(dto.getSampleIds());
        // èŽ·å–æ‰€æœ‰æ£€æµ‹é¡¹åç§°
        List<String> itemNames = dataList.stream()
                .map(TestItemDataVo::getItemName)
                .distinct()
                .sorted()
                .collect(Collectors.toList());
        // æŒ‰æ ·å“åˆ†ç»„
        Map<Long, List<TestItemDataVo>> sampleMap = dataList.stream()
                .collect(Collectors.groupingBy(TestItemDataVo::getSampleId));
        // æž„建比较数据
        List<Map<String, Object>> compareList = new ArrayList<>();
        for (Long sampleId : dto.getSampleIds()) {
            Map<String, Object> row = new HashMap<>();
            List<TestItemDataVo> sampleData = sampleMap.getOrDefault(sampleId, new ArrayList<>());
            // èŽ·å–æ ·å“ä¿¡æ¯
            if (CollectionUtil.isNotEmpty(sampleData)) {
                TestItemDataVo first = sampleData.get(0);
                row.put("sampleCode", first.getSampleCode());
                row.put("sampleName", first.getSampleName());
                row.put("batchNo", first.getBatchNo());
            }
            // å¡«å……检测项值
            for (String itemName : itemNames) {
                Optional<TestItemDataVo> match = sampleData.stream()
                        .filter(v -> v.getItemName().equals(itemName))
                        .findFirst();
                row.put(itemName, match.map(TestItemDataVo::getLastValue).orElse(null));
            }
            compareList.add(row);
        }
        Map<String, Object> result = new HashMap<>();
        result.put("itemNames", itemNames);
        result.put("compareList", compareList);
        return result;
    }
    @Override
    public void exportTestItemData(TestItemDataDto dto, HttpServletResponse response) {
        try {
            // æŸ¥è¯¢å…¨éƒ¨æ•°æ®
            Page<TestItemDataVo> page = new Page<>();
            page.setSize(Long.MAX_VALUE);
            Page<TestItemDataVo> result = testItemDataMapper.pageTestItemData(page, dto);
            // å¤„理数据
            List<TestItemDataVo> records = result.getRecords();
            for (TestItemDataVo vo : records) {
                vo.setInsResultName(formatInsResult(vo.getInsResult()));
            }
            // è®¾ç½®å“åº”头
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
            response.setCharacterEncoding("utf-8");
            String fileName = "检测项目数据_" + DateUtil.format(new Date(), "yyyyMMddHHmmss");
            response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");
            // ä½¿ç”¨EasyExcel导出
            EasyExcel.write(response.getOutputStream(), TestItemDataVo.class)
                    .sheet("检测项目数据")
                    .doWrite(records);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    @Override
    public List<String> getItemNames(TestItemDataDto dto) {
        return testItemDataMapper.getItemNames(dto);
    }
    /**
     * æ ¼å¼åŒ–检测结果
     */
    private String formatInsResult(Integer val) {
        if (val == null) return "";
        if (val == 1) return "合格";
        if (val == 0) return "不合格";
        return "";
    }
}
report-server/src/main/java/com/ruoyi/report/service/impl/WorkStatisticsServiceImpl.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,103 @@
package com.ruoyi.report.service.impl;
import cn.hutool.core.date.DateUtil;
import com.ruoyi.report.dto.WorkStatisticsDto;
import com.ruoyi.report.mapper.WorkStatisticsMapper;
import com.ruoyi.report.service.WorkStatisticsService;
import com.ruoyi.report.vo.WorkStatisticsVo;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
import java.util.*;
/**
 * å·¥ä½œç»Ÿè®¡æœåŠ¡å®žçŽ°
 */
@Service
@AllArgsConstructor
public class WorkStatisticsServiceImpl implements WorkStatisticsService {
    private WorkStatisticsMapper workStatisticsMapper;
    @Override
    public List<WorkStatisticsVo> getByUser(WorkStatisticsDto dto) {
        // å¤„理时间类型
        processDateType(dto);
        List<WorkStatisticsVo> list = workStatisticsMapper.getByUser(dto);
        // è®¡ç®—及时率
        for (WorkStatisticsVo vo : list) {
            int timely = vo.getTimelyCount() != null ? vo.getTimelyCount() : 0;
            int overdue = vo.getOverdueCount() != null ? vo.getOverdueCount() : 0;
            int total = timely + overdue;
            if (total > 0) {
                vo.setTimelyRate((timely * 100.0) / total);
            } else {
                vo.setTimelyRate(0.0);
            }
        }
        return list;
    }
    @Override
    public List<Map<String, Object>> getTimelyRate(WorkStatisticsDto dto) {
        processDateType(dto);
        return workStatisticsMapper.getTimelyRate(dto);
    }
    @Override
    public Map<String, Object> getTrend(WorkStatisticsDto dto) {
        processDateType(dto);
        List<Map<String, Object>> trendData = workStatisticsMapper.getTrend(dto);
        Map<String, Object> result = new HashMap<>();
        List<String> dates = new ArrayList<>();
        List<Integer> sampleCounts = new ArrayList<>();
        List<Integer> itemCounts = new ArrayList<>();
        for (Map<String, Object> item : trendData) {
            dates.add((String) item.get("date"));
            sampleCounts.add(((Number) item.get("sampleCount")).intValue());
            itemCounts.add(((Number) item.get("itemCount")).intValue());
        }
        result.put("dates", dates);
        result.put("sampleCounts", sampleCounts);
        result.put("itemCounts", itemCounts);
        return result;
    }
    /**
     * å¤„理时间类型
     */
    private void processDateType(WorkStatisticsDto dto) {
        if (dto.getStartTime() != null && dto.getEndTime() != null) {
            return;
        }
        String dateType = dto.getDateType();
        if (dateType == null || dateType.isEmpty()) {
            dateType = "2"; // é»˜è®¤æœ¬æœˆ
        }
        Date now = new Date();
        switch (dateType) {
            case "1": // æœ¬å‘¨
                dto.setStartTime(DateUtil.format(DateUtil.beginOfWeek(now), "yyyy-MM-dd HH:mm:ss"));
                dto.setEndTime(DateUtil.format(DateUtil.endOfWeek(now), "yyyy-MM-dd HH:mm:ss"));
                break;
            case "2": // æœ¬æœˆ
                dto.setStartTime(DateUtil.format(DateUtil.beginOfMonth(now), "yyyy-MM-dd HH:mm:ss"));
                dto.setEndTime(DateUtil.format(DateUtil.endOfMonth(now), "yyyy-MM-dd HH:mm:ss"));
                break;
            case "3": // æœ¬å¹´
                dto.setStartTime(DateUtil.format(DateUtil.beginOfYear(now), "yyyy-MM-dd HH:mm:ss"));
                dto.setEndTime(DateUtil.format(DateUtil.endOfYear(now), "yyyy-MM-dd HH:mm:ss"));
                break;
        }
    }
}
report-server/src/main/java/com/ruoyi/report/vo/DashboardOverviewVo.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,42 @@
package com.ruoyi.report.vo;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.List;
import java.util.Map;
/**
 * çœ‹æ¿æ¦‚览VO
 */
@Data
public class DashboardOverviewVo {
    @ApiModelProperty("待领样品数")
    private Integer waitReceive;
    @ApiModelProperty("待检样品数")
    private Integer waitInspection;
    @ApiModelProperty("待审核样品数")
    private Integer waitAudit;
    @ApiModelProperty("待编制报告数")
    private Integer waitReport;
    @ApiModelProperty("今日新增样品")
    private Integer todayNewSample;
    @ApiModelProperty("今日完成样品")
    private Integer todayFinished;
    @ApiModelProperty("近30天原材料检验结果")
    private List<Map<String, Object>> rawMaterialResult;
    @ApiModelProperty("近30天半成品检验结果")
    private List<Map<String, Object>> semiFinishedResult;
    @ApiModelProperty("近30天成品检验结果")
    private List<Map<String, Object>> finishedProductResult;
}
report-server/src/main/java/com/ruoyi/report/vo/DeviceRecordVo.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,54 @@
package com.ruoyi.report.vo;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
 * è®¾å¤‡ä½¿ç”¨è®°å½•VO
 */
@Data
public class DeviceRecordVo {
    @ApiModelProperty("记录ID")
    private Long id;
    @ApiModelProperty("设备ID")
    private Long deviceId;
    @ApiModelProperty("设备编号")
    private String deviceCode;
    @ApiModelProperty("设备名称")
    private String deviceName;
    @ApiModelProperty("样品编号")
    private String sampleCode;
    @ApiModelProperty("使用人")
    private String useUser;
    @ApiModelProperty("开始时间")
    private String startTime;
    @ApiModelProperty("结束时间")
    private String endTime;
    @ApiModelProperty("温度")
    private String temperature;
    @ApiModelProperty("湿度")
    private String humidity;
    @ApiModelProperty("使用前状态(0异常/1良好)")
    private Integer useBefore;
    @ApiModelProperty("使用后状态(0异常/1良好)")
    private Integer useAfter;
    @ApiModelProperty("异常情况")
    private String abnormal;
    @ApiModelProperty("备注")
    private String remark;
}
report-server/src/main/java/com/ruoyi/report/vo/NormalDistributionVo.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,42 @@
package com.ruoyi.report.vo;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.math.BigDecimal;
import java.util.List;
/**
 * æ­£æ€åˆ†å¸ƒåˆ†æžç»“æžœVO
 */
@Data
public class NormalDistributionVo {
    @ApiModelProperty("直方图分组边界")
    private List<BigDecimal> binEdges;
    @ApiModelProperty("直方图频数")
    private List<Integer> frequencies;
    @ApiModelProperty("正态分布曲线Xè½´")
    private List<BigDecimal> normalX;
    @ApiModelProperty("正态分布曲线Yè½´")
    private List<BigDecimal> normalY;
    @ApiModelProperty("均值")
    private BigDecimal mean;
    @ApiModelProperty("标准差")
    private BigDecimal stdDev;
    @ApiModelProperty("最小值")
    private BigDecimal min;
    @ApiModelProperty("最大值")
    private BigDecimal max;
    @ApiModelProperty("样本数")
    private Integer sampleSize;
}
report-server/src/main/java/com/ruoyi/report/vo/ParetoVo.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,23 @@
package com.ruoyi.report.vo;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.List;
/**
 * å¸•累托图VO
 */
@Data
public class ParetoVo {
    @ApiModelProperty("不合格项目")
    private List<String> categories;
    @ApiModelProperty("不合格次数")
    private List<Integer> values;
    @ApiModelProperty("累计百分比")
    private List<Double> cumulativePercent;
}
report-server/src/main/java/com/ruoyi/report/vo/RankingVo.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,30 @@
package com.ruoyi.report.vo;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
 * æŽ’行VO
 */
@Data
public class RankingVo {
    @ApiModelProperty("排名")
    private Integer rank;
    @ApiModelProperty("用户ID")
    private Long userId;
    @ApiModelProperty("用户名称")
    private String userName;
    @ApiModelProperty("部门名称")
    private String deptName;
    @ApiModelProperty("提交数量")
    private Integer submitCount;
    @ApiModelProperty("完成数量")
    private Integer finishCount;
}
report-server/src/main/java/com/ruoyi/report/vo/SampleProgressVo.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,57 @@
package com.ruoyi.report.vo;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
 * æ ·å“è¿›åº¦VO
 */
@Data
public class SampleProgressVo {
    @ApiModelProperty("样品ID")
    private Long sampleId;
    @ApiModelProperty("委托编号")
    private String entrustCode;
    @ApiModelProperty("样品编号")
    private String sampleCode;
    @ApiModelProperty("样品名称")
    private String sampleName;
    @ApiModelProperty("报告编号")
    private String reportCode;
    @ApiModelProperty("检测状态(0待检/1检验中/2已检验/3待审核/4审核未通过/5审核通过)")
    private Integer insState;
    @ApiModelProperty("检测状态名称")
    private String insStateName;
    @ApiModelProperty("进度百分比")
    private Double progressPercent;
    @ApiModelProperty("已完成项目数")
    private Integer finishedItems;
    @ApiModelProperty("总项目数")
    private Integer totalItems;
    @ApiModelProperty("计划完成时间")
    private String planFinishTime;
    @ApiModelProperty("实际完成时间")
    private String actualFinishTime;
    @ApiModelProperty("负责人")
    private String chargeUser;
    @ApiModelProperty("客户名称")
    private String custom;
    @ApiModelProperty("创建时间")
    private String createTime;
}
report-server/src/main/java/com/ruoyi/report/vo/SampleRecordVo.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,48 @@
package com.ruoyi.report.vo;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
 * æ ·å“é¢†æ ·è®°å½•VO
 */
@Data
public class SampleRecordVo {
    @ApiModelProperty("记录ID")
    private Long id;
    @ApiModelProperty("样品ID")
    private Long sampleId;
    @ApiModelProperty("样品编号")
    private String sampleCode;
    @ApiModelProperty("样品名称")
    private String sampleName;
    @ApiModelProperty("客户名称")
    private String custom;
    @ApiModelProperty("操作类型(领用/归还/转移)")
    private String operateType;
    @ApiModelProperty("操作类型名称")
    private String operateTypeName;
    @ApiModelProperty("操作人")
    private String operateUser;
    @ApiModelProperty("操作时间")
    private String operateTime;
    @ApiModelProperty("原库位")
    private String fromCell;
    @ApiModelProperty("目标库位")
    private String toCell;
    @ApiModelProperty("备注")
    private String remark;
}
report-server/src/main/java/com/ruoyi/report/vo/SpcResultVo.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,58 @@
package com.ruoyi.report.vo;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
/**
 * SPC分析结果VO
 */
@Data
public class SpcResultVo {
    @ApiModelProperty("X-bar图数据")
    private ChartData xBar;
    @ApiModelProperty("R图数据")
    private ChartData rChart;
    @ApiModelProperty("制程能力")
    private Capability capability;
    @Data
    public static class ChartData {
        @ApiModelProperty("数据点")
        private List<BigDecimal> data;
        @ApiModelProperty("控制上限")
        private BigDecimal ucl;
        @ApiModelProperty("控制下限")
        private BigDecimal lcl;
        @ApiModelProperty("中心线")
        private BigDecimal cl;
        @ApiModelProperty("样本编号")
        private List<String> sampleLabels;
    }
    @Data
    public static class Capability {
        @ApiModelProperty("制程能力指数Cp")
        private BigDecimal cp;
        @ApiModelProperty("制程能力指数Cpk")
        private BigDecimal cpk;
        @ApiModelProperty("制程性能指数Pp")
        private BigDecimal pp;
        @ApiModelProperty("制程性能指数Ppk")
        private BigDecimal ppk;
    }
}
report-server/src/main/java/com/ruoyi/report/vo/TaskCalendarVo.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,27 @@
package com.ruoyi.report.vo;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
 * ä»»åŠ¡æ—¥åŽ†VO
 */
@Data
public class TaskCalendarVo {
    @ApiModelProperty("日期")
    private String date;
    @ApiModelProperty("样品数量")
    private Integer sampleCount;
    @ApiModelProperty("完成数量")
    private Integer finishedCount;
    @ApiModelProperty("待处理数量")
    private Integer pendingCount;
    @ApiModelProperty("超期数量")
    private Integer overdueCount;
}
report-server/src/main/java/com/ruoyi/report/vo/TestItemDataVo.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,57 @@
package com.ruoyi.report.vo;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
 * æ£€æµ‹é¡¹ç›®æ•°æ®VO
 */
@Data
public class TestItemDataVo {
    @ApiModelProperty("检测项ID")
    private Long productId;
    @ApiModelProperty("样品ID")
    private Long sampleId;
    @ApiModelProperty("样品编号")
    private String sampleCode;
    @ApiModelProperty("样品名称")
    private String sampleName;
    @ApiModelProperty("生产订单")
    private String productionOrder;
    @ApiModelProperty("批次号")
    private String batchNo;
    @ApiModelProperty("检测项名称")
    private String itemName;
    @ApiModelProperty("检测值")
    private String lastValue;
    @ApiModelProperty("标准值")
    private String standardValue;
    @ApiModelProperty("检测结果(1合格/0不合格)")
    private Integer insResult;
    @ApiModelProperty("检测结果名称")
    private String insResultName;
    @ApiModelProperty("单位")
    private String unit;
    @ApiModelProperty("检测人")
    private String insUser;
    @ApiModelProperty("检测时间")
    private String insTime;
    @ApiModelProperty("报告编号")
    private String reportCode;
}
report-server/src/main/java/com/ruoyi/report/vo/WorkStatisticsVo.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,36 @@
package com.ruoyi.report.vo;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
 * å·¥ä½œç»Ÿè®¡VO
 */
@Data
public class WorkStatisticsVo {
    @ApiModelProperty("用户ID")
    private Long userId;
    @ApiModelProperty("用户名称")
    private String userName;
    @ApiModelProperty("部门名称")
    private String deptName;
    @ApiModelProperty("检测样品数")
    private Integer sampleCount;
    @ApiModelProperty("检测项目数")
    private Integer itemCount;
    @ApiModelProperty("及时率(%)")
    private Double timelyRate;
    @ApiModelProperty("按时完成数")
    private Integer timelyCount;
    @ApiModelProperty("超期完成数")
    private Integer overdueCount;
}
report-server/src/main/resources/mapper/DashboardMapper.xml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,164 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ruoyi.report.mapper.DashboardMapper">
    <!-- èŽ·å–å¾…é¢†æ ·å“æ•° -->
    <select id="getWaitReceive" resultType="java.lang.Integer">
        SELECT COUNT(*) FROM ins_sample WHERE ins_state = 0
    </select>
    <!-- èŽ·å–å¾…æ£€æ ·å“æ•° -->
    <select id="getWaitInspection" resultType="java.lang.Integer">
        SELECT COUNT(*) FROM ins_order WHERE ins_state = 0
    </select>
    <!-- èŽ·å–å¾…å®¡æ ¸æ ·å“æ•° -->
    <select id="getWaitAudit" resultType="java.lang.Integer">
        SELECT COUNT(*) FROM ins_order WHERE ins_state = 3
    </select>
    <!-- èŽ·å–å¾…ç¼–åˆ¶æŠ¥å‘Šæ•° -->
    <select id="getWaitReport" resultType="java.lang.Integer">
        SELECT COUNT(*) FROM ins_report WHERE state = 0
    </select>
    <!-- ä»Šæ—¥æ–°å¢žæ ·å“ -->
    <select id="getTodayNewSample" resultType="java.lang.Integer">
        SELECT COUNT(*) FROM ins_sample
        WHERE DATE(create_time) = CURDATE()
    </select>
    <!-- ä»Šæ—¥å®Œæˆæ ·å“ -->
    <select id="getTodayFinished" resultType="java.lang.Integer">
        SELECT COUNT(*) FROM ins_order
        WHERE ins_state = 5 AND DATE(ins_time) = CURDATE()
    </select>
    <!-- åŽ†å²15天数据 -->
    <select id="getHistoryDays" resultType="com.ruoyi.report.vo.TaskCalendarVo">
        SELECT
            DATE_FORMAT(DATE_SUB(CURDATE(), INTERVAL n DAY), '%Y-%m-%d') AS date,
            COUNT(DISTINCT s.id) AS sampleCount,
            SUM(CASE WHEN o.ins_state = 5 THEN 1 ELSE 0 END) AS finishedCount,
            SUM(CASE WHEN o.ins_state IN (0,1,2,3) THEN 1 ELSE 0 END) AS pendingCount,
            SUM(CASE WHEN o.ins_state IN (0,1,2,3) AND o.appointed &lt; NOW() THEN 1 ELSE 0 END) AS overdueCount
        FROM (
            SELECT 0 AS n UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4
            UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9
            UNION SELECT 10 UNION SELECT 11 UNION SELECT 12 UNION SELECT 13 UNION SELECT 14
        ) days
        LEFT JOIN ins_order o ON DATE(o.create_time) = DATE_SUB(CURDATE(), INTERVAL n DAY)
        LEFT JOIN ins_sample s ON o.id = s.ins_order_id
        GROUP BY date
        ORDER BY date ASC
    </select>
    <!-- æœªæ¥15天任务 -->
    <select id="getFutureDays" resultType="com.ruoyi.report.vo.TaskCalendarVo">
        SELECT
            DATE_FORMAT(DATE_ADD(CURDATE(), INTERVAL n DAY), '%Y-%m-%d') AS date,
            COUNT(DISTINCT s.id) AS sampleCount,
            0 AS finishedCount,
            SUM(CASE WHEN o.ins_state IN (0,1,2,3) THEN 1 ELSE 0 END) AS pendingCount,
            0 AS overdueCount
        FROM (
            SELECT 0 AS n UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4
            UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9
            UNION SELECT 10 UNION SELECT 11 UNION SELECT 12 UNION SELECT 13 UNION SELECT 14
        ) days
        LEFT JOIN ins_order o ON DATE(o.appointed) = DATE_ADD(CURDATE(), INTERVAL n DAY) AND o.ins_state IN (0,1,2,3)
        LEFT JOIN ins_sample s ON o.id = s.ins_order_id
        GROUP BY date
        ORDER BY date ASC
    </select>
    <!-- æäº¤æŽ’行(原始记录) -->
    <select id="getOriginalRecordRanking" resultType="com.ruoyi.report.vo.RankingVo">
        SELECT
            u.id AS userId,
            u.name AS userName,
            d.dept_name AS deptName,
            COUNT(*) AS submitCount
        FROM ins_product p
        LEFT JOIN ins_product_user pu ON p.id = pu.ins_product_id
        LEFT JOIN user u ON pu.create_user = u.id
        LEFT JOIN sys_dept d ON u.dept_id = d.dept_id
        LEFT JOIN ins_sample s ON p.ins_sample_id = s.id
        LEFT JOIN ins_order o ON s.ins_order_id = o.id
        WHERE o.ins_time IS NOT NULL
        <if test="dto.startTime != null and dto.startTime != ''">
            AND o.ins_time >= #{dto.startTime}
        </if>
        <if test="dto.endTime != null and dto.endTime != ''">
            AND o.ins_time &lt;= #{dto.endTime}
        </if>
        GROUP BY u.id, u.name, d.dept_name
        ORDER BY submitCount DESC
        LIMIT 10
    </select>
    <!-- æäº¤æŽ’行(报告) -->
    <select id="getReportRanking" resultType="com.ruoyi.report.vo.RankingVo">
        SELECT
            u.id AS userId,
            u.name AS userName,
            d.dept_name AS deptName,
            COUNT(*) AS submitCount
        FROM ins_report r
        LEFT JOIN user u ON r.write_user_id = u.id
        LEFT JOIN sys_dept d ON u.dept_id = d.dept_id
        WHERE r.state >= 1
        <if test="dto.startTime != null and dto.startTime != ''">
            AND r.create_time >= #{dto.startTime}
        </if>
        <if test="dto.endTime != null and dto.endTime != ''">
            AND r.create_time &lt;= #{dto.endTime}
        </if>
        GROUP BY u.id, u.name, d.dept_name
        ORDER BY submitCount DESC
        LIMIT 10
    </select>
    <!-- è¿‘30天检验结果 -->
    <select id="getInsResultByDays" resultType="java.util.Map">
        SELECT
            DATE_FORMAT(DATE_SUB(CURDATE(), INTERVAL n DAY), '%Y-%m-%d') AS date,
            SUM(CASE WHEN p.ins_result = 1 THEN 1 ELSE 0 END) AS qualified,
            SUM(CASE WHEN p.ins_result = 0 THEN 1 ELSE 0 END) AS unqualified,
            COUNT(*) AS total
        FROM (
            SELECT 0 AS n UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4
            UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9
            UNION SELECT 10 UNION SELECT 11 UNION SELECT 12 UNION SELECT 13 UNION SELECT 14
            UNION SELECT 15 UNION SELECT 16 UNION SELECT 17 UNION SELECT 18 UNION SELECT 19
            UNION SELECT 20 UNION SELECT 21 UNION SELECT 22 UNION SELECT 23 UNION SELECT 24
            UNION SELECT 25 UNION SELECT 26 UNION SELECT 27 UNION SELECT 28 UNION SELECT 29
        ) days
        LEFT JOIN ins_product p ON DATE(p.create_time) = DATE_SUB(CURDATE(), INTERVAL n DAY)
        LEFT JOIN ins_sample s ON p.ins_sample_id = s.id
        LEFT JOIN ins_order o ON s.ins_order_id = o.id
        WHERE p.ins_result IS NOT NULL
        <if test="orderType != null and orderType != ''">
            AND o.order_type = #{orderType}
        </if>
        GROUP BY date
        ORDER BY date ASC
    </select>
    <!-- èŽ·å–è¯­éŸ³æ’­æŠ¥é˜Ÿåˆ— -->
    <select id="getVoiceQueue" resultType="java.util.Map">
        SELECT
            id,
            event_type AS eventType,
            event_name AS eventName,
            details,
            voice_text AS voiceText,
            priority,
            create_time AS createTime
        FROM voice_queue
        WHERE status = 0
        ORDER BY priority DESC, create_time ASC
        LIMIT 10
    </select>
</mapper>
report-server/src/main/resources/mapper/NormalDistributionMapper.xml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,57 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ruoyi.report.mapper.NormalDistributionMapper">
    <!-- æŸ¥è¯¢æ£€æµ‹é¡¹æ•°æ® -->
    <select id="getItemData" resultType="java.util.Map">
        SELECT
            s.sample_code AS sampleCode,
            s.sample AS sampleName,
            p.inspection_item AS itemName,
            p.last_value AS lastValue,
            o.ins_time AS insTime
        FROM ins_product p
        LEFT JOIN ins_sample s ON p.ins_sample_id = s.id
        LEFT JOIN ins_order o ON s.ins_order_id = o.id
        WHERE p.ins_result IS NOT NULL AND p.last_value IS NOT NULL
        <if test="dto.itemName != null and dto.itemName != ''">
            AND p.inspection_item = #{dto.itemName}
        </if>
        <if test="dto.sampleName != null and dto.sampleName != ''">
            AND s.sample LIKE CONCAT('%', #{dto.sampleName}, '%')
        </if>
        <if test="dto.startDate != null and dto.startDate != ''">
            AND o.ins_time >= #{dto.startDate}
        </if>
        <if test="dto.endDate != null and dto.endDate != ''">
            AND o.ins_time &lt;= #{dto.endDate}
        </if>
        ORDER BY o.ins_time ASC
    </select>
    <!-- æŸ¥è¯¢å¯é€‰æ£€æµ‹é¡¹ -->
    <select id="getItemNames" resultType="java.lang.String">
        SELECT DISTINCT p.inspection_item
        FROM ins_product p
        LEFT JOIN ins_sample s ON p.ins_sample_id = s.id
        WHERE p.ins_result IS NOT NULL AND p.last_value IS NOT NULL
        <if test="dto.sampleName != null and dto.sampleName != ''">
            AND s.sample LIKE CONCAT('%', #{dto.sampleName}, '%')
        </if>
        ORDER BY p.inspection_item ASC
    </select>
    <!-- æŸ¥è¯¢å¯é€‰æ ·å“åç§°åˆ—表 -->
    <select id="getSampleNames" resultType="java.lang.String">
        SELECT DISTINCT s.sample
        FROM ins_product p
        LEFT JOIN ins_sample s ON p.ins_sample_id = s.id
        LEFT JOIN ins_order o ON s.ins_order_id = o.id
        WHERE p.ins_result IS NOT NULL AND p.last_value IS NOT NULL
        <if test="dto.itemName != null and dto.itemName != ''">
            AND p.inspection_item = #{dto.itemName}
        </if>
        ORDER BY s.sample ASC
    </select>
</mapper>
report-server/src/main/resources/mapper/PassRateMapper.xml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,126 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ruoyi.report.mapper.PassRateMapper">
    <!-- åŽŸææ–™åˆæ ¼çŽ‡ -->
    <select id="getRawMaterialPassRate" resultType="java.util.Map">
        SELECT
            s.sample AS sampleName,
            o.entrust_code AS batchNo,
            COUNT(*) AS totalCount,
            SUM(CASE WHEN p.ins_result = 1 THEN 1 ELSE 0 END) AS qualifiedCount,
            SUM(CASE WHEN p.ins_result = 0 THEN 1 ELSE 0 END) AS unqualifiedCount,
            ROUND(SUM(CASE WHEN p.ins_result = 1 THEN 1 ELSE 0 END) * 100.0 / COUNT(*), 2) AS passRate
        FROM ins_product p
        LEFT JOIN ins_sample s ON p.ins_sample_id = s.id
        LEFT JOIN ins_order o ON s.ins_order_id = o.id
        WHERE p.ins_result IS NOT NULL AND o.order_type = '1'
        <if test="dto.startTime != null and dto.startTime != ''">
            AND o.ins_time >= #{dto.startTime}
        </if>
        <if test="dto.endTime != null and dto.endTime != ''">
            AND o.ins_time &lt;= #{dto.endTime}
        </if>
        <if test="dto.sampleName != null and dto.sampleName != ''">
            AND s.sample LIKE CONCAT('%', #{dto.sampleName}, '%')
        </if>
        <if test="dto.supplierName != null and dto.supplierName != ''">
            AND o.custom LIKE CONCAT('%', #{dto.supplierName}, '%')
        </if>
        GROUP BY s.sample, o.entrust_code
        ORDER BY passRate ASC
    </select>
    <!-- ä¾›åº”商不合格统计 -->
    <select id="getSupplierUnqualified" resultType="java.util.Map">
        SELECT
            o.custom AS supplierName,
            COUNT(*) AS totalCount,
            SUM(CASE WHEN p.ins_result = 0 THEN 1 ELSE 0 END) AS unqualifiedCount
        FROM ins_product p
        LEFT JOIN ins_sample s ON p.ins_sample_id = s.id
        LEFT JOIN ins_order o ON s.ins_order_id = o.id
        WHERE p.ins_result IS NOT NULL AND o.order_type = '1'
        <if test="dto.startTime != null and dto.startTime != ''">
            AND o.ins_time >= #{dto.startTime}
        </if>
        <if test="dto.endTime != null and dto.endTime != ''">
            AND o.ins_time &lt;= #{dto.endTime}
        </if>
        GROUP BY o.custom
        HAVING unqualifiedCount > 0
        ORDER BY unqualifiedCount DESC
    </select>
    <!-- ä¸åˆæ ¼é¡¹ç›®ç»Ÿè®¡(用于帕累托图) -->
    <select id="getUnqualifiedItemStats" resultType="java.util.Map">
        SELECT
            p.inspection_item AS itemName,
            COUNT(*) AS unqualifiedCount
        FROM ins_product p
        LEFT JOIN ins_sample s ON p.ins_sample_id = s.id
        LEFT JOIN ins_order o ON s.ins_order_id = o.id
        WHERE p.ins_result = 0
        <if test="dto.startTime != null and dto.startTime != ''">
            AND o.ins_time >= #{dto.startTime}
        </if>
        <if test="dto.endTime != null and dto.endTime != ''">
            AND o.ins_time &lt;= #{dto.endTime}
        </if>
        <if test="dto.orderType != null and dto.orderType != ''">
            AND o.order_type = #{dto.orderType}
        </if>
        GROUP BY p.inspection_item
        ORDER BY unqualifiedCount DESC
    </select>
    <!-- å·¥åºåˆæ ¼çއ -->
    <select id="getProcessPassRate" resultType="java.util.Map">
        SELECT
            o.laboratory AS processName,
            COUNT(*) AS totalCount,
            SUM(CASE WHEN p.ins_result = 1 THEN 1 ELSE 0 END) AS qualifiedCount,
            SUM(CASE WHEN p.ins_result = 0 THEN 1 ELSE 0 END) AS unqualifiedCount,
            ROUND(SUM(CASE WHEN p.ins_result = 1 THEN 1 ELSE 0 END) * 100.0 / COUNT(*), 2) AS passRate
        FROM ins_product p
        LEFT JOIN ins_sample s ON p.ins_sample_id = s.id
        LEFT JOIN ins_order o ON s.ins_order_id = o.id
        WHERE p.ins_result IS NOT NULL
        <if test="dto.startTime != null and dto.startTime != ''">
            AND o.ins_time >= #{dto.startTime}
        </if>
        <if test="dto.endTime != null and dto.endTime != ''">
            AND o.ins_time &lt;= #{dto.endTime}
        </if>
        <if test="dto.orderType != null and dto.orderType != ''">
            AND o.order_type = #{dto.orderType}
        </if>
        GROUP BY o.laboratory
        ORDER BY passRate ASC
    </select>
    <!-- æœºå°ä¸åˆæ ¼ç»Ÿè®¡ -->
    <select id="getMachineUnqualified" resultType="java.util.Map">
        SELECT
            p.factory AS machineNo,
            COUNT(*) AS totalCount,
            SUM(CASE WHEN p.ins_result = 0 THEN 1 ELSE 0 END) AS unqualifiedCount
        FROM ins_product p
        LEFT JOIN ins_sample s ON p.ins_sample_id = s.id
        LEFT JOIN ins_order o ON s.ins_order_id = o.id
        WHERE p.ins_result IS NOT NULL
        <if test="dto.startTime != null and dto.startTime != ''">
            AND o.ins_time >= #{dto.startTime}
        </if>
        <if test="dto.endTime != null and dto.endTime != ''">
            AND o.ins_time &lt;= #{dto.endTime}
        </if>
        <if test="dto.orderType != null and dto.orderType != ''">
            AND o.order_type = #{dto.orderType}
        </if>
        GROUP BY p.factory
        HAVING unqualifiedCount > 0
        ORDER BY unqualifiedCount DESC
    </select>
</mapper>
report-server/src/main/resources/mapper/ReportDeviceRecordMapper.xml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,73 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ruoyi.report.mapper.ReportDeviceRecordMapper">
    <!-- åˆ†é¡µæŸ¥è¯¢è®¾å¤‡ä½¿ç”¨è®°å½• -->
    <select id="pageDeviceRecord" resultType="com.ruoyi.report.vo.DeviceRecordVo">
        SELECT
            r.id AS id,
            d.id AS deviceId,
            d.management_number AS deviceCode,
            d.device_name AS deviceName,
            r.sample_code AS sampleCode,
            r.use_person AS useUser,
            r.use_start_date AS startTime,
            r.use_end_date AS endTime,
            r.temperature,
            r.humidity,
            r.use_before AS useBefore,
            r.use_after AS useAfter,
            r.abnormal,
            r.remark
        FROM device_record r
        LEFT JOIN device d ON r.device_id = d.id
        WHERE 1=1
        <if test="dto.deviceCode != null and dto.deviceCode != ''">
            AND d.management_number LIKE CONCAT('%', #{dto.deviceCode}, '%')
        </if>
        <if test="dto.deviceName != null and dto.deviceName != ''">
            AND d.device_name LIKE CONCAT('%', #{dto.deviceName}, '%')
        </if>
        <if test="dto.useUser != null and dto.useUser != ''">
            AND r.use_person LIKE CONCAT('%', #{dto.useUser}, '%')
        </if>
        <if test="dto.sampleCode != null and dto.sampleCode != ''">
            AND r.sample_code LIKE CONCAT('%', #{dto.sampleCode}, '%')
        </if>
        <if test="dto.startTime != null and dto.startTime != ''">
            AND r.use_start_date >= #{dto.startTime}
        </if>
        <if test="dto.endTime != null and dto.endTime != ''">
            AND r.use_end_date &lt;= #{dto.endTime}
        </if>
        ORDER BY r.use_start_date DESC
    </select>
    <!-- è®¾å¤‡ä½¿ç”¨ç»Ÿè®¡ -->
    <select id="getStatistics" resultType="java.util.Map">
        SELECT
            d.device_name AS deviceName,
            d.management_number AS deviceCode,
            COUNT(*) AS useCount,
            COUNT(DISTINCT r.sample_code) AS sampleCount,
            COUNT(DISTINCT r.use_person_id) AS userCount
        FROM device_record r
        LEFT JOIN device d ON r.device_id = d.id
        WHERE 1=1
        <if test="dto.deviceCode != null and dto.deviceCode != ''">
            AND d.management_number LIKE CONCAT('%', #{dto.deviceCode}, '%')
        </if>
        <if test="dto.deviceName != null and dto.deviceName != ''">
            AND d.device_name LIKE CONCAT('%', #{dto.deviceName}, '%')
        </if>
        <if test="dto.startTime != null and dto.startTime != ''">
            AND r.use_start_date >= #{dto.startTime}
        </if>
        <if test="dto.endTime != null and dto.endTime != ''">
            AND r.use_end_date &lt;= #{dto.endTime}
        </if>
        GROUP BY d.id
        ORDER BY useCount DESC
    </select>
</mapper>
report-server/src/main/resources/mapper/SampleProgressMapper.xml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,98 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ruoyi.report.mapper.SampleProgressMapper">
    <!-- åˆ†é¡µæŸ¥è¯¢æ ·å“è¿›åº¦ -->
    <select id="pageSampleProgress" resultType="com.ruoyi.report.vo.SampleProgressVo">
        SELECT
            s.id AS sampleId,
            o.entrust_code AS entrustCode,
            s.sample_code AS sampleCode,
            s.sample AS sampleName,
            r.code AS reportCode,
            o.ins_state AS insState,
            COUNT(p.id) AS totalItems,
            SUM(CASE WHEN p.ins_result IS NOT NULL THEN 1 ELSE 0 END) AS finishedItems,
            o.appointed AS planFinishTime,
            o.ins_time AS actualFinishTime,
            u.name AS chargeUser,
            o.custom AS custom,
            s.create_time AS createTime
        FROM ins_sample s
        LEFT JOIN ins_order o ON s.ins_order_id = o.id
        LEFT JOIN ins_product p ON s.id = p.ins_sample_id
        LEFT JOIN ins_report r ON o.id = r.ins_order_id
        LEFT JOIN user u ON o.prepare_user_id = u.id
        WHERE 1=1
        <if test="dto.entrustCode != null and dto.entrustCode != ''">
            AND o.entrust_code LIKE CONCAT('%', #{dto.entrustCode}, '%')
        </if>
        <if test="dto.sampleCode != null and dto.sampleCode != ''">
            AND s.sample_code LIKE CONCAT('%', #{dto.sampleCode}, '%')
        </if>
        <if test="dto.sampleName != null and dto.sampleName != ''">
            AND s.sample LIKE CONCAT('%', #{dto.sampleName}, '%')
        </if>
        <if test="dto.reportCode != null and dto.reportCode != ''">
            AND r.code LIKE CONCAT('%', #{dto.reportCode}, '%')
        </if>
        <if test="dto.insState != null">
            AND o.ins_state = #{dto.insState}
        </if>
        <if test="dto.custom != null and dto.custom != ''">
            AND o.custom LIKE CONCAT('%', #{dto.custom}, '%')
        </if>
        <if test="dto.startTime != null and dto.startTime != ''">
            AND s.create_time >= #{dto.startTime}
        </if>
        <if test="dto.endTime != null and dto.endTime != ''">
            AND s.create_time &lt;= #{dto.endTime}
        </if>
        GROUP BY s.id
        ORDER BY s.create_time DESC
    </select>
    <!-- èŽ·å–ç»Ÿè®¡æ•°æ® -->
    <select id="getStatistics" resultType="java.util.Map">
        SELECT
            SUM(CASE WHEN o.ins_state = 0 THEN 1 ELSE 0 END) AS waitInspection,
            SUM(CASE WHEN o.ins_state = 1 THEN 1 ELSE 0 END) AS inspecting,
            SUM(CASE WHEN o.ins_state = 3 THEN 1 ELSE 0 END) AS waitAudit,
            SUM(CASE WHEN o.ins_state = 5 THEN 1 ELSE 0 END) AS finished
        FROM ins_sample s
        LEFT JOIN ins_order o ON s.ins_order_id = o.id
        WHERE 1=1
        <if test="dto.custom != null and dto.custom != ''">
            AND o.custom LIKE CONCAT('%', #{dto.custom}, '%')
        </if>
        <if test="dto.startTime != null and dto.startTime != ''">
            AND s.create_time >= #{dto.startTime}
        </if>
        <if test="dto.endTime != null and dto.endTime != ''">
            AND s.create_time &lt;= #{dto.endTime}
        </if>
    </select>
    <!-- èŽ·å–å›¾è¡¨æ•°æ® -->
    <select id="getChartData" resultType="java.util.Map">
        SELECT
            DATE_FORMAT(s.create_time, '%Y-%m-%d') AS date,
            COUNT(*) AS totalCount,
            SUM(CASE WHEN o.ins_state = 5 THEN 1 ELSE 0 END) AS finishedCount
        FROM ins_sample s
        LEFT JOIN ins_order o ON s.ins_order_id = o.id
        WHERE 1=1
        <if test="dto.custom != null and dto.custom != ''">
            AND o.custom LIKE CONCAT('%', #{dto.custom}, '%')
        </if>
        <if test="dto.startTime != null and dto.startTime != ''">
            AND s.create_time >= #{dto.startTime}
        </if>
        <if test="dto.endTime != null and dto.endTime != ''">
            AND s.create_time &lt;= #{dto.endTime}
        </if>
        GROUP BY DATE_FORMAT(s.create_time, '%Y-%m-%d')
        ORDER BY date ASC
    </select>
</mapper>
report-server/src/main/resources/mapper/SampleRecordMapper.xml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,67 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ruoyi.report.mapper.SampleRecordMapper">
    <!-- åˆ†é¡µæŸ¥è¯¢é¢†æ ·è®°å½• -->
    <select id="pageSampleRecord" resultType="com.ruoyi.report.vo.SampleRecordVo">
        SELECT
            h.id AS id,
            s.id AS sampleId,
            s.sample_code AS sampleCode,
            s.sample_name AS sampleName,
            o.custom AS custom,
            h.operate_type AS operateType,
            u.name AS operateUser,
            h.operate_time AS operateTime,
            h.from_cell AS fromCell,
            h.to_cell AS toCell,
            h.remark AS remark
        FROM warehouse_history h
        LEFT JOIN ins_sample s ON h.sample_id = s.id
        LEFT JOIN ins_order o ON s.ins_order_id = o.id
        LEFT JOIN user u ON h.operate_user_id = u.id
        WHERE 1=1
        <if test="dto.sampleCode != null and dto.sampleCode != ''">
            AND s.sample_code LIKE CONCAT('%', #{dto.sampleCode}, '%')
        </if>
        <if test="dto.sampleName != null and dto.sampleName != ''">
            AND s.sample_name LIKE CONCAT('%', #{dto.sampleName}, '%')
        </if>
        <if test="dto.custom != null and dto.custom != ''">
            AND o.custom LIKE CONCAT('%', #{dto.custom}, '%')
        </if>
        <if test="dto.receiveUser != null and dto.receiveUser != ''">
            AND u.name LIKE CONCAT('%', #{dto.receiveUser}, '%')
        </if>
        <if test="dto.startTime != null and dto.startTime != ''">
            AND h.operate_time >= #{dto.startTime}
        </if>
        <if test="dto.endTime != null and dto.endTime != ''">
            AND h.operate_time &lt;= #{dto.endTime}
        </if>
        ORDER BY h.operate_time DESC
    </select>
    <!-- æŸ¥è¯¢æ ·å“æµè½¬è®°å½• -->
    <select id="getFlowRecord" resultType="com.ruoyi.report.vo.SampleRecordVo">
        SELECT
            h.id AS id,
            s.id AS sampleId,
            s.sample_code AS sampleCode,
            s.sample_name AS sampleName,
            o.custom AS custom,
            h.operate_type AS operateType,
            u.name AS operateUser,
            h.operate_time AS operateTime,
            h.from_cell AS fromCell,
            h.to_cell AS toCell,
            h.remark AS remark
        FROM warehouse_history h
        LEFT JOIN ins_sample s ON h.sample_id = s.id
        LEFT JOIN ins_order o ON s.ins_order_id = o.id
        LEFT JOIN user u ON h.operate_user_id = u.id
        WHERE s.id = #{sampleId}
        ORDER BY h.operate_time ASC
    </select>
</mapper>
report-server/src/main/resources/mapper/SpcChartMapper.xml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,57 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ruoyi.report.mapper.SpcChartMapper">
    <!-- æŸ¥è¯¢æ£€æµ‹é¡¹æ•°æ® -->
    <select id="getItemData" resultType="java.util.Map">
        SELECT
            s.sample_code AS sampleCode,
            s.sample AS sampleName,
            p.inspection_item AS itemName,
            p.last_value AS lastValue,
            o.ins_time AS insTime
        FROM ins_product p
        LEFT JOIN ins_sample s ON p.ins_sample_id = s.id
        LEFT JOIN ins_order o ON s.ins_order_id = o.id
        WHERE p.ins_result IS NOT NULL AND p.last_value IS NOT NULL
        <if test="dto.itemName != null and dto.itemName != ''">
            AND p.inspection_item = #{dto.itemName}
        </if>
        <if test="dto.sampleName != null and dto.sampleName != ''">
            AND s.sample LIKE CONCAT('%', #{dto.sampleName}, '%')
        </if>
        <if test="dto.startDate != null and dto.startDate != ''">
            AND o.ins_time >= #{dto.startDate}
        </if>
        <if test="dto.endDate != null and dto.endDate != ''">
            AND o.ins_time &lt;= #{dto.endDate}
        </if>
        ORDER BY o.ins_time ASC
    </select>
    <!-- æŸ¥è¯¢å¯é€‰æ£€æµ‹é¡¹ -->
    <select id="getItemNames" resultType="java.lang.String">
        SELECT DISTINCT p.inspection_item
        FROM ins_product p
        LEFT JOIN ins_sample s ON p.ins_sample_id = s.id
        WHERE p.ins_result IS NOT NULL AND p.last_value IS NOT NULL
        <if test="dto.sampleName != null and dto.sampleName != ''">
            AND s.sample LIKE CONCAT('%', #{dto.sampleName}, '%')
        </if>
        ORDER BY p.inspection_item ASC
    </select>
    <!-- æŸ¥è¯¢å¯é€‰æ ·å“åç§°åˆ—表 -->
    <select id="getSampleNames" resultType="java.lang.String">
        SELECT DISTINCT s.sample
        FROM ins_product p
        LEFT JOIN ins_sample s ON p.ins_sample_id = s.id
        LEFT JOIN ins_order o ON s.ins_order_id = o.id
        WHERE p.ins_result IS NOT NULL AND p.last_value IS NOT NULL
        <if test="dto.itemName != null and dto.itemName != ''">
            AND p.inspection_item = #{dto.itemName}
        </if>
        ORDER BY s.sample ASC
    </select>
</mapper>
report-server/src/main/resources/mapper/TestItemDataMapper.xml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,132 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ruoyi.report.mapper.TestItemDataMapper">
    <!-- åˆ†é¡µæŸ¥è¯¢æ£€æµ‹é¡¹ç›®æ•°æ® -->
    <select id="pageTestItemData" resultType="com.ruoyi.report.vo.TestItemDataVo">
        SELECT
            p.id AS productId,
            s.id AS sampleId,
            s.sample_code AS sampleCode,
            s.sample AS sampleName,
            o.production AS productionOrder,
            o.entrust_code AS batchNo,
            p.inspection_item AS itemName,
            p.last_value AS lastValue,
            p.ask AS standardValue,
            p.ins_result AS insResult,
            p.unit AS unit,
            u.name AS insUser,
            o.ins_time AS insTime,
            r.code AS reportCode
        FROM ins_product p
        LEFT JOIN ins_sample s ON p.ins_sample_id = s.id
        LEFT JOIN ins_order o ON s.ins_order_id = o.id
        LEFT JOIN ins_report r ON o.id = r.ins_order_id
        LEFT JOIN ins_product_user pu ON p.id = pu.ins_product_id
        LEFT JOIN user u ON pu.create_user = u.id
        WHERE 1=1
        <if test="dto.productionOrder != null and dto.productionOrder != ''">
            AND o.production LIKE CONCAT('%', #{dto.productionOrder}, '%')
        </if>
        <if test="dto.batchNo != null and dto.batchNo != ''">
            AND o.entrust_code LIKE CONCAT('%', #{dto.batchNo}, '%')
        </if>
        <if test="dto.sampleCode != null and dto.sampleCode != ''">
            AND s.sample_code LIKE CONCAT('%', #{dto.sampleCode}, '%')
        </if>
        <if test="dto.sampleName != null and dto.sampleName != ''">
            AND s.sample LIKE CONCAT('%', #{dto.sampleName}, '%')
        </if>
        <if test="dto.itemName != null and dto.itemName != ''">
            AND p.inspection_item LIKE CONCAT('%', #{dto.itemName}, '%')
        </if>
        <if test="dto.insState != null">
            AND o.ins_state = #{dto.insState}
        </if>
        <if test="dto.startTime != null and dto.startTime != ''">
            AND o.ins_time >= #{dto.startTime}
        </if>
        <if test="dto.endTime != null and dto.endTime != ''">
            AND o.ins_time &lt;= #{dto.endTime}
        </if>
        ORDER BY o.ins_time DESC
    </select>
    <!-- æŸ¥è¯¢æ£€æµ‹é¡¹ç›®è¯¦æƒ… -->
    <select id="getDetail" resultType="com.ruoyi.report.vo.TestItemDataVo">
        SELECT
            p.id AS productId,
            s.id AS sampleId,
            s.sample_code AS sampleCode,
            s.sample AS sampleName,
            o.production AS productionOrder,
            o.entrust_code AS batchNo,
            p.inspection_item AS itemName,
            p.last_value AS lastValue,
            p.ask AS standardValue,
            p.ins_result AS insResult,
            p.unit AS unit,
            u.name AS insUser,
            o.ins_time AS insTime,
            r.code AS reportCode
        FROM ins_product p
        LEFT JOIN ins_sample s ON p.ins_sample_id = s.id
        LEFT JOIN ins_order o ON s.ins_order_id = o.id
        LEFT JOIN ins_report r ON o.id = r.ins_order_id
        LEFT JOIN ins_product_user pu ON p.id = pu.ins_product_id
        LEFT JOIN user u ON pu.create_user = u.id
        WHERE s.id = #{sampleId}
        ORDER BY p.inspection_item ASC
    </select>
    <!-- æŸ¥è¯¢æ£€æµ‹é¡¹åç§°åˆ—表 -->
    <select id="getItemNames" resultType="java.lang.String">
        SELECT DISTINCT p.inspection_item
        FROM ins_product p
        LEFT JOIN ins_sample s ON p.ins_sample_id = s.id
        LEFT JOIN ins_order o ON s.ins_order_id = o.id
        WHERE 1=1
        <if test="dto.sampleName != null and dto.sampleName != ''">
            AND s.sample LIKE CONCAT('%', #{dto.sampleName}, '%')
        </if>
        <if test="dto.startTime != null and dto.startTime != ''">
            AND o.ins_time >= #{dto.startTime}
        </if>
        <if test="dto.endTime != null and dto.endTime != ''">
            AND o.ins_time &lt;= #{dto.endTime}
        </if>
        ORDER BY p.inspection_item ASC
    </select>
    <!-- æ ¹æ®æ ·å“ID列表查询检测数据 -->
    <select id="listBySampleIds" resultType="com.ruoyi.report.vo.TestItemDataVo">
        SELECT
            p.id AS productId,
            s.id AS sampleId,
            s.sample_code AS sampleCode,
            s.sample AS sampleName,
            o.production AS productionOrder,
            o.entrust_code AS batchNo,
            p.inspection_item AS itemName,
            p.last_value AS lastValue,
            p.ask AS standardValue,
            p.ins_result AS insResult,
            p.unit AS unit,
            u.name AS insUser,
            o.ins_time AS insTime,
            r.code AS reportCode
        FROM ins_product p
        LEFT JOIN ins_sample s ON p.ins_sample_id = s.id
        LEFT JOIN ins_order o ON s.ins_order_id = o.id
        LEFT JOIN ins_report r ON o.id = r.ins_order_id
        LEFT JOIN ins_product_user pu ON p.id = pu.ins_product_id
        LEFT JOIN user u ON pu.create_user = u.id
        WHERE s.id IN
        <foreach collection="sampleIds" item="id" open="(" separator="," close=")">
            #{id}
        </foreach>
        ORDER BY s.sample_code ASC, p.inspection_item ASC
    </select>
</mapper>
report-server/src/main/resources/mapper/WorkStatisticsMapper.xml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,87 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ruoyi.report.mapper.WorkStatisticsMapper">
    <!-- æŒ‰äººå‘˜ç»Ÿè®¡ -->
    <select id="getByUser" resultType="com.ruoyi.report.vo.WorkStatisticsVo">
        SELECT
            u.id AS userId,
            u.name AS userName,
            d.dept_name AS deptName,
            COUNT(DISTINCT s.id) AS sampleCount,
            COUNT(p.id) AS itemCount,
            SUM(CASE WHEN o.ins_time IS NOT NULL AND o.ins_time &lt;= o.appointed THEN 1 ELSE 0 END) AS timelyCount,
            SUM(CASE WHEN o.ins_time IS NOT NULL AND o.ins_time > o.appointed THEN 1 ELSE 0 END) AS overdueCount
        FROM ins_product p
        LEFT JOIN ins_sample s ON p.ins_sample_id = s.id
        LEFT JOIN ins_order o ON s.ins_order_id = o.id
        LEFT JOIN ins_product_user pu ON p.id = pu.ins_product_id
        LEFT JOIN user u ON pu.create_user = u.id
        LEFT JOIN sys_dept d ON u.dept_id = d.dept_id
        WHERE p.ins_result IS NOT NULL
        <if test="dto.startTime != null and dto.startTime != ''">
            AND o.ins_time >= #{dto.startTime}
        </if>
        <if test="dto.endTime != null and dto.endTime != ''">
            AND o.ins_time &lt;= #{dto.endTime}
        </if>
        <if test="dto.userId != null">
            AND pu.create_user = #{dto.userId}
        </if>
        <if test="dto.deptId != null">
            AND u.dept_id = #{dto.deptId}
        </if>
        GROUP BY u.id
        ORDER BY sampleCount DESC
    </select>
    <!-- åŠæ—¶çŽ‡ç»Ÿè®¡ -->
    <select id="getTimelyRate" resultType="java.util.Map">
        SELECT
            u.name AS userName,
            COUNT(*) AS totalCount,
            SUM(CASE WHEN o.ins_time IS NOT NULL AND o.ins_time &lt;= o.appointed THEN 1 ELSE 0 END) AS timelyCount,
            ROUND(SUM(CASE WHEN o.ins_time IS NOT NULL AND o.ins_time &lt;= o.appointed THEN 1 ELSE 0 END) * 100.0 / COUNT(*), 2) AS timelyRate
        FROM ins_order o
        LEFT JOIN ins_sample s ON o.id = s.ins_order_id
        LEFT JOIN ins_product p ON s.id = p.ins_sample_id
        LEFT JOIN user u ON o.prepare_user_id = u.id
        WHERE o.ins_state = 5
        <if test="dto.startTime != null and dto.startTime != ''">
            AND o.ins_time >= #{dto.startTime}
        </if>
        <if test="dto.endTime != null and dto.endTime != ''">
            AND o.ins_time &lt;= #{dto.endTime}
        </if>
        <if test="dto.deptId != null">
            AND u.dept_id = #{dto.deptId}
        </if>
        GROUP BY u.id
        ORDER BY timelyRate DESC
    </select>
    <!-- å·¥ä½œè¶‹åŠ¿å›¾ -->
    <select id="getTrend" resultType="java.util.Map">
        SELECT
            DATE_FORMAT(o.ins_time, '%Y-%m-%d') AS date,
            COUNT(DISTINCT s.id) AS sampleCount,
            COUNT(p.id) AS itemCount
        FROM ins_product p
        LEFT JOIN ins_sample s ON p.ins_sample_id = s.id
        LEFT JOIN ins_order o ON s.ins_order_id = o.id
        LEFT JOIN ins_product_user pu ON p.id = pu.ins_product_id
        WHERE p.ins_result IS NOT NULL
        <if test="dto.startTime != null and dto.startTime != ''">
            AND o.ins_time >= #{dto.startTime}
        </if>
        <if test="dto.endTime != null and dto.endTime != ''">
            AND o.ins_time &lt;= #{dto.endTime}
        </if>
        <if test="dto.userId != null">
            AND pu.create_user = #{dto.userId}
        </if>
        GROUP BY DATE_FORMAT(o.ins_time, '%Y-%m-%d')
        ORDER BY date ASC
    </select>
</mapper>
ruoyi-admin/pom.xml
@@ -103,6 +103,12 @@
            <artifactId>cnas-personnel</artifactId>
        </dependency>
        <!--报表图表模块-->
        <dependency>
            <groupId>com.ruoyi</groupId>
            <artifactId>report-server</artifactId>
        </dependency>
    </dependencies>
ruoyi-admin/src/main/resources/application-druid.yml
@@ -65,13 +65,13 @@
  # redis é…ç½®
  redis:
    # åœ°å€
    host: localhost
    host: 47.114.74.44
    # ç«¯å£ï¼Œé»˜è®¤ä¸º6379
    port: 6379
    port: 6399
    # æ•°æ®åº“索引
    database: 0
    database: 9
    #    # å¯†ç 
    password: 123456
    password:
    # è¿žæŽ¥è¶…æ—¶æ—¶é—´
    timeout: 10s
    lettuce:
ruoyi-admin/src/main/resources/report_chart_sql.sql
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,177 @@
-- =====================================================
-- æŠ¥è¡¨å›¾è¡¨ç®¡ç†æ¨¡å—数据库脚本
-- æ‰§è¡Œå‰è¯·å¤‡ä»½æ•°æ®åº“
-- åˆ›å»ºæ—¶é—´: 2026-06-04
-- =====================================================
-- =============================================
-- 1. è¯­éŸ³æ’­æŠ¥é˜Ÿåˆ—表 (voice_queue) - æ–°å¢ž
-- =============================================
DROP TABLE IF EXISTS `voice_queue`;
CREATE TABLE `voice_queue` (
  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID',
  `event_type` varchar(50) NOT NULL COMMENT '事件类型(sample_receive/task_assign/report_submit/emergency)',
  `event_name` varchar(100) NOT NULL COMMENT '事件名称',
  `details` varchar(500) DEFAULT '' COMMENT '事件详情',
  `voice_text` varchar(500) NOT NULL COMMENT '语音播报文本',
  `priority` int DEFAULT 0 COMMENT '优先级(0普通/1重要/2紧急)',
  `status` tinyint DEFAULT 0 COMMENT '状态(0待播报/1已播报/2已取消)',
  `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_time` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  PRIMARY KEY (`id`),
  KEY `idx_status_priority` (`status`, `priority`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='语音播报队列表';
-- =============================================
-- 2. æŠ¥è¡¨é…ç½®è¡¨
-- =============================================
DROP TABLE IF EXISTS `report_config`;
CREATE TABLE `report_config` (
  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID',
  `report_name` varchar(100) NOT NULL COMMENT '报表名称',
  `report_code` varchar(50) NOT NULL COMMENT '报表编码',
  `report_type` varchar(20) NOT NULL COMMENT '报表类型(sample_progress/test_item/sample_record/device_record/dashboard)',
  `query_config` text COMMENT '查询条件配置JSON',
  `column_config` text COMMENT '列配置JSON',
  `chart_config` text COMMENT '图表配置JSON',
  `status` tinyint DEFAULT 1 COMMENT '状态(1启用/0停用)',
  `create_by` varchar(64) DEFAULT '' COMMENT '创建者',
  `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_by` varchar(64) DEFAULT '' COMMENT '更新者',
  `update_time` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  `remark` varchar(500) DEFAULT '' COMMENT '备注',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_report_code` (`report_code`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='报表配置表';
-- =============================================
-- 3. å›¾è¡¨é…ç½®è¡¨
-- =============================================
DROP TABLE IF EXISTS `chart_config`;
CREATE TABLE `chart_config` (
  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID',
  `chart_name` varchar(100) NOT NULL COMMENT '图表名称',
  `chart_code` varchar(50) NOT NULL COMMENT '图表编码',
  `chart_type` varchar(20) NOT NULL COMMENT '图表类型(bar/line/pie/radar/spc/normal)',
  `data_source` varchar(100) NOT NULL COMMENT '数据源SQL或接口标识',
  `x_axis_field` varchar(50) COMMENT 'X轴字段',
  `y_axis_field` varchar(100) COMMENT 'Y轴字段(JSON数组)',
  `query_params` text COMMENT '查询参数配置JSON',
  `chart_options` text COMMENT 'ECharts配置JSON',
  `status` tinyint DEFAULT 1 COMMENT '状态(1启用/0停用)',
  `create_by` varchar(64) DEFAULT '' COMMENT '创建者',
  `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_by` varchar(64) DEFAULT '' COMMENT '更新者',
  `update_time` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  `remark` varchar(500) DEFAULT '' COMMENT '备注',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_chart_code` (`chart_code`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='图表配置表';
-- =============================================
-- 4. çœ‹æ¿é…ç½®è¡¨
-- =============================================
DROP TABLE IF EXISTS `dashboard_config`;
CREATE TABLE `dashboard_config` (
  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID',
  `dashboard_name` varchar(100) NOT NULL COMMENT '看板名称',
  `dashboard_code` varchar(50) NOT NULL COMMENT '看板编码',
  `layout_config` text COMMENT '布局配置JSON',
  `components` text COMMENT '组件配置JSON',
  `voice_config` text COMMENT '语音播报配置JSON',
  `refresh_interval` int DEFAULT 30 COMMENT '刷新间隔(秒)',
  `status` tinyint DEFAULT 1 COMMENT '状态(1启用/0停用)',
  `create_by` varchar(64) DEFAULT '' COMMENT '创建者',
  `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_by` varchar(64) DEFAULT '' COMMENT '更新者',
  `update_time` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  `remark` varchar(500) DEFAULT '' COMMENT '备注',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_dashboard_code` (`dashboard_code`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='看板配置表';
-- =============================================
-- 5. èœå•权限配置
-- =============================================
-- æŠ¥è¡¨å›¾è¡¨ç®¡ç†ï¼ˆä¸€çº§ç›®å½•)- æŽ’在最后,order_num = 21
INSERT INTO `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `route_name`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`, `is_rersonal_button`) VALUES
(3000, '报表图表管理', 0, 21, 'reportChart', '', NULL, '', 1, 0, 'M', '0', '0', '', 'chart', 'admin', NOW(), '', NULL, '报表图表管理目录', 0),
-- æ•°å­—化语音看板(二级目录)
(3001, '数字化语音看板', 3000, 1, 'dashboard', '', NULL, '', 1, 0, 'M', '0', '0', '', 'monitor', 'admin', NOW(), '', NULL, '数字化语音看板目录', 0),
-- è¯•验大厅
(3002, '试验大厅', 3001, 1, 'testHall', 'report/dashboard/index', NULL, '', 1, 0, 'C', '0', '0', 'report:dashboard:list', 'monitor', 'admin', NOW(), '', NULL, '试验大厅菜单', 0),
-- æŠ¥è¡¨ç®¡ç†ï¼ˆäºŒçº§ç›®å½•)
(3010, '报表管理', 3000, 2, 'report', '', NULL, '', 1, 0, 'M', '0', '0', '', 'form', 'admin', NOW(), '', NULL, '报表管理目录', 0),
-- æ ·å“è¿›åº¦æŠ¥è¡¨
(3011, '样品进度报表', 3010, 1, 'sampleProgress', 'report/sampleProgress/index', NULL, '', 1, 0, 'C', '0', '0', 'report:sampleProgress:list', 'table', 'admin', NOW(), '', NULL, '样品进度报表菜单', 0),
-- æ£€æµ‹é¡¹ç›®æ•°æ®
(3012, '检测项目数据', 3010, 2, 'testItemData', 'report/testItemData/index', NULL, '', 1, 0, 'C', '0', '0', 'report:testItemData:list', 'table', 'admin', NOW(), '', NULL, '检测项目数据菜单', 0),
-- æ ·å“é¢†æ ·è®°å½•
(3013, '样品领样记录', 3010, 3, 'sampleRecord', 'report/sampleRecord/index', NULL, '', 1, 0, 'C', '0', '0', 'report:sampleRecord:list', 'table', 'admin', NOW(), '', NULL, '样品领样记录菜单', 0),
-- è®¾å¤‡ä½¿ç”¨è®°å½•
(3014, '设备使用记录', 3010, 4, 'deviceRecord', 'report/deviceRecord/index', NULL, '', 1, 0, 'C', '0', '0', 'report:deviceRecord:list', 'table', 'admin', NOW(), '', NULL, '设备使用记录菜单', 0),
-- æ™ºèƒ½å›¾è¡¨ï¼ˆäºŒçº§ç›®å½•)
(3020, '智能图表', 3000, 3, 'chart', '', NULL, '', 1, 0, 'M', '0', '0', '', 'chart', 'admin', NOW(), '', NULL, '智能图表目录', 0),
-- å·¥ä½œç»Ÿè®¡
(3021, '工作统计', 3020, 1, 'workStatistics', 'report/workStatistics/index', NULL, '', 1, 0, 'C', '0', '0', 'chart:workStatistics:list', 'peoples', 'admin', NOW(), '', NULL, '工作统计菜单', 0),
-- åˆæ ¼çŽ‡ç»Ÿè®¡
(3022, '合格率统计', 3020, 2, 'passRate', 'report/passRate/index', NULL, '', 1, 0, 'C', '0', '0', 'chart:passRate:list', 'chart', 'admin', NOW(), '', NULL, '合格率统计菜单', 0),
-- SPC控制图
(3023, 'SPC控制图', 3020, 3, 'spcChart', 'report/spcChart/index', NULL, '', 1, 0, 'C', '0', '0', 'chart:spcChart:list', 'chart', 'admin', NOW(), '', NULL, 'SPC控制图菜单', 0),
-- æ­£æ€åˆ†å¸ƒå›¾
(3024, '正态分布图', 3020, 4, 'normalDistribution', 'report/normalDistribution/index', NULL, '', 1, 0, 'C', '0', '0', 'chart:normalDistribution:list', 'chart', 'admin', NOW(), '', NULL, '正态分布图菜单', 0);
-- =============================================
-- 6. åˆå§‹åŒ–看板配置数据
-- =============================================
INSERT INTO `dashboard_config` (`dashboard_name`, `dashboard_code`, `layout_config`, `components`, `voice_config`, `refresh_interval`, `status`, `create_by`) VALUES
('试验大厅看板', 'test_hall',
'[{"i":"history","x":0,"y":0,"w":8,"h":4},{"i":"future","x":8,"y":0,"w":4,"h":4},{"i":"ranking","x":0,"y":4,"w":6,"h":3},{"i":"status","x":6,"y":4,"w":6,"h":3},{"i":"result","x":0,"y":7,"w":12,"h":3}]',
'[{"id":"history","type":"calendar","title":"历史15天检测任务","api":"/report/dashboard/history15Days"},{"id":"future","type":"calendar","title":"未来15天检测任务","api":"/report/dashboard/future15Days"},{"id":"ranking","type":"ranking","title":"提交排行","api":"/report/dashboard/ranking"},{"id":"status","type":"stat","title":"待处理统计","api":"/report/dashboard/overview"},{"id":"result","type":"chart","title":"检验结果统计","api":"/report/dashboard/insResult"}]',
'{"enabled":true,"events":["sample_receive","task_assign","report_submit","emergency"],"template":"紧急通知:{eventName},{details}"}',
30, 1, 'admin');
-- =============================================
-- 7. åˆå§‹åŒ–报表配置数据
-- =============================================
INSERT INTO `report_config` (`report_name`, `report_code`, `report_type`, `query_config`, `status`, `create_by`) VALUES
('样品进度报表', 'sample_progress', 'sample_progress', '[{"field":"entrustCode","label":"委托编号","type":"input"},{"field":"sampleCode","label":"样品编号","type":"input"},{"field":"sampleName","label":"样品名称","type":"input"},{"field":"insState","label":"检测状态","type":"select","options":[{"value":0,"label":"待检"},{"value":1,"label":"检验中"},{"value":5,"label":"已完成"}]}]', 1, 'admin'),
('检测项目数据', 'test_item_data', 'test_item', '[{"field":"productionOrder","label":"生产订单","type":"input"},{"field":"batchNo","label":"批次号","type":"input"},{"field":"sampleCode","label":"样品编号","type":"input"},{"field":"itemName","label":"检测项目","type":"input"}]', 1, 'admin'),
('样品领样记录', 'sample_record', 'sample_record', '[{"field":"sampleCode","label":"样品编号","type":"input"},{"field":"operateUser","label":"操作人","type":"input"},{"field":"startTime","label":"开始时间","type":"date"},{"field":"endTime","label":"结束时间","type":"date"}]', 1, 'admin'),
('设备使用记录', 'device_record', 'device_record', '[{"field":"deviceCode","label":"设备编号","type":"input"},{"field":"deviceName","label":"设备名称","type":"input"},{"field":"useUser","label":"使用人","type":"input"}]', 1, 'admin');
-- =============================================
-- 8. åˆå§‹åŒ–图表配置数据
-- =============================================
INSERT INTO `chart_config` (`chart_name`, `chart_code`, `chart_type`, `data_source`, `x_axis_field`, `y_axis_field`, `status`, `create_by`) VALUES
('工作统计图', 'work_statistics', 'bar', '/chart/workStatistics/byUser', 'userName', '[{"field":"sampleCount","name":"样品数量"},{"field":"itemCount","name":"项目数量"}]', 1, 'admin'),
('及时率统计', 'timely_rate', 'line', '/chart/workStatistics/timelyRate', 'userName', '[{"field":"timelyRate","name":"及时率(%)"}]', 1, 'admin'),
('原材料合格率', 'raw_material_pass_rate', 'bar', '/chart/passRate/rawMaterial', 'sampleName', '[{"field":"passRate","name":"合格率(%)"}]', 1, 'admin'),
('帕累托图', 'pareto', 'bar', '/chart/passRate/pareto', 'itemName', '[{"field":"unqualifiedCount","name":"不合格数"},{"field":"cumulativePercent","name":"累计百分比"}]', 1, 'admin'),
('工序合格率', 'process_pass_rate', 'pie', '/chart/passRate/process', 'processName', '[{"field":"passRate","name":"合格率(%)"}]', 1, 'admin'),
('SPC控制图', 'spc_chart', 'line', '/chart/spc/analyze', 'subgroup', '[{"field":"xBar","name":"X-Bar"},{"field":"ucl","name":"UCL"},{"field":"lcl","name":"LCL"}]', 1, 'admin'),
('正态分布图', 'normal_distribution', 'line', '/chart/normalDistribution/analyze', 'value', '[{"field":"frequency","name":"频率"},{"field":"normalCurve","name":"正态曲线"}]', 1, 'admin');
-- =============================================
-- 9. åˆå§‹åŒ–语音播报测试数据
-- =============================================
INSERT INTO `voice_queue` (`event_type`, `event_name`, `details`, `voice_text`, `priority`, `status`) VALUES
('sample_receive', '样品接收', '样品A001已到达实验室', '样品A001已到达实验室,请及时领取', 0, 0),
('task_assign', '任务分配', '检测任务已分配给张三', '检测任务已分配给张三,请尽快开始检测', 1, 0),
('emergency', '紧急通知', '设备故障需要维修', '紧急通知:关键检测设备出现故障,请立即联系维修人员', 2, 0);
-- =====================================================
-- æ‰§è¡Œå®Œæˆ
-- =====================================================