车车 4 месяцев назад
Родитель
Сommit
df32ebf39d
17 измененных файлов с 1418 добавлено и 0 удалено
  1. 151 0
      yudao-module-iscs/src/main/java/cn/iocoder/yudao/module/iscs/controller/admin/statistics/StatisticsApiController.java
  2. 38 0
      yudao-module-iscs/src/main/java/cn/iocoder/yudao/module/iscs/controller/admin/statistics/vo/CabinetStatisticsVO.java
  3. 32 0
      yudao-module-iscs/src/main/java/cn/iocoder/yudao/module/iscs/controller/admin/statistics/vo/DayLoanStatisticsVO.java
  4. 26 0
      yudao-module-iscs/src/main/java/cn/iocoder/yudao/module/iscs/controller/admin/statistics/vo/HomePageLoanVO.java
  5. 37 0
      yudao-module-iscs/src/main/java/cn/iocoder/yudao/module/iscs/controller/admin/statistics/vo/HomePageVO.java
  6. 29 0
      yudao-module-iscs/src/main/java/cn/iocoder/yudao/module/iscs/controller/admin/statistics/vo/InventoryTypeVO.java
  7. 30 0
      yudao-module-iscs/src/main/java/cn/iocoder/yudao/module/iscs/controller/admin/statistics/vo/InventoryVO.java
  8. 35 0
      yudao-module-iscs/src/main/java/cn/iocoder/yudao/module/iscs/controller/admin/statistics/vo/MaterialsChangeStatisticsVO.java
  9. 38 0
      yudao-module-iscs/src/main/java/cn/iocoder/yudao/module/iscs/controller/admin/statistics/vo/MaterialsLoanStatisticsVO.java
  10. 38 0
      yudao-module-iscs/src/main/java/cn/iocoder/yudao/module/iscs/controller/admin/statistics/vo/MaterialsStatusStatisticsVO.java
  11. 35 0
      yudao-module-iscs/src/main/java/cn/iocoder/yudao/module/iscs/controller/admin/statistics/vo/MaterialsTypeVO.java
  12. 44 0
      yudao-module-iscs/src/main/java/cn/iocoder/yudao/module/iscs/controller/admin/statistics/vo/OngoingJobVO.java
  13. 35 0
      yudao-module-iscs/src/main/java/cn/iocoder/yudao/module/iscs/controller/admin/statistics/vo/UserLoanStatisticsVO.java
  14. 35 0
      yudao-module-iscs/src/main/java/cn/iocoder/yudao/module/iscs/dal/mysql/statistics/StatisticsMapper.java
  15. 42 0
      yudao-module-iscs/src/main/java/cn/iocoder/yudao/module/iscs/service/statistics/StatisticsApiService.java
  16. 488 0
      yudao-module-iscs/src/main/java/cn/iocoder/yudao/module/iscs/service/statistics/StatisticsApiServiceImpl.java
  17. 285 0
      yudao-module-iscs/src/main/resources/mapper/StatisticsMapper.xml

+ 151 - 0
yudao-module-iscs/src/main/java/cn/iocoder/yudao/module/iscs/controller/admin/statistics/StatisticsApiController.java

@@ -0,0 +1,151 @@
+package cn.iocoder.yudao.module.iscs.controller.admin.statistics;
+
+import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog;
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.module.iscs.controller.admin.statistics.vo.*;
+import cn.iocoder.yudao.module.iscs.service.statistics.StatisticsApiService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.Parameters;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import lombok.extern.java.Log;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.List;
+
+import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT;
+
+
+/**
+ * 硬件调用接口
+ *
+ * @author cgj
+ * @date 2024-10-16
+ */
+@Tag(name = "统计接口")
+@RestController
+@RequestMapping("/iscs/statistics-api")
+public class StatisticsApiController {
+    @Autowired
+    private StatisticsApiService statisticsApiService;
+
+    @Operation(summary = "物资柜使⽤情况统计")
+    @Parameters({
+            @Parameter(name = "startTime", description = "开始时间"),
+            @Parameter(name = "endTime", description = "结束时间")
+    })
+    @GetMapping("/getCabinetStatistics")
+    public CommonResult<List<CabinetStatisticsVO>> getCabinetStatistics(String startTime, String endTime) {
+        List<CabinetStatisticsVO> list = statisticsApiService.getCabinetStatistics(startTime, endTime);
+        return CommonResult.success(list);
+    }
+
+    @Operation(summary = "物资当前状态统计")
+    @Parameters({
+            @Parameter(name = "startTime", description = "开始时间"),
+            @Parameter(name = "endTime", description = "结束时间")
+    })
+    @GetMapping("/getMaterialsStatusStatistics")
+    public CommonResult<List<MaterialsStatusStatisticsVO>> getMaterialsStatusStatistics(String startTime, String endTime) {
+        List<MaterialsStatusStatisticsVO> list = statisticsApiService.getMaterialsStatusStatistics(startTime, endTime);
+        return CommonResult.success(list);
+    }
+
+    @Operation(summary = "物资使⽤情况统计")
+    @Parameters({
+            @Parameter(name = "startTime", description = "开始时间"),
+            @Parameter(name = "endTime", description = "结束时间")
+    })
+    @GetMapping("/getMaterialsLoanStatistics")
+    public CommonResult<List<MaterialsLoanStatisticsVO>> getMaterialsLoanStatistics(String startTime, String endTime) {
+        List<MaterialsLoanStatisticsVO> list = statisticsApiService.getMaterialsLoanStatistics(startTime, endTime);
+        return CommonResult.success(list);
+    }
+
+    @Operation(summary = "物资更换情况统计⽤情况统计")
+    @Parameters({
+            @Parameter(name = "startTime", description = "开始时间"),
+            @Parameter(name = "endTime", description = "结束时间")
+    })
+    @GetMapping("/getMaterialsChangeStatistics")
+    public CommonResult<List<MaterialsChangeStatisticsVO>> getMaterialsChangeStatistics(String startTime, String endTime) {
+        List<MaterialsChangeStatisticsVO> list = statisticsApiService.getMaterialsChangeStatistics(startTime, endTime);
+        return CommonResult.success(list);
+    }
+
+    @Operation(summary = "⼈员借⽤情况统计⽤情况统计")
+    @Parameters({
+            @Parameter(name = "startTime", description = "开始时间"),
+            @Parameter(name = "endTime", description = "结束时间")
+    })
+    @GetMapping("/getUserLoanStatistics")
+    public CommonResult<List<UserLoanStatisticsVO>> getUserLoanStatistics(String startTime, String endTime) {
+        List<UserLoanStatisticsVO> list = statisticsApiService.getUserLoanStatistics(startTime, endTime);
+        return CommonResult.success(list);
+    }
+
+    @Operation(summary = "每⽇领取归还统计")
+    @Parameters({
+            @Parameter(name = "startTime", description = "开始时间"),
+            @Parameter(name = "endTime", description = "结束时间")
+    })
+    @GetMapping("/getDayLoanStatistics")
+    public CommonResult<List<DayLoanStatisticsVO>> getDayLoanStatistics(String startTime, String endTime) {
+        List<DayLoanStatisticsVO> list = statisticsApiService.getDayLoanStatistics(startTime, endTime);
+        return CommonResult.success(list);
+    }
+
+    @Operation(summary = "首页")
+    @Parameters({
+            @Parameter(name = "startTime", description = "开始时间"),
+            @Parameter(name = "endTime", description = "结束时间")
+    })
+    @GetMapping("/getHomePage")
+    public CommonResult<HomePageVO> getHomePage(String startTime, String endTime) {
+        HomePageVO vo = statisticsApiService.getHomePage(startTime, endTime);
+        return CommonResult.success(vo);
+    }
+
+    @Operation(summary = "物资盘点")
+    @Parameter(name = "type", description = "查询类型(0-总览 1-柜中 2-借出 3-正常 4-过期 5-损坏)")
+    @GetMapping("/getMaterialInventory")
+    public CommonResult<List<InventoryVO>> getMaterialInventory(Integer type) {
+        List<InventoryVO> vo = statisticsApiService.getMaterialInventory(type);
+        return CommonResult.success(vo);
+    }
+
+    @Operation(summary = "物资盘点-上方统计")
+    @GetMapping("/getInventorySum")
+    public CommonResult<List<InventoryTypeVO>> getInventorySum() {
+        List<InventoryTypeVO> vo = statisticsApiService.getInventorySum();
+        return CommonResult.success(vo);
+    }
+
+    @Operation(summary = "导出物资盘点")
+    @ApiAccessLog(operateType = EXPORT)
+    @PostMapping("/exportMaterialInventory")
+    public void exportMaterialInventory(HttpServletResponse response, HttpServletRequest request) {
+        statisticsApiService.exportMaterialInventory(response, request);
+    }
+
+    @Operation(summary = "导出基础数据统计")
+    @ApiAccessLog(operateType = EXPORT)
+    @PostMapping("/exportBaseData")
+    public void exportBaseData(HttpServletResponse response, HttpServletRequest request, String startTime, String endTime) {
+        statisticsApiService.exportBaseData(response, request, startTime, endTime);
+    }
+
+    @Operation(summary = "导出领取归还统计")
+    @ApiAccessLog(operateType = EXPORT)
+    @PostMapping("/exportClaimAndReturn")
+    public void exportClaimAndReturn(HttpServletResponse response, HttpServletRequest request, String startTime, String endTime) {
+        statisticsApiService.exportClaimAndReturn(response, request, startTime, endTime);
+    }
+
+}

+ 38 - 0
yudao-module-iscs/src/main/java/cn/iocoder/yudao/module/iscs/controller/admin/statistics/vo/CabinetStatisticsVO.java

@@ -0,0 +1,38 @@
+package cn.iocoder.yudao.module.iscs.controller.admin.statistics.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.io.Serializable;
+
+/**
+ * 物资柜统计
+ *
+ * @author cgj
+ * @date 2024-10-18
+ */
+@EqualsAndHashCode(callSuper = false)
+@Data
+public class CabinetStatisticsVO implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    @Schema(description = "物资柜ID")
+    private Long cabinetId;
+
+    @Schema(description = "物资柜名称")
+    private String cabinetName;
+
+    @Schema(description = "区域")
+    private String workstationName;
+
+    @Schema(description = "开关次数")
+    private Integer openCount;
+
+    @Schema(description = "超时未关次数")
+    private Integer openTimeoutCount;
+
+    @Schema(description = "物资错放次数")
+    private Integer misplaceCount;
+
+}

+ 32 - 0
yudao-module-iscs/src/main/java/cn/iocoder/yudao/module/iscs/controller/admin/statistics/vo/DayLoanStatisticsVO.java

@@ -0,0 +1,32 @@
+package cn.iocoder.yudao.module.iscs.controller.admin.statistics.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.io.Serializable;
+
+/**
+ * 物资当前状态统计
+ *
+ * @author cgj
+ * @date 2024-10-18
+ */
+@EqualsAndHashCode(callSuper = false)
+@Data
+public class DayLoanStatisticsVO implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    @Schema(description = "日期")
+    private String day;
+
+    @Schema(description = "累计借出总数")
+    private Integer allCount;
+
+    @Schema(description = "正常归还次数")
+    private Integer returnCount;
+
+    @Schema(description = "超时归还次数")
+    private Integer timeoutCount;
+
+}

+ 26 - 0
yudao-module-iscs/src/main/java/cn/iocoder/yudao/module/iscs/controller/admin/statistics/vo/HomePageLoanVO.java

@@ -0,0 +1,26 @@
+package cn.iocoder.yudao.module.iscs.controller.admin.statistics.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * 首页返回类
+ *
+ * @author cgj
+ * @date 2024-10-16
+ */
+@Data
+public class HomePageLoanVO implements Serializable {
+
+    @Schema(description = "日期")
+    private String day;
+
+    @Schema(description = "借出")
+    private Integer loanCount;
+
+    @Schema(description = "归还")
+    private Integer returnCount;
+
+}

+ 37 - 0
yudao-module-iscs/src/main/java/cn/iocoder/yudao/module/iscs/controller/admin/statistics/vo/HomePageVO.java

@@ -0,0 +1,37 @@
+package cn.iocoder.yudao.module.iscs.controller.admin.statistics.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * 首页返回类
+ *
+ * @author cgj
+ * @date 2024-10-16
+ */
+@Data
+public class HomePageVO implements Serializable {
+
+    @Schema(description = "物资总数")
+    private Integer materialsCount;
+
+    @Schema(description = "柜中物资")
+    private Integer cabinetMaterialsCount;
+
+    @Schema(description = "借出物资")
+    private Integer loanMaterialsCount;
+
+    @Schema(description = "异常数量")
+    private Integer exceptionMaterialsCount;
+
+    @Schema(description = "进行中的作业")
+    private List<OngoingJobVO> jobList;
+
+    @Schema(description = "折线数据")
+    private List<HomePageLoanVO>  loanList;
+
+
+}

+ 29 - 0
yudao-module-iscs/src/main/java/cn/iocoder/yudao/module/iscs/controller/admin/statistics/vo/InventoryTypeVO.java

@@ -0,0 +1,29 @@
+package cn.iocoder.yudao.module.iscs.controller.admin.statistics.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.io.Serializable;
+
+/**
+ * 物资柜统计
+ *
+ * @author cgj
+ * @date 2024-10-18
+ */
+@EqualsAndHashCode(callSuper = false)
+@Data
+public class InventoryTypeVO implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    @Schema(description = "值")
+    private String dictValue;
+
+    @Schema(description = "描述")
+    private String dictLabel;
+
+    @Schema(description = "总数")
+    private Integer sum;
+
+}

+ 30 - 0
yudao-module-iscs/src/main/java/cn/iocoder/yudao/module/iscs/controller/admin/statistics/vo/InventoryVO.java

@@ -0,0 +1,30 @@
+package cn.iocoder.yudao.module.iscs.controller.admin.statistics.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * 物资柜统计
+ *
+ * @author cgj
+ * @date 2024-10-18
+ */
+@EqualsAndHashCode(callSuper = false)
+@Data
+public class InventoryVO implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    @Schema(description = "物资柜ID")
+    private Long cabinetId;
+
+    @Schema(description = "物资柜名称")
+    private String cabinetName;
+
+    @Schema(description = "物资柜名称")
+    private List<MaterialsTypeVO> materialsTypeVOList;
+
+}

+ 35 - 0
yudao-module-iscs/src/main/java/cn/iocoder/yudao/module/iscs/controller/admin/statistics/vo/MaterialsChangeStatisticsVO.java

@@ -0,0 +1,35 @@
+package cn.iocoder.yudao.module.iscs.controller.admin.statistics.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.io.Serializable;
+
+/**
+ * 物资更换情况统计
+ *
+ * @author cgj
+ * @date 2024-10-18
+ */
+@EqualsAndHashCode(callSuper = false)
+@Data
+public class MaterialsChangeStatisticsVO implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    @Schema(description = "物资类型ID")
+    private Long materialsTypeId;
+
+    @Schema(description = "物资类型名称")
+    private String materialsTypeName;
+
+    @Schema(description = "正常状态下更换次数")
+    private Integer allCount;
+
+    @Schema(description = "过期更换次数")
+    private Integer expireCount;
+
+    @Schema(description = "损坏更换次数")
+    private Integer badCount;
+
+}

+ 38 - 0
yudao-module-iscs/src/main/java/cn/iocoder/yudao/module/iscs/controller/admin/statistics/vo/MaterialsLoanStatisticsVO.java

@@ -0,0 +1,38 @@
+package cn.iocoder.yudao.module.iscs.controller.admin.statistics.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.io.Serializable;
+
+/**
+ * 物资当前状态统计
+ *
+ * @author cgj
+ * @date 2024-10-18
+ */
+@EqualsAndHashCode(callSuper = false)
+@Data
+public class MaterialsLoanStatisticsVO implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    @Schema(description = "物资类型ID")
+    private Long materialsTypeId;
+
+    @Schema(description = "物资类型名称")
+    private String materialsTypeName;
+
+    @Schema(description = "累计借出总数")
+    private Integer allCount;
+
+    @Schema(description = "正常归还次数")
+    private Integer returnCount;
+
+    @Schema(description = "超时归还次数")
+    private Integer timeoutCount;
+
+    @Schema(description = "平均借出时长")
+    private Double averageTime;
+
+}

+ 38 - 0
yudao-module-iscs/src/main/java/cn/iocoder/yudao/module/iscs/controller/admin/statistics/vo/MaterialsStatusStatisticsVO.java

@@ -0,0 +1,38 @@
+package cn.iocoder.yudao.module.iscs.controller.admin.statistics.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.io.Serializable;
+
+/**
+ * 物资当前状态统计
+ *
+ * @author cgj
+ * @date 2024-10-18
+ */
+@EqualsAndHashCode(callSuper = false)
+@Data
+public class MaterialsStatusStatisticsVO implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    @Schema(description = "物资类型ID")
+    private Long materialsTypeId;
+
+    @Schema(description = "物资类型名称")
+    private String materialsTypeName;
+
+    @Schema(description = "当前总数")
+    private Integer allCount;
+
+    @Schema(description = "即将过期")
+    private Integer willExpireCount;
+
+    @Schema(description = "已过期")
+    private Integer expiredCount;
+
+    @Schema(description = "损坏数")
+    private Integer badCount;
+
+}

+ 35 - 0
yudao-module-iscs/src/main/java/cn/iocoder/yudao/module/iscs/controller/admin/statistics/vo/MaterialsTypeVO.java

@@ -0,0 +1,35 @@
+package cn.iocoder.yudao.module.iscs.controller.admin.statistics.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.io.Serializable;
+
+/**
+ * 物资柜统计
+ *
+ * @author cgj
+ * @date 2024-10-18
+ */
+@EqualsAndHashCode(callSuper = false)
+@Data
+public class MaterialsTypeVO implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    @Schema(description = "物资类型ID")
+    private Long materialsTypeId;
+
+    @Schema(description = "物资类型名称")
+    private String materialsTypeName;
+
+    @Schema(description = "物资类型图标")
+    private String materialsTypeIcon;
+
+    @Schema(description = "物资类型缩略图")
+    private String materialsTypePicture;
+
+    @Schema(description = "数量")
+    private Integer number;
+
+}

+ 44 - 0
yudao-module-iscs/src/main/java/cn/iocoder/yudao/module/iscs/controller/admin/statistics/vo/OngoingJobVO.java

@@ -0,0 +1,44 @@
+package cn.iocoder.yudao.module.iscs.controller.admin.statistics.vo;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * 首页返回类
+ *
+ * @author cgj
+ * @date 2024-10-16
+ */
+@Data
+public class OngoingJobVO implements Serializable {
+
+    @Schema(description = "作业票ID")
+    private Long ticketId;
+
+    @Schema(description = "作业票名称")
+    private String ticketName;
+
+    @Schema(description = "所属岗位ID")
+    private Long workstationId;
+
+    @Schema(description = "所属岗位Name")
+    private String workstationName;
+
+    @Schema(description = "设备工艺ID")
+    private Long machineryId;
+
+    @Schema(description = "设备工艺Name")
+    private String machineryName;
+
+    @Schema(description = "作业票类型")
+    private String ticketType;
+
+    @Schema(description = "作业票开始时间")
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date ticketStartTime;
+
+}

+ 35 - 0
yudao-module-iscs/src/main/java/cn/iocoder/yudao/module/iscs/controller/admin/statistics/vo/UserLoanStatisticsVO.java

@@ -0,0 +1,35 @@
+package cn.iocoder.yudao.module.iscs.controller.admin.statistics.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.io.Serializable;
+
+/**
+ * 物资当前状态统计
+ *
+ * @author cgj
+ * @date 2024-10-18
+ */
+@EqualsAndHashCode(callSuper = false)
+@Data
+public class UserLoanStatisticsVO implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    @Schema(description = "用户ID")
+    private Long userId;
+
+    @Schema(description = "用户名称")
+    private String userName;
+
+    @Schema(description = "领取总数")
+    private Integer allCount;
+
+    @Schema(description = "正常归还次数")
+    private Integer normalCount;
+
+    @Schema(description = "超时归还次数")
+    private Integer timeoutCount;
+
+}

+ 35 - 0
yudao-module-iscs/src/main/java/cn/iocoder/yudao/module/iscs/dal/mysql/statistics/StatisticsMapper.java

@@ -0,0 +1,35 @@
+package cn.iocoder.yudao.module.iscs.dal.mysql.statistics;
+
+import cn.iocoder.yudao.module.iscs.controller.admin.statistics.vo.*;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+/**
+ * 物资柜开关门记录Mapper接口
+ *
+ * @author cgj
+ * @date 2025-02-14
+ */
+@Mapper
+public interface StatisticsMapper {
+
+    List<CabinetStatisticsVO> getCabinetStatistics(@Param(value = "startTime") String startTime, @Param(value = "endTime") String endTime);
+
+    List<MaterialsStatusStatisticsVO> getMaterialsStatusStatistics(@Param(value = "startTime") String startTime, @Param(value = "endTime") String endTime);
+
+    List<MaterialsLoanStatisticsVO> getMaterialsLoanStatistics(@Param(value = "startTime") String startTime, @Param(value = "endTime") String endTime);
+
+    List<MaterialsChangeStatisticsVO> getMaterialsChangeStatistics(@Param(value = "startTime") String startTime, @Param(value = "endTime") String endTime);
+
+    List<UserLoanStatisticsVO> getUserLoanStatistics(@Param(value = "startTime") String startTime, @Param(value = "endTime") String endTime);
+
+    List<DayLoanStatisticsVO> getDayLoanStatistics(@Param(value = "startTime") String startTime, @Param(value = "endTime") String endTime);
+
+    List<OngoingJobVO> getOngoingJobList();
+
+    List<HomePageLoanVO> getLoanList(@Param(value = "startTime") String startTime, @Param(value = "endTime") String endTime);
+
+
+}

+ 42 - 0
yudao-module-iscs/src/main/java/cn/iocoder/yudao/module/iscs/service/statistics/StatisticsApiService.java

@@ -0,0 +1,42 @@
+package cn.iocoder.yudao.module.iscs.service.statistics;
+
+import cn.iocoder.yudao.module.iscs.controller.admin.statistics.vo.*;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+
+import java.util.List;
+
+/**
+ * 统计接口
+ *
+ * @author cgj
+ * @date 2024-10-16
+ */
+public interface StatisticsApiService {
+
+    List<CabinetStatisticsVO> getCabinetStatistics(String startTime, String endTime);
+
+    List<MaterialsStatusStatisticsVO> getMaterialsStatusStatistics(String startTime, String endTime);
+
+    List<MaterialsLoanStatisticsVO> getMaterialsLoanStatistics(String startTime, String endTime);
+
+    List<MaterialsChangeStatisticsVO> getMaterialsChangeStatistics(String startTime, String endTime);
+
+    List<UserLoanStatisticsVO> getUserLoanStatistics(String startTime, String endTime);
+
+    List<DayLoanStatisticsVO> getDayLoanStatistics(String startTime, String endTime);
+
+    HomePageVO getHomePage(String startTime, String endTime);
+
+    List<InventoryVO> getMaterialInventory(Integer type);
+
+    List<InventoryTypeVO> getInventorySum();
+
+    void exportMaterialInventory(HttpServletResponse response, HttpServletRequest request);
+
+    void exportBaseData(HttpServletResponse response, HttpServletRequest request, String startTime, String endTime);
+
+    void exportClaimAndReturn(HttpServletResponse response, HttpServletRequest request, String startTime, String endTime);
+
+
+}

+ 488 - 0
yudao-module-iscs/src/main/java/cn/iocoder/yudao/module/iscs/service/statistics/StatisticsApiServiceImpl.java

@@ -0,0 +1,488 @@
+package cn.iocoder.yudao.module.iscs.service.statistics;
+
+import cn.hutool.core.lang.Assert;
+import cn.iocoder.yudao.module.iscs.controller.admin.statistics.vo.*;
+import cn.iocoder.yudao.module.iscs.dal.dataobject.exceptionmisplace.ExceptionMisplaceDO;
+import cn.iocoder.yudao.module.iscs.dal.dataobject.materials.MaterialsDO;
+import cn.iocoder.yudao.module.iscs.dal.dataobject.materialscabinet.MaterialsCabinetDO;
+import cn.iocoder.yudao.module.iscs.dal.dataobject.materialstype.MaterialsTypeDO;
+import cn.iocoder.yudao.module.iscs.dal.mysql.statistics.StatisticsMapper;
+import cn.iocoder.yudao.module.iscs.service.exceptionmisplace.ExceptionMisplaceService;
+import cn.iocoder.yudao.module.iscs.service.materials.MaterialsService;
+import cn.iocoder.yudao.module.iscs.service.materialscabinet.MaterialsCabinetService;
+import cn.iocoder.yudao.module.iscs.service.materialstype.MaterialsTypeService;
+import cn.iocoder.yudao.module.system.dal.dataobject.dict.DictDataDO;
+import cn.iocoder.yudao.module.system.service.dict.DictDataService;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.poi.xssf.streaming.SXSSFRow;
+import org.apache.poi.xssf.streaming.SXSSFSheet;
+import org.apache.poi.xssf.streaming.SXSSFWorkbook;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * 统计接口
+ *
+ * @author cgj
+ * @date 2024-10-16
+ */
+@Slf4j
+@Service
+public class StatisticsApiServiceImpl implements StatisticsApiService {
+
+    @Autowired
+    private StatisticsMapper statisticsMapper;
+    @Autowired
+    private MaterialsService iIsMaterialsService;
+    @Autowired
+    private MaterialsTypeService iIsMaterialsTypeService;
+    @Autowired
+    private MaterialsCabinetService iIsMaterialsCabinetService;
+    @Autowired
+    private ExceptionMisplaceService isMaterialsLoanExceptionService;
+    @Autowired
+    private DictDataService dictDataService;
+
+    @Override
+    public List<CabinetStatisticsVO> getCabinetStatistics(String startTime, String endTime) {
+        return statisticsMapper.getCabinetStatistics(startTime, endTime);
+    }
+
+    @Override
+    public List<MaterialsStatusStatisticsVO> getMaterialsStatusStatistics(String startTime, String endTime) {
+        return statisticsMapper.getMaterialsStatusStatistics(startTime, endTime);
+    }
+
+    @Override
+    public List<MaterialsLoanStatisticsVO> getMaterialsLoanStatistics(String startTime, String endTime) {
+        List<MaterialsLoanStatisticsVO> list = statisticsMapper.getMaterialsLoanStatistics(startTime, endTime);
+        return list;
+    }
+
+    @Override
+    public List<MaterialsChangeStatisticsVO> getMaterialsChangeStatistics(String startTime, String endTime) {
+        return statisticsMapper.getMaterialsChangeStatistics(startTime, endTime);
+    }
+
+    @Override
+    public List<UserLoanStatisticsVO> getUserLoanStatistics(String startTime, String endTime) {
+        return statisticsMapper.getUserLoanStatistics(startTime, endTime);
+    }
+
+    @Override
+    public List<DayLoanStatisticsVO> getDayLoanStatistics(String startTime, String endTime) {
+        return statisticsMapper.getDayLoanStatistics(startTime, endTime);
+    }
+
+    @Override
+    public HomePageVO getHomePage(String startTime, String endTime) {
+        // 1.第一部分
+        List<MaterialsDO> materialsList = iIsMaterialsService.list(Wrappers.<MaterialsDO>lambdaQuery().isNotNull(MaterialsDO::getMaterialsCabinetId));
+        // 1.1物资总数
+        int materialsCount = materialsList.size();
+        // 1.2柜中物资
+        int cabinetMaterialsCount = (int) materialsList.stream().filter(o -> "1".equals(o.getLoanState())).count();
+        // 1.3借出物资
+        int loanMaterialsCount = (int) materialsList.stream().filter(o -> "0".equals(o.getLoanState())).count();
+        // 1.4异常数量
+        int exceptionMaterialsCount = (int) isMaterialsLoanExceptionService.count(Wrappers.<ExceptionMisplaceDO>lambdaQuery().eq(ExceptionMisplaceDO::getStatus, "0"));
+
+        // 2.第二部分,进行中的作业
+        List<OngoingJobVO> ongoingJobList = statisticsMapper.getOngoingJobList();
+
+        // 3.第三部分
+        List<HomePageLoanVO> loanList = statisticsMapper.getLoanList(startTime, endTime);
+
+        HomePageVO vo = new HomePageVO();
+        vo.setMaterialsCount(materialsCount);
+        vo.setCabinetMaterialsCount(cabinetMaterialsCount);
+        vo.setLoanMaterialsCount(loanMaterialsCount);
+        vo.setExceptionMaterialsCount(exceptionMaterialsCount);
+        vo.setJobList(ongoingJobList);
+        vo.setLoanList(loanList);
+        return vo;
+    }
+
+    @Override
+    public List<InventoryVO> getMaterialInventory(Integer type) {
+        Assert.notNull(type, "type不能为空!");
+        // 1.获取所有在柜子中的物资
+        List<MaterialsDO> allMaterials = iIsMaterialsService.list(Wrappers.<MaterialsDO>lambdaQuery()
+                .isNotNull(MaterialsDO::getMaterialsCabinetId)
+                .ne(MaterialsDO::getMaterialsCabinetId, 0));
+        // 2.获取所有的柜子
+        List<MaterialsCabinetDO> cabinets = iIsMaterialsCabinetService.list();
+        // 2.1获取物资分类
+        List<MaterialsTypeDO> materialsTypes = iIsMaterialsTypeService.list();
+        // 3.构建返回类
+        List<InventoryVO> inventoryVOS = new ArrayList<>();
+        if (!allMaterials.isEmpty() && !cabinets.isEmpty() && !materialsTypes.isEmpty()) {
+            for (MaterialsCabinetDO cabinet : cabinets) {
+                InventoryVO inventoryVO = new InventoryVO();
+                inventoryVO.setCabinetId(cabinet.getId());
+                inventoryVO.setCabinetName(cabinet.getCabinetName());
+
+                List<MaterialsTypeVO> materialsTypeVOS = new ArrayList<>();
+                for (MaterialsTypeDO materialsType : materialsTypes) {
+                    MaterialsTypeVO materialsTypeVO = new MaterialsTypeVO();
+                    materialsTypeVO.setMaterialsTypeId(materialsType.getId());
+                    materialsTypeVO.setMaterialsTypeName(materialsType.getMaterialsTypeName());
+                    materialsTypeVO.setMaterialsTypeIcon(materialsType.getMaterialsTypeIcon());
+                    materialsTypeVO.setMaterialsTypePicture(materialsType.getMaterialsTypePicture());
+                    materialsTypeVOS.add(materialsTypeVO);
+                }
+
+                inventoryVO.setMaterialsTypeVOList(materialsTypeVOS);
+                inventoryVOS.add(inventoryVO);
+            }
+            // 4.获取每个类型下需要解析的数据
+            List<MaterialsDO> materials = new ArrayList<>();
+            if (type.equals(0)) {
+                // 总览
+                materials = allMaterials;
+            }
+            if (type.equals(1)) {
+                // 柜中
+                materials = allMaterials.stream().filter(o -> StringUtils.isNotBlank(o.getLoanState()) && "1".equals(o.getLoanState())).collect(Collectors.toList());
+            }
+            if (type.equals(2)) {
+                // 借出
+                materials = allMaterials.stream().filter(o -> StringUtils.isNotBlank(o.getLoanState()) && "0".equals(o.getLoanState())).collect(Collectors.toList());
+            }
+            if (type.equals(3)) {
+                // 正常
+                materials = allMaterials.stream().filter(o -> StringUtils.isNotBlank(o.getStatus()) && "0".equals(o.getStatus())).collect(Collectors.toList());
+            }
+            if (type.equals(4)) {
+                // 过期
+                materials = allMaterials.stream().filter(o -> StringUtils.isNotBlank(o.getStatus()) && "2".equals(o.getStatus())).collect(Collectors.toList());
+            }
+            if (type.equals(5)) {
+                // 损坏
+                materials = allMaterials.stream().filter(o -> StringUtils.isNotBlank(o.getStatus()) && "1".equals(o.getStatus())).collect(Collectors.toList());
+            }
+            // 5.开始解析
+            if (!materials.isEmpty()) {
+                for (InventoryVO inventoryVO : inventoryVOS) {
+                    List<MaterialsDO> cabinetMaterials = materials.stream().filter(o -> o.getMaterialsCabinetId().equals(inventoryVO.getCabinetId())).collect(Collectors.toList());
+                    if (!cabinetMaterials.isEmpty()) {
+                        for (MaterialsTypeVO isMaterialsType : inventoryVO.getMaterialsTypeVOList()) {
+                            int number = (int) cabinetMaterials.stream().filter(o -> o.getMaterialsTypeId().equals(isMaterialsType.getMaterialsTypeId())).count();
+                            isMaterialsType.setNumber(number);
+                        }
+                    }
+                }
+            }
+        }
+        return inventoryVOS;
+    }
+
+    @Override
+    public List<InventoryTypeVO> getInventorySum() {
+        List<DictDataDO> inventoryType = dictDataService.getDictDataListByDictType("Inventory_type");
+        List<MaterialsDO> allMaterials = iIsMaterialsService.list(Wrappers.<MaterialsDO>lambdaQuery()
+                .isNotNull(MaterialsDO::getMaterialsCabinetId)
+                .ne(MaterialsDO::getMaterialsCabinetId, 0));
+        ArrayList<InventoryTypeVO> inventoryTypeVOS = new ArrayList<>();
+        for (DictDataDO sysDictData : inventoryType) {
+            InventoryTypeVO inventoryTypeVO = new InventoryTypeVO();
+            inventoryTypeVO.setDictValue(sysDictData.getValue());
+            inventoryTypeVO.setDictLabel(sysDictData.getLabel());
+            int sum = 0;
+            if ("0".equals(sysDictData.getValue())) {
+                // 总览
+                sum = allMaterials.size();
+            }
+            if ("1".equals(sysDictData.getValue())) {
+                // 柜中
+                sum = (int) allMaterials.stream().filter(o -> StringUtils.isNotBlank(o.getLoanState()) && "1".equals(o.getLoanState())).count();
+            }
+            if ("2".equals(sysDictData.getValue())) {
+                // 借出
+                sum = (int) allMaterials.stream().filter(o -> StringUtils.isNotBlank(o.getLoanState()) && "0".equals(o.getLoanState())).count();
+            }
+            if ("3".equals(sysDictData.getValue())) {
+                // 正常
+                sum = (int) allMaterials.stream().filter(o -> StringUtils.isNotBlank(o.getStatus()) && "0".equals(o.getStatus())).count();
+            }
+            if ("4".equals(sysDictData.getValue())) {
+                // 过期
+                sum = (int) allMaterials.stream().filter(o -> StringUtils.isNotBlank(o.getStatus()) && "2".equals(o.getStatus())).count();
+            }
+            if ("5".equals(sysDictData.getValue())) {
+                // 损坏
+                sum = (int) allMaterials.stream().filter(o -> StringUtils.isNotBlank(o.getStatus()) && "1".equals(o.getStatus())).count();
+            }
+            inventoryTypeVO.setSum(sum);
+            inventoryTypeVOS.add(inventoryTypeVO);
+        }
+        return inventoryTypeVOS;
+    }
+
+    @Override
+    public void exportMaterialInventory(HttpServletResponse response, HttpServletRequest request) {
+        String fileName = "导出数据";
+        List<InventoryVO> materialInventory0 = getMaterialInventory(0);
+        List<InventoryVO> materialInventory1 = getMaterialInventory(1);
+        List<InventoryVO> materialInventory2 = getMaterialInventory(2);
+        List<InventoryVO> materialInventory3 = getMaterialInventory(3);
+        List<InventoryVO> materialInventory4 = getMaterialInventory(4);
+        List<InventoryVO> materialInventory5 = getMaterialInventory(5);
+
+
+        SXSSFWorkbook workbook = new SXSSFWorkbook(20000);
+        getData(workbook, materialInventory0, "总览");
+        getData(workbook, materialInventory1, "柜中");
+        getData(workbook, materialInventory2, "借出");
+        getData(workbook, materialInventory3, "正常");
+        getData(workbook, materialInventory4, "过期");
+        getData(workbook, materialInventory5, "损坏");
+        fileOutputStream(request, response, workbook, fileName);
+    }
+
+
+    // 使用synchronized,防止list在多线程的情况下顺序变乱
+    private synchronized void getData(SXSSFWorkbook workbook, List<InventoryVO> data, String sheetName) {
+        // 由于数据格式的问题,直接转换成List<List<String>>
+        // 数据承载
+        ArrayList<List<String>> lists = new ArrayList<>();
+        // 构造第一行
+        List<String> strings = new ArrayList<>();
+        strings.add(0, "物资类型");
+        for (InventoryVO datum : data) {
+            strings.add(datum.getCabinetName());
+        }
+        lists.add(strings);
+        // 获取接下来还有几行
+        List<MaterialsTypeVO> materialsTypeVOList = data.get(0).getMaterialsTypeVOList();
+        if (!materialsTypeVOList.isEmpty()) {
+            // 每一个typeNames代表一行数据
+            List<String> typeNames = materialsTypeVOList.stream().map(MaterialsTypeVO::getMaterialsTypeName).collect(Collectors.toList());
+            // 开始组装接下来的每一行数据
+            for (String typeName : typeNames) {
+                // 构造其他行
+                List<String> strings1 = new ArrayList<>();
+                strings1.add(typeName);
+                for (InventoryVO datum : data) {
+                    // 只会有一条
+                    List<MaterialsTypeVO> collect = datum.getMaterialsTypeVOList().stream().filter(o -> o.getMaterialsTypeName().equals(typeName)).collect(Collectors.toList());
+                    strings1.add((collect.get(0).getNumber() == null || collect.get(0).getNumber() == 0) ? "" : String.valueOf(collect.get(0).getNumber()));
+                }
+                lists.add(strings1);
+            }
+        }
+        SXSSFSheet sheet = workbook.createSheet(sheetName);
+        for (int i = 0; i < lists.size(); i++) {
+            sheet.setColumnWidth(i, 5000);
+            SXSSFRow row = sheet.createRow(i);
+            for (int j = 0; j < lists.get(i).size(); j++) {
+                row.createCell(j).setCellValue(lists.get(i).get(j));
+            }
+        }
+    }
+
+    private void fileOutputStream(HttpServletRequest request, HttpServletResponse response, SXSSFWorkbook workbook, String fileName) {
+        OutputStream output = null;
+        try {
+            output = response.getOutputStream();
+            String agent = request.getHeader("USER-AGENT").toLowerCase();
+            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); // 使用正确的 MIME 类型
+            response.setContentType("application/force-download");
+            response.setContentType("application/vnd.ms-excel");
+            String codedFileName = URLEncoder.encode(fileName, "UTF-8");
+            if (agent.contains("firefox")) {
+                response.setCharacterEncoding("utf-8");
+                response.setHeader("content-disposition", "attachment;filename=" + new String(fileName.getBytes(), StandardCharsets.UTF_8) + ".xlsx");
+            } else {
+                response.setHeader("content-disposition", "attachment;filename=" + codedFileName + ".xlsx");
+            }
+            workbook.write(output);
+        } catch (IOException e) {
+            log.error("数据导出出错:{}", e.getMessage());
+        } finally {
+            if (output != null) {
+                try {
+                    output.close();
+                } catch (IOException e) {
+                    System.out.println("关闭输出流时出错: " + e.getMessage());
+                }
+            }
+        }
+    }
+
+    @Override
+    public void exportBaseData(HttpServletResponse response, HttpServletRequest request, String startTime, String endTime) {
+        String fileName = "导出数据";
+        SXSSFWorkbook workbook = new SXSSFWorkbook(20000);
+        // ------------------------ 第一个sheet---------------------------------------------
+        List<CabinetStatisticsVO> cabinetStatisticsVOList = getCabinetStatistics(startTime, endTime);
+        // 数据承载
+        ArrayList<List<String>> lists = new ArrayList<>();
+        // 构造第一行
+        List<String> one = new ArrayList<>();
+        one.add("物资柜");
+        one.add("开关次数");
+        one.add("异常总数");
+        one.add("错放数");
+        one.add("超时未关");
+        lists.add(one);
+        // 构造其他行
+        for (CabinetStatisticsVO vo : cabinetStatisticsVOList) {
+            List<String> other = new ArrayList<>();
+            other.add(vo.getCabinetName());
+            other.add(vo.getOpenCount() == null ? "0" : String.valueOf(vo.getOpenCount()));
+            other.add(String.valueOf(vo.getMisplaceCount() + vo.getOpenTimeoutCount()));
+            other.add(String.valueOf(vo.getMisplaceCount()));
+            other.add(String.valueOf(vo.getOpenTimeoutCount()));
+            lists.add(other);
+        }
+        SXSSFSheet sheet = workbook.createSheet("物资柜统计");
+        for (int i = 0; i < lists.size(); i++) {
+            sheet.setColumnWidth(i, 5000);
+            SXSSFRow row = sheet.createRow(i);
+            for (int j = 0; j < lists.get(i).size(); j++) {
+                row.createCell(j).setCellValue(lists.get(i).get(j));
+            }
+        }
+        // ------------------------ 第二个sheet---------------------------------------------
+        List<MaterialsStatusStatisticsVO> materialsStatusStatistics = getMaterialsStatusStatistics(startTime, endTime);
+        // 数据承载
+        ArrayList<List<String>> lists1 = new ArrayList<>();
+        // 构造第一行
+        List<String> one1 = new ArrayList<>();
+        one1.add("物资");
+        one1.add("即将过期");
+        one1.add("已过期");
+        one1.add("损坏数");
+        lists1.add(one1);
+        // 构造其他行
+        for (MaterialsStatusStatisticsVO vo : materialsStatusStatistics) {
+            List<String> other = new ArrayList<>();
+            other.add(vo.getMaterialsTypeName());
+            other.add(String.valueOf(vo.getWillExpireCount()));
+            other.add(String.valueOf(vo.getExpiredCount()));
+            other.add(String.valueOf(vo.getBadCount()));
+            lists1.add(other);
+        }
+        SXSSFSheet sheet1 = workbook.createSheet("物资统计");
+        for (int i = 0; i < lists1.size(); i++) {
+            sheet1.setColumnWidth(i, 5000);
+            SXSSFRow row = sheet1.createRow(i);
+            for (int j = 0; j < lists1.get(i).size(); j++) {
+                row.createCell(j).setCellValue(lists1.get(i).get(j));
+            }
+        }
+        // ------------------------ 第三个sheet---------------------------------------------
+        List<MaterialsChangeStatisticsVO> materialsChangeStatistics = getMaterialsChangeStatistics(startTime, endTime);
+        // 数据承载
+        ArrayList<List<String>> lists2 = new ArrayList<>();
+        // 构造第一行
+        List<String> one2 = new ArrayList<>();
+        one2.add("物资");
+        one2.add("正常更换次数");
+        one2.add("过期更换次数");
+        one2.add("损坏更换次数");
+        lists2.add(one2);
+        // 构造其他行
+        for (MaterialsChangeStatisticsVO vo : materialsChangeStatistics) {
+            List<String> other = new ArrayList<>();
+            other.add(vo.getMaterialsTypeName());
+            other.add(String.valueOf(vo.getAllCount()));
+            other.add(String.valueOf(vo.getExpireCount()));
+            other.add(String.valueOf(vo.getBadCount()));
+            lists2.add(other);
+        }
+        SXSSFSheet sheet2 = workbook.createSheet("物资更换统计");
+        for (int i = 0; i < lists2.size(); i++) {
+            sheet2.setColumnWidth(i, 5000);
+            SXSSFRow row = sheet2.createRow(i);
+            for (int j = 0; j < lists2.get(i).size(); j++) {
+                row.createCell(j).setCellValue(lists2.get(i).get(j));
+            }
+        }
+        fileOutputStream(request, response, workbook, fileName);
+    }
+
+    @Override
+    public void exportClaimAndReturn(HttpServletResponse response, HttpServletRequest request, String startTime, String endTime) {
+        String fileName = "导出数据";
+        SXSSFWorkbook workbook = new SXSSFWorkbook(20000);
+        // ------------------------ 第一个sheet---------------------------------------------
+        List<MaterialsLoanStatisticsVO> materialsLoanStatistics = getMaterialsLoanStatistics(startTime, endTime);
+        // 数据承载
+        ArrayList<List<String>> lists = new ArrayList<>();
+        // 构造第一行
+        List<String> one = new ArrayList<>();
+        one.add("物资");
+        one.add("借出平均时长(小时)");
+        one.add("领取次数");
+        one.add("正常归还次数");
+        one.add("超时归还次数");
+        lists.add(one);
+        // 构造其他行
+        for (MaterialsLoanStatisticsVO vo : materialsLoanStatistics) {
+            List<String> other = new ArrayList<>();
+            other.add(vo.getMaterialsTypeName());
+            double seconds = vo.getAverageTime();
+            // 计算小时数,并保留两位小数
+            double hours = seconds / 3600.0;
+            other.add(String.format("%.2f", hours));
+            other.add(String.valueOf(vo.getAllCount()));
+            other.add(String.valueOf(vo.getReturnCount()));
+            other.add(String.valueOf(vo.getTimeoutCount()));
+            lists.add(other);
+        }
+        SXSSFSheet sheet = workbook.createSheet("物资领取归还");
+        for (int i = 0; i < lists.size(); i++) {
+            sheet.setColumnWidth(i, 5000);
+            SXSSFRow row = sheet.createRow(i);
+            for (int j = 0; j < lists.get(i).size(); j++) {
+                row.createCell(j).setCellValue(lists.get(i).get(j));
+            }
+        }
+
+        // ------------------------ 第二个sheet---------------------------------------------
+        List<DayLoanStatisticsVO> dayLoanStatistics = getDayLoanStatistics(startTime, endTime);
+        // 数据承载
+        ArrayList<List<String>> lists1 = new ArrayList<>();
+        // 构造第一行
+        List<String> one1 = new ArrayList<>();
+        one1.add("日期");
+        one1.add("累计领取次数");
+        one1.add("累计正常归还次数");
+        one1.add("累计超时归还次数");
+        lists1.add(one1);
+        // 构造其他行
+        for (DayLoanStatisticsVO vo : dayLoanStatistics) {
+            List<String> other = new ArrayList<>();
+            other.add(vo.getDay());
+            other.add(String.valueOf(vo.getAllCount()));
+            other.add(String.valueOf(vo.getReturnCount()));
+            other.add(String.valueOf(vo.getTimeoutCount()));
+            lists1.add(other);
+        }
+        SXSSFSheet sheet1 = workbook.createSheet("每日领取归还");
+        for (int i = 0; i < lists1.size(); i++) {
+            sheet1.setColumnWidth(i, 5000);
+            SXSSFRow row = sheet1.createRow(i);
+            for (int j = 0; j < lists1.get(i).size(); j++) {
+                row.createCell(j).setCellValue(lists1.get(i).get(j));
+            }
+        }
+        fileOutputStream(request, response, workbook, fileName);
+    }
+
+
+}

+ 285 - 0
yudao-module-iscs/src/main/resources/mapper/StatisticsMapper.xml

@@ -0,0 +1,285 @@
+<?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="cn.iocoder.yudao.module.iscs.dal.mysql.statistics.StatisticsMapper">
+<cache/>
+    <select id="getCabinetStatistics" resultType="cn.iocoder.yudao.module.iscs.controller.admin.statistics.vo.CabinetStatisticsVO">
+        SELECT
+            c.id as cabinet_id,
+            c.cabinet_name,
+            w.workstation_name,
+            ( CASE WHEN op.open_count IS NULL THEN 0 ELSE op.open_count END ) AS open_count,
+            ( CASE WHEN ex.openex_count IS NULL THEN 0 ELSE ex.openex_count END ) AS open_timeout_count,
+            ( CASE WHEN lex.loanex_count IS NULL THEN 0 ELSE lex.loanex_count END ) AS misplace_count
+        FROM
+            isc_materials_cabinet c
+                LEFT JOIN isc_workstation w ON w.id = c.workstation_id
+                LEFT JOIN ( SELECT o.cabinet_id, count( o.id ) AS open_count FROM isc_cabinet_open_record o
+                <where>
+                    <if test="startTime != null and startTime.trim != ''">
+                        and o.open_time &gt;= #{startTime}
+                    </if>
+                    <if test="endTime != null and endTime.trim != ''">
+                        and o.open_time &lt;= #{endTime}
+                    </if>
+                </where>
+                GROUP BY o.cabinet_id ) op ON op.cabinet_id = c.id
+                LEFT JOIN (SELECT e.loan_from_id, count( e.misplace_id ) AS openex_count FROM sys_exception_misplace e
+                <where>
+                    e.exception_type = '1'
+                    <if test="startTime != null and startTime.trim != ''">
+                        and e.occur_time &gt;= #{startTime}
+                    </if>
+                    <if test="endTime != null and endTime.trim != ''">
+                        and e.occur_time &lt;= #{endTime}
+                    </if>
+                </where>
+                GROUP BY e.loan_from_id ) ex ON ex.loan_from_id = c.id
+                LEFT JOIN (SELECT e.loan_from_id, count( e.misplace_id ) AS loanex_count FROM sys_exception_misplace e
+                <where>
+                    e.exception_type = '0'
+                    <if test="startTime != null and startTime.trim != ''">
+                        and e.occur_time &gt;= #{startTime}
+                    </if>
+                    <if test="endTime != null and endTime.trim != ''">
+                        and e.occur_time &lt;= #{endTime}
+                    </if>
+                </where>
+                GROUP BY e.loan_from_id ) lex ON lex.loan_from_id = c.id
+        order by c.id asc
+    </select>
+
+    <select id="getMaterialsStatusStatistics" resultType="cn.iocoder.yudao.module.iscs.controller.admin.statistics.vo.MaterialsStatusStatisticsVO">
+        SELECT
+        t.id as materials_type_id,
+        t.materials_type_name,
+        ( CASE WHEN a.all_count IS NULL THEN 0 ELSE a.all_count END ) AS all_count,
+        ( CASE WHEN b.will_expire_count IS NULL THEN 0 ELSE b.will_expire_count END ) AS will_expire_count,
+        ( CASE WHEN c.expired_count IS NULL THEN 0 ELSE c.expired_count END ) AS expired_count,
+        ( CASE WHEN d.bad_count IS NULL THEN 0 ELSE d.bad_count END ) AS bad_count
+        FROM
+        isc_materials_type t
+        LEFT JOIN ( SELECT m.materials_type_id, count( m.id ) AS all_count FROM isc_materials m WHERE m.materials_cabinet_id is not null GROUP BY m.materials_type_id ) a ON a.materials_type_id = t.id
+        LEFT JOIN (SELECT m.materials_type_id, count( m.id ) AS will_expire_count FROM isc_materials m WHERE m.materials_cabinet_id is not null and DATE_ADD( NOW(), INTERVAL 30 DAY ) &gt; m.expiration_date AND NOW() &lt; m.expiration_date GROUP BY m.materials_type_id) b ON b.materials_type_id = t.materials_type_id
+        LEFT JOIN (SELECT m.materials_type_id, count( m.id ) AS expired_count FROM isc_materials m WHERE m.materials_cabinet_id is not null and m.STATUS = '2' GROUP BY m.materials_type_id ) c ON c.materials_type_id = t.id
+        LEFT JOIN (SELECT m.materials_type_id, count( m.id ) AS bad_count FROM isc_materials m WHERE m.materials_cabinet_id is not null and m.STATUS = '1' GROUP BY m.materials_type_id) d ON d.materials_type_id = t.id
+        order by t.id asc
+    </select>
+
+    <select id="getMaterialsLoanStatistics"
+            resultType="cn.iocoder.yudao.module.iscs.controller.admin.statistics.vo.MaterialsLoanStatisticsVO">
+        SELECT
+        t.id as materials_type_id,
+        t.materials_type_name,
+        ( CASE WHEN a.all_count IS NULL THEN 0 ELSE a.all_count END ) AS all_count,
+        ( CASE WHEN b.return_count IS NULL THEN 0 ELSE b.return_count END ) AS return_count,
+        ( CASE WHEN c.timeout_count IS NULL THEN 0 ELSE c.timeout_count END ) AS timeout_count,
+        ( CASE WHEN d.average_time IS NULL THEN 0 ELSE d.average_time END ) AS average_time
+        FROM
+        isc_materials_type t
+
+        LEFT JOIN ( SELECT ma.materials_type_id, count( m.materials_id ) AS all_count FROM
+        isc_materials_loan m LEFT JOIN isc_materials ma on ma.id = m.materials_id
+        <where>
+            <if test="startTime != null and startTime.trim != ''">
+                and m.create_time &gt;= #{startTime}
+            </if>
+            <if test="endTime != null and endTime.trim != ''">
+                and m.create_time &lt;= #{endTime}
+            </if>
+        </where>
+        GROUP BY ma.materials_type_id ) a ON a.materials_type_id = t.id
+
+        LEFT JOIN ( SELECT ma.materials_type_id, count( m.materials_id ) AS return_count FROM
+        isc_materials_loan m LEFT JOIN isc_materials ma on ma.id = m.materials_id
+        <where>
+            m.actual_restitution_time &lt;= m.reminder_time
+            <if test="startTime != null and startTime.trim != ''">
+                and m.create_time &gt;= #{startTime}
+            </if>
+            <if test="endTime != null and endTime.trim != ''">
+                and m.create_time &lt;= #{endTime}
+            </if>
+        </where>
+        GROUP BY ma.materials_type_id ) b ON b.materials_type_id = t.id
+
+        LEFT JOIN ( SELECT ma.materials_type_id, count( m.materials_id ) AS timeout_count FROM
+        isc_materials_loan m LEFT JOIN isc_materials ma on ma.id = m.materials_id
+        <where>
+            m.actual_restitution_time &gt; m.reminder_time
+            <if test="startTime != null and startTime.trim != ''">
+                and m.create_time &gt;= #{startTime}
+            </if>
+            <if test="endTime != null and endTime.trim != ''">
+                and m.create_time &lt;= #{endTime}
+            </if>
+        </where>
+        GROUP BY ma.materials_type_id ) c ON c.materials_type_id = t.id
+
+        LEFT JOIN ( SELECT ma.materials_type_id, AVG(TIMESTAMPDIFF(SECOND, m.loan_time, m.actual_restitution_time)) AS average_time FROM
+        isc_materials_loan m LEFT JOIN isc_materials ma on ma.id = m.materials_id
+        <where>
+            <if test="startTime != null and startTime.trim != ''">
+                and m.create_time &gt;= #{startTime}
+            </if>
+            <if test="endTime != null and endTime.trim != ''">
+                and m.create_time &lt;= #{endTime}
+            </if>
+        </where>
+        GROUP BY ma.materials_type_id ) d ON d.materials_type_id = t.id
+        order by t.id asc
+    </select>
+    <select id="getMaterialsChangeStatistics"
+            resultType="cn.iocoder.yudao.module.iscs.controller.admin.statistics.vo.MaterialsChangeStatisticsVO">
+        SELECT
+            t.id as materials_type_id,
+            t.materials_type_name,
+            ( CASE WHEN a.all_count IS NULL THEN 0 ELSE a.all_count END ) AS all_count,
+            ( CASE WHEN b.expire_count IS NULL THEN 0 ELSE b.expire_count END ) AS expire_count,
+            ( CASE WHEN c.bad_count IS NULL THEN 0 ELSE c.bad_count END ) AS bad_count
+        FROM
+            isc_materials_type t
+                LEFT JOIN ( SELECT ma.materials_type_id, count( m.old_materials_id ) AS all_count FROM
+                isc_materials_change_record m
+                LEFT JOIN isc_materials ma on ma.id = m.old_materials_id
+                <where>
+                    (m.check_record_id = null or m.check_record_id = 0)
+                    <if test="startTime != null and startTime.trim != ''">
+                        and m.create_time &gt;= #{startTime}
+                    </if>
+                    <if test="endTime != null and endTime.trim != ''">
+                        and m.create_time &lt;= #{endTime}
+                    </if>
+                </where>
+                GROUP BY ma.materials_type_id ) a ON a.materials_type_id = t.id
+
+                LEFT JOIN (
+                SELECT ma.materials_type_id, count( m.old_materials_id ) AS expire_count FROM
+                    isc_materials_change_record m
+                    LEFT JOIN isc_materials ma on ma.id = m.old_materials_id
+                    LEFT JOIN isc_materials_check_record mc on mc.id = m.check_record_id
+                    <where>
+                        mc.reason = '2'
+                        <if test="startTime != null and startTime.trim != ''">
+                            and m.create_time &gt;= #{startTime}
+                        </if>
+                        <if test="endTime != null and endTime.trim != ''">
+                            and m.create_time &lt;= #{endTime}
+                        </if>
+                    </where>
+                    GROUP BY ma.materials_type_id ) b ON b.materials_type_id = t.id
+
+                LEFT JOIN (
+                SELECT ma.materials_type_id, count( m.old_materials_id ) AS bad_count FROM
+                    is_materials_change_record m
+                        LEFT JOIN is_materials ma on ma.materials_id = m.old_materials_id
+                        LEFT JOIN is_materials_check_record mc on mc.id = m.check_record_id
+                    <where>
+                        mc.reason = '1'
+                        <if test="startTime != null and startTime.trim != ''">
+                            and m.create_time &gt;= #{startTime}
+                        </if>
+                        <if test="endTime != null and endTime.trim != ''">
+                            and m.create_time &lt;= #{endTime}
+                        </if>
+                    </where>
+                    GROUP BY ma.materials_type_id ) c ON c.materials_type_id = t.id
+        order by t.id asc
+    </select>
+    <select id="getUserLoanStatistics" resultType="cn.iocoder.yudao.module.iscs.controller.admin.statistics.vo.UserLoanStatisticsVO">
+        SELECT a.user_id, a.user_name, a.nick_name,
+        ( CASE WHEN b.all_count IS NULL THEN 0 ELSE b.all_count END ) AS all_count,
+        ( CASE WHEN c.normal_count IS NULL THEN 0 ELSE c.normal_count END ) AS normal_count,
+        ( CASE WHEN d.timeout_count IS NULL THEN 0 ELSE d.timeout_count END ) AS timeout_count
+        FROM
+        (SELECT
+        u.id as user_id,
+        u.username as user_name,
+        u.nickname as nick_name
+        FROM isc_materials_loan l LEFT JOIN system_users u ON u.id = l.loan_user_id  GROUP BY u.id) a
+        LEFT JOIN (SELECT l.loan_user_id, count(l.id) as all_count from isc_materials_loan l
+        <where>
+            <if test="startTime != null and startTime.trim != ''">
+                and l.create_time &gt;= #{startTime}
+            </if>
+            <if test="endTime != null and endTime.trim != ''">
+                and l.create_time &lt;= #{endTime}
+            </if>
+        </where>
+        GROUP BY l.loan_user_id) b on b.loan_user_id = a.user_id
+        LEFT JOIN (SELECT l.loan_user_id, count(l.id) as normal_count from isc_materials_loan l
+        <where>
+            l.actual_restitution_time &lt;= l.reminder_time
+            <if test="startTime != null and startTime.trim != ''">
+                and l.create_time &gt;= #{startTime}
+            </if>
+            <if test="endTime != null and endTime.trim != ''">
+                and l.create_time &lt;= #{endTime}
+            </if>
+        </where>
+        GROUP BY l.loan_user_id) c on b.loan_user_id = a.user_id
+        LEFT JOIN (SELECT l.loan_user_id, count(l.id) as timeout_count from isc_materials_loan l
+        <where>
+            l.actual_restitution_time &gt; l.reminder_time
+            <if test="startTime != null and startTime.trim != ''">
+                and l.create_time &gt;= #{startTime}
+            </if>
+            <if test="endTime != null and endTime.trim != ''">
+                and l.create_time &lt;= #{endTime}
+            </if>
+        </where>
+        GROUP BY l.loan_user_id) d on b.loan_user_id = a.user_id
+    </select>
+    <select id="getDayLoanStatistics" resultType="cn.iocoder.yudao.module.iscs.controller.admin.statistics.vo.DayLoanStatisticsVO">
+        select DATE_FORMAT(a.date, '%m/%d') as day,
+        ( CASE WHEN b.all_count  IS NULL THEN 0 ELSE b.all_count  END ) AS all_count,
+        ( CASE WHEN c.return_count  IS NULL THEN 0 ELSE c.return_count  END ) AS return_count,
+        ( CASE WHEN d.timeout_count  IS NULL THEN 0 ELSE d.timeout_count  END ) AS timeout_count
+        FROM (
+        select a.Date from (
+        select curdate() - INTERVAL (a.a + (10 * b.a) + (100 * c.a) + (1000 * d.a) ) DAY as Date
+        from (select 0 as a union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) as a
+        cross join (select 0 as a union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) as b
+        cross join (select 0 as a union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) as c
+        cross join (select 0 as a union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) as d
+        ) a where a.Date between #{startTime} and #{endTime}) a
+        left join (select count(l.id) as all_count, DATE_FORMAT(l.loan_time, '%Y-%m-%d') as date from isc_materials_loan l group by date) b on b.date = a.Date
+        left join (select count(l.id) as return_count, DATE_FORMAT(l.loan_time, '%Y-%m-%d') as date from isc_materials_loan l where DATE_FORMAT(l.loan_time, '%Y-%m-%d') between #{startTime} and #{endTime} and l.actual_restitution_time &lt;= l.reminder_time group by date) c on c.date = a.Date
+        left join (select count(l.id) as timeout_count, DATE_FORMAT(l.loan_time, '%Y-%m-%d') as date from isc_materials_loan l where DATE_FORMAT(l.loan_time, '%Y-%m-%d') between #{startTime} and #{endTime} and l.actual_restitution_time &gt; l.reminder_time group by date) d on d.date = a.Date
+        ORDER BY a.date DESC
+    </select>
+    <select id="getOngoingJobList" resultType="cn.iocoder.yudao.module.iscs.controller.admin.statistics.vo.OngoingJobVO">
+        SELECT
+            j.ticket_id,
+            j.ticket_name,
+            j.workstation_id,
+            w.workstation_name,
+            j.machinery_id,
+            ma.machinery_name,
+            j.ticket_type,
+            j.ticket_start_time
+        FROM
+            isc_job_ticket j
+                LEFT JOIN isc_workstation w ON w.id = j.workstation_id
+                LEFT JOIN isc_machinery ma ON ma.id = j.machinery_id
+        ORDER BY j.ticket_id DESC
+    </select>
+    <select id="getLoanList" resultType="cn.iocoder.yudao.module.iscs.controller.admin.statistics.vo.HomePageLoanVO">
+        select DATE_FORMAT(a.date, '%m/%d') as day,
+        ( CASE WHEN b.loan_count  IS NULL THEN 0 ELSE b.loan_count  END ) AS loan_count,
+        ( CASE WHEN c.return_count  IS NULL THEN 0 ELSE c.return_count  END ) AS return_count
+        FROM (
+            select a.Date from (
+            select curdate() - INTERVAL (a.a + (10 * b.a) + (100 * c.a) + (1000 * d.a) ) DAY as Date
+            from (select 0 as a union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) as a
+            cross join (select 0 as a union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) as b
+            cross join (select 0 as a union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) as c
+            cross join (select 0 as a union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) as d
+            ) a where a.Date between #{startTime} and #{endTime}) a
+            left join (select count(l.id) as loan_count, DATE_FORMAT(l.loan_time, '%Y-%m-%d') as date from isc_materials_loan l where DATE_FORMAT(l.loan_time, '%Y-%m-%d') between #{startTime} and #{endTime} group by date) b on b.date = a.Date
+            left join (select count(l.id) as return_count, DATE_FORMAT(l.loan_time, '%Y-%m-%d') as date from isc_materials_loan l where DATE_FORMAT(l.loan_time, '%Y-%m-%d') between #{startTime} and #{endTime} and l.status = "1" group by date) c on c.date = a.Date
+        ORDER BY a.date DESC
+    </select>
+
+</mapper>