Browse Source

大修大改:完成TODO,优化部分代码

hyy 8 months ago
parent
commit
bbc2225928
23 changed files with 341 additions and 503 deletions
  1. 2 1
      yudao-module-museums/yudao-module-museums-api/src/main/java/cn/iocoder/yudao/module/museums/enums/ErrorCodeConstants.java
  2. 1 1
      yudao-module-museums/yudao-module-museums-api/src/main/java/cn/iocoder/yudao/module/museums/enums/social/LogRecordConstants.java
  3. 2 2
      yudao-module-museums/yudao-module-museums-biz/src/main/java/cn/iocoder/yudao/module/museums/controller/admin/photos/vo/PhotosSaveReqVO.java
  4. 20 137
      yudao-module-museums/yudao-module-museums-biz/src/main/java/cn/iocoder/yudao/module/museums/controller/admin/specimeninfo/SpecimenInfoController.java
  5. 3 11
      yudao-module-museums/yudao-module-museums-biz/src/main/java/cn/iocoder/yudao/module/museums/controller/admin/specimenoutbound/SpecimenOutboundController.java
  6. 4 0
      yudao-module-museums/yudao-module-museums-biz/src/main/java/cn/iocoder/yudao/module/museums/controller/admin/specimenoutbound/vo/SpecimenOutboundRespVO.java
  7. 118 0
      yudao-module-museums/yudao-module-museums-biz/src/main/java/cn/iocoder/yudao/module/museums/controller/admin/specimenoutbound/vo/SpecimenOutboundReturnRespVO.java
  8. 1 1
      yudao-module-museums/yudao-module-museums-biz/src/main/java/cn/iocoder/yudao/module/museums/controller/admin/specimenoutbound/vo/SpecimenOutboundSaveReqVO.java
  9. 11 40
      yudao-module-museums/yudao-module-museums-biz/src/main/java/cn/iocoder/yudao/module/museums/dal/mysql/specimeninfo/SpecimenInfoMapper.java
  10. 10 2
      yudao-module-museums/yudao-module-museums-biz/src/main/java/cn/iocoder/yudao/module/museums/dal/mysql/specimenoutbound/SpecimenOutboundMapper.java
  11. 0 11
      yudao-module-museums/yudao-module-museums-biz/src/main/java/cn/iocoder/yudao/module/museums/service/museumsdocument/MuseumsDocumentService.java
  12. 0 40
      yudao-module-museums/yudao-module-museums-biz/src/main/java/cn/iocoder/yudao/module/museums/service/museumsdocument/MuseumsDocumentServiceImpl.java
  13. 49 46
      yudao-module-museums/yudao-module-museums-biz/src/main/java/cn/iocoder/yudao/module/museums/service/photogroup/PhotoGroupServiceImpl.java
  14. 8 36
      yudao-module-museums/yudao-module-museums-biz/src/main/java/cn/iocoder/yudao/module/museums/service/photos/PhotosServiceImpl.java
  15. 1 28
      yudao-module-museums/yudao-module-museums-biz/src/main/java/cn/iocoder/yudao/module/museums/service/specimeninfo/SpecimenInfoService.java
  16. 84 85
      yudao-module-museums/yudao-module-museums-biz/src/main/java/cn/iocoder/yudao/module/museums/service/specimeninfo/SpecimenInfoServiceImpl.java
  17. 0 1
      yudao-module-museums/yudao-module-museums-biz/src/main/java/cn/iocoder/yudao/module/museums/service/specimenoutbound/SpecimenOutboundService.java
  18. 6 56
      yudao-module-museums/yudao-module-museums-biz/src/main/java/cn/iocoder/yudao/module/museums/service/specimenoutbound/SpecimenOutboundServiceImpl.java
  19. 4 0
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/logger/vo/operatelog/OperateLogPageReqVO.java
  20. 2 0
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/logger/OperateLogDO.java
  21. 7 0
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/logger/OperateLogMapper.java
  22. 1 3
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/logger/OperateLogService.java
  23. 7 2
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/logger/OperateLogServiceImpl.java

+ 2 - 1
yudao-module-museums/yudao-module-museums-api/src/main/java/cn/iocoder/yudao/module/museums/enums/ErrorCodeConstants.java

@@ -14,11 +14,12 @@ public class ErrorCodeConstants {
     public static final ErrorCode UPLOADED_FOLDER_CANNOT_EMPTY = new ErrorCode(1-016-000-002, "上传的压缩包不能为空");
     public static final ErrorCode INVALID_IMAGE_FORMAT = new ErrorCode(1-016-000-003, "图片格式无效");
     public static final ErrorCode SPECIMEN_NUMBER_ALREADY_EXISTS_CANNOT_ADDED = new ErrorCode(1-016-000-004, "标本编号已存在,无法新增");
+    public static final ErrorCode SPECIMEN_NUMBER_NOT_EXISTS = new ErrorCode(1-016-000-005, "存在无效的标本编号");
     // ========== 标本出库回库信息 1-016-001-000 ==========
     public static final ErrorCode SPECIMEN_OUTBOUND_NOT_EXISTS = new ErrorCode(1-016-001-000, "标本出库回库信息不存在");
     public static final ErrorCode NO_PERMISSION_VIEW_NON_RETURNED_SPECIMENS = new ErrorCode(1-016-001-001, "没有权限查看非已回库的标本出库信息");
     public static final ErrorCode SPECIMEN_OUTBOUND_ORDER_NOT_EXISTS = new ErrorCode(1-016-001-002, "标本出库单信息不存在");
-    public static final ErrorCode SPECIMEN_IS_LENDING_OUT = new ErrorCode(1-016-001-003, "标本当前状态为借出中,无法进行出库操作");
+    public static final ErrorCode SPECIMEN_IS_LENDING_OUT = new ErrorCode(1-016-001-003, "存在当前状态为借出中的标本,无法进行出库操作");
     public static final ErrorCode USER_NOT_HAVE_THE_RIGHT_FIRST_INSTANCE = new ErrorCode(1-016-001-004, "用户没有一审权限");
     public static final ErrorCode USER_NOT_HAVE_THE_RIGHT_SECOND_INSTANCE = new ErrorCode(1-016-001-005, "用户没有二审权限");
     public static final ErrorCode INVALID_APPROVAL_STATUS = new ErrorCode(1-016-001-005, "无效的审批状态");

+ 1 - 1
yudao-module-museums/yudao-module-museums-api/src/main/java/cn/iocoder/yudao/module/museums/enums/social/LogRecordConstants.java

@@ -33,5 +33,5 @@ public interface LogRecordConstants {
     String MUSEUMS_SPECIMEN_UPDATE_RETURN_SUCCESS = "更新了标本回库单【{{#existingSpecimen.id}}】, 标本情况: {{#existingSpecimen.specimenCondition}}, 退还人: {{#updateReqVO.returner}}, 点收人: {{#updateReqVO.receiver}}, 备注: {{#updateReqVO.remarks}}";
     String MUSEUMS_SPECIMEN_UPDATE_RECOMPILE_SUCCESS = "修改了标本出库单【{{#updateReqVO.id}}】:{_DIFF{#updateReqVO}}";
     String MUSEUMS_SPECIMEN_CREATE_CONFIEM_OUTBOUND_SUCCESS = "{{#operator}}确认了标本出库";
-    String MUSEUMS_SPECIMEN_APPROVE_OUTBOUND_SUCCESS = "审批结果:{{#approvalMessage}},审批人ID:{{#userId}},驳回原因:{{#processInstanceId}}{{#rejectionReasons}}";
+    String MUSEUMS_SPECIMEN_APPROVE_OUTBOUND_SUCCESS = "审批结果:{{#approvalMessage}},审批人ID:{{#userId}},审批建议:{{#processInstanceId}}{{#rejectionReasons}}";
 }

+ 2 - 2
yudao-module-museums/yudao-module-museums-biz/src/main/java/cn/iocoder/yudao/module/museums/controller/admin/photos/vo/PhotosSaveReqVO.java

@@ -22,7 +22,7 @@ public class PhotosSaveReqVO {
     @NotEmpty(message = "照片存储路径不能为空")
     private List<String> photoUrl;
 
-//    @Schema(description = "上传时间")
-//    private LocalDateTime createdAt;
+    @Schema(description = "上传时间")
+    private LocalDateTime createdAt;
 
 }

+ 20 - 137
yudao-module-museums/yudao-module-museums-biz/src/main/java/cn/iocoder/yudao/module/museums/controller/admin/specimeninfo/SpecimenInfoController.java

@@ -1,9 +1,11 @@
 package cn.iocoder.yudao.module.museums.controller.admin.specimeninfo;
 
+import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants;
 import cn.iocoder.yudao.module.museums.enums.common.CollectionStatusEnum;
 import cn.iocoder.yudao.module.museums.enums.common.PreservationTypeEnum;
 import cn.iocoder.yudao.module.museums.enums.common.SourceEnum;
 import cn.iocoder.yudao.module.museums.enums.common.SpecimenTypeEnum;
+import cn.iocoder.yudao.module.system.controller.admin.logger.vo.operatelog.OperateLogPageReqVO;
 import cn.iocoder.yudao.module.system.controller.admin.logger.vo.operatelog.OperateLogRespVO;
 import cn.iocoder.yudao.module.system.dal.dataobject.logger.OperateLogDO;
 import cn.iocoder.yudao.module.system.service.logger.OperateLogService;
@@ -158,37 +160,6 @@ public class SpecimenInfoController {
         ExcelUtils.write(response, "标本导入模板.xls", "标本信息", SpecimenImportExcelVO.class, list);
     }
 
-
-
-    @PostMapping("/import-specimen")
-    @Operation(summary = "导入标本")
-    @Parameters({
-            @Parameter(name = "file", description = "Excel 文件", required = true),
-            @Parameter(name = "updateSupport", description = "是否支持更新,默认为 false", example = "true")
-    })
-    @PreAuthorize("@ss.hasPermission('museums:specimen-info:import')")
-    public CommonResult<SpecimenImportRespVO> importSpecimenExcel(@RequestParam("file") MultipartFile file,
-                                                                  @RequestParam(value = "updateSupport", required = false, defaultValue = "false") Boolean updateSupport) throws Exception {
-        List<SpecimenImportExcelVO> list = ExcelUtils.read(file, SpecimenImportExcelVO.class);
-        return success(specimenInfoService.importSpecimenList(list, updateSupport));
-    }
-
-    @PostMapping("/import-specimen-images")
-    @Operation(summary = "导入标本图片")
-    @Parameters({
-            @Parameter(name = "file", description = "压缩包文件", required = true)
-    })
-    @PreAuthorize("@ss.hasPermission('museums:specimen-info:import-images')")
-    public CommonResult<String> importSpecimenImages(@RequestParam("file") MultipartFile file) throws Exception {
-        // 解压文件并处理图片
-        String result = specimenInfoService.importSpecimenImages(file);
-        // 确保返回的数据不为 null
-        if (result == null) {
-            throw exception(INVALID_IMAGE_FORMAT);
-        }
-        return success(result);
-    }
-
     @PostMapping("/import-specimen-with-images")
     @Operation(summary = "导入标本及其图片")
     @Parameters({
@@ -233,109 +204,28 @@ public class SpecimenInfoController {
     @GetMapping("/statistics/entry/{year}")
     @Operation(summary = "统计本年标本每月入库数量")
     @Parameter(name = "year", description = "年份", required = true, example = "2024")
-    // TODO 工作台最好有一个独立的权限标识 ,工作台内部的统计可以共用
-    @PreAuthorize("@ss.hasPermission('museums:specimen-info:query')")
+    @PreAuthorize("@ss.hasPermission('museums:specimen-info:workbench')")
     public CommonResult<Map<String, Object>> getMonthlyEntryStatistics(@PathVariable int year) {
-        List<Map<String, Object>> entryStatistics = specimenInfoService.getMonthlyEntryStatistics(year);
-
-        // TODO 返回格式在CommonResult 里面已经封装了啊,不需要在构建一个
-
-        // 构造返回格式
-        Map<String, Object> result = new HashMap<>();
-        result.put("code", 200);
-        //  TODO 统计的就是本年啊?所以这里是不需要的,
-        result.put("year", String.valueOf(year));
-
-
-        //  TODO 直接返回这个就行 Map<String, String> monthData = new HashMap<>();
-        result.put("data", entryStatistics.stream()
-                .map(stat -> {
-                    Map<String, Object> monthData = new HashMap<>();
-                    monthData.put("number", stat.get("entryCount")); // 获取入库数量
-                    monthData.put("month", stat.get("month") + "月"); // 获取月份并转换格式
-                    return monthData;
-                })
-                .collect(Collectors.toList())
-        );
-
-        //  TODO 这个msg完全没必要啊,同样在CommonResult里面封装了
-        //   result.code = GlobalErrorCodeConstants.SUCCESS.getCode();
-        //        result.data = data;
-        //        result.msg = "";
-
-        result.put("msg", "统计本年标本入库数量");
-
-        return success(result);
-    }
-
-    //根据标本类别指标统计各类标本库存数,第一个是可查询某个标本类别的所有数据,第二个是可查询各个标本类型的库存数
-    @GetMapping("/statistics/{specimen_type}")
-    @Operation(summary = "按标本类别统计库存数")
-    @Parameter(name = "specimen_type", description = "标本类型", required = true, example = "1")
-    @PreAuthorize("@ss.hasPermission('museums:specimen-info:query')")
-    public CommonResult<List<SpecimenInfoDO>> getSpecimenTypeStatistics(@PathVariable int specimen_type) {
-        // TODO 这个接口和我在page中写where有什么不同吗? 白写咯哈哈哈
-        List<SpecimenInfoDO> specimenTypeStatistics = specimenInfoService.getSpecimenTypeStatistics(specimen_type);
-        return success(specimenTypeStatistics);
+        List<Map<String, Object>> monthlyStatistics = specimenInfoService.getMonthlyEntryStatistics(year);
+        Map<String, Object> responseData = new HashMap<>();
+        responseData.put("data", monthlyStatistics);
+        return CommonResult.success(responseData);
     }
 
     @GetMapping("/statistics/allType")
     @Operation(summary = "按标本类别统计库存数")
-    @PreAuthorize("@ss.hasPermission('museums:specimen-info:query')")
+    @PreAuthorize("@ss.hasPermission('museums:specimen-info:workbench')")
     public CommonResult<Map<String, Object>> getSpecimenTypeStatistics() {
-
-        // 从服务层获取标本类别的统计数据
-        //  TODO 你第一段代码就已经得出结果了,剩下的其实可以交给前端处理,如果你需要处理,可以使用更简单的方式比如
-        //   @Select("""
-        //    SELECT
-        //        CASE
-        //            WHEN specimen_type = 0 THEN '矿物'
-        //            WHEN specimen_type = 1 THEN '岩石矿石'
-        //            WHEN specimen_type = 2 THEN '化石'
-        //            WHEN specimen_type = 3 THEN '陨石'
-        //            ELSE '未知'
-        //        END as specimen_type,
-        //        COUNT(*) as count
-        //    FROM specimen_info
-        //    GROUP BY specimen_type""") 直接得到结果,填入 return success(result);即可
-        List<Map<String, Object>> specimenTypeStatistics = specimenInfoService.getAllSpecimenTypeStatistics();
-        Map<String, Object> result = new HashMap<>();
-
-        // 映射标本类型,使用 HashMap 代替 Map.of
-        Map<Integer, String> typeMapping = new HashMap<>();
-        typeMapping.put(0, "矿物");
-        typeMapping.put(1, "岩石矿石");
-        typeMapping.put(2, "化石");
-        typeMapping.put(3, "陨石");
-
-        // 存储统计结果的 Map
-        Map<String, Integer> samples = new HashMap<>();
-        int totalCount = 0;
-
-        // 将统计结果填充到 samples 中
-        for (Map<String, Object> specimen : specimenTypeStatistics) {
-            Integer type = (Integer) specimen.get("specimen_type");
-            Integer count = ((Long) specimen.get("count")).intValue(); // 处理 Long 转换
-            String typeName = typeMapping.get(type);
-
-            if (typeName != null) {
-                samples.put(typeName, count);
-                totalCount += count; // 统计总数
-            }
-        }
-
-        // 将总数和样本统计信息放入结果中
-        samples.put("标本总数", totalCount);
-
-        //  TODO 结果可以没必要封装这一层,没有实际的意义直接返回samples即可
-        result.put("samples", samples); // 将样本统计信息放入结果的 data 中
-
-        return success(result);
+        Map<String, Integer> samples = specimenInfoService.getSpecimenTypeStatistics();
+        Map<String, Object> responseData = new HashMap<>();
+        responseData.put("samples", samples);
+        return success(responseData);
     }
 
     //根据出、回、入库的登记信息统计本馆标本历年增减情况。
     @GetMapping("/statistics/yearly")
     @Operation(summary = "根据出、回、入库登记统计标本历年增减情况")
+    @PreAuthorize("@ss.hasPermission('museums:specimen-info:workbench')")
     public CommonResult<Map<String, Object>> getYearlySpecimenStatistics() {
         Map<String, Object> yearlyStatistics = specimenInfoService.getYearlySpecimenStatistics();
         return CommonResult.success(yearlyStatistics);
@@ -344,30 +234,23 @@ public class SpecimenInfoController {
     //根据入馆凭证中标本来源的登记情况统计
     @GetMapping("/statistics/source")
     @Operation(summary = "根据标本来源统计历年标本登记情况")
+    @PreAuthorize("@ss.hasPermission('museums:specimen-info:workbench')")
     public CommonResult<List<Map<String, Object>>> getYearlySpecimenSourceStatistics() {
         List<Map<String, Object>> yearlySourceStatistics = specimenInfoService.getYearlySpecimenSourceStatistics();
         return CommonResult.success(yearlySourceStatistics);
     }
 
-    //标本库管理
-    //实现对标本操作记录进行追溯查看,包括入库记录、编辑记录、出库记录、回库记录等。
-    @GetMapping("/records")
-    @Operation(summary = "获得标本操作记录")
-    @Parameter(name = "id", description = "标本编号", required = true, example = "1024")
-    @PreAuthorize("@ss.hasPermission('museums:specimen-info:query')")
-    public CommonResult<List<SpecimenInfoDO>> select(@RequestParam("id") Long id) {
-        List<SpecimenInfoDO> list = specimenInfoService.getSpecimenRecords(id);
-        return success(list); // 返回整个列表
-    }
-
     @GetMapping("/logs")
     @Operation(summary = "获得标本相关的系统日志")
     @Parameter(name = "specimenId", description = "标本编号", required = true, example = "1024")
     @Parameter(name = "moduleType", description = "操作模块类型", required = true, example = "MUSEUMS 标本")
     public CommonResult<List<OperateLogRespVO>> getSpecimenLogs(
-            @RequestParam("specimenId") Integer specimenId,
-            @RequestParam("moduleType") String moduleType) {
-        List<OperateLogDO> logs = operateLogService.getLogsBySpecimenIdAndType(specimenId, moduleType);
+            @RequestParam("specimenId") List<String> extra,
+            @RequestParam("moduleType") String type) {
+        OperateLogPageReqVO pageReqDTO=new OperateLogPageReqVO();
+        pageReqDTO.setType(type);
+        pageReqDTO.setExtra(extra);
+        List<OperateLogDO> logs = operateLogService.getLogsBySpecimenIdAndType(pageReqDTO);
         return success(BeanUtils.toBean(logs, OperateLogRespVO.class));
     }
 }

+ 3 - 11
yudao-module-museums/yudao-module-museums-biz/src/main/java/cn/iocoder/yudao/module/museums/controller/admin/specimenoutbound/SpecimenOutboundController.java

@@ -144,14 +144,7 @@ public class SpecimenOutboundController {
     public CommonResult<SpecimenOutboundRespVO> getSpecimenReturnInformation(@RequestParam("id") Long id) {
         SpecimenOutboundDO specimenOutbound = specimenOutboundService.getSpecimenReturnInformation(id);
         if (specimenOutbound != null && specimenOutbound.getStatus() == 4) {
-            SpecimenOutboundRespVO respVO = new SpecimenOutboundRespVO();
-            respVO.setReturner(specimenOutbound.getReturner());
-            respVO.setReceiver(specimenOutbound.getReceiver());
-            respVO.setReturnDate(specimenOutbound.getReturnDate());
-            respVO.setRemarks(specimenOutbound.getRemarks());
-            respVO.setSpecimenCondition(specimenOutbound.getSpecimenCondition());
-            //TODO  BeanUtils.toBean(SpecimenOutboundRespVO, SpecimenOutboundDO.class)
-            return success(respVO);
+            return success(BeanUtils.toBean(specimenOutbound, SpecimenOutboundRespVO.class));
         } else {
             throw exception(NO_PERMISSION_VIEW_NON_RETURNED_SPECIMENS);
         }
@@ -183,7 +176,7 @@ public class SpecimenOutboundController {
     @GetMapping("/statistics/outgoing/{year}")
     @Operation(summary = "根据出库登记情况统计本年标本出库信息")
     @Parameter(name = "year", description = "年份", required = true, example = "2024")
-    @PreAuthorize("@ss.hasPermission('museums:specimen-outbound:query')")
+    @PreAuthorize("@ss.hasPermission('museums:specimen-info:workbench')")
     public CommonResult<Map<String, Object>> getOutboundStatistics(@PathVariable int year) {
         List<Map<String, Object>> monthlyStatistics = specimenOutboundService.getMonthlyOutboundStatistics(year);
 
@@ -206,7 +199,7 @@ public class SpecimenOutboundController {
     @GetMapping("/statistics/return/{year}")
     @Operation(summary = "根据回库登记情况统计本年标本回库信息")
     @Parameter(name = "year", description = "年份", required = true, example = "2024")
-    @PreAuthorize("@ss.hasPermission('museums:specimen-outbound:query')")
+    @PreAuthorize("@ss.hasPermission('museums:specimen-info:workbench')")
     public CommonResult<Map<String, Object>> getReturnStatistics(@PathVariable int year) {
         List<Map<String, Object>> monthlyStatistics = specimenOutboundService.getMonthlyReturnStatistics(year);
 
@@ -234,7 +227,6 @@ public class SpecimenOutboundController {
     @PreAuthorize("@ss.hasPermission('museums:specimen-outbound:query')")
     public CommonResult<SpecimenOutboundWithInfoRespVO> getSpecimen(@RequestParam("id") Long id) {
         SpecimenOutboundWithInfoRespVO specimenOutbound = specimenOutboundService.getSpecimenOutboundWithInfo(id);
-
         if (specimenOutbound == null) {
             throw exception(SPECIMEN_OUTBOUND_ORDER_NOT_EXISTS);
         }

+ 4 - 0
yudao-module-museums/yudao-module-museums-biz/src/main/java/cn/iocoder/yudao/module/museums/controller/admin/specimenoutbound/vo/SpecimenOutboundRespVO.java

@@ -108,6 +108,10 @@ public class SpecimenOutboundRespVO {
     @ExcelProperty("一审时间")
     private LocalDateTime approvalTime;
 
+    @Schema(description = "二审时间")
+    @ExcelProperty("二审时间")
+    private LocalDateTime twoApprovalTime;
+
     @Schema(description = "一审批员")
     @ExcelProperty("一审批员")
     private Long approveUsers;

+ 118 - 0
yudao-module-museums/yudao-module-museums-biz/src/main/java/cn/iocoder/yudao/module/museums/controller/admin/specimenoutbound/vo/SpecimenOutboundReturnRespVO.java

@@ -0,0 +1,118 @@
+package cn.iocoder.yudao.module.museums.controller.admin.specimenoutbound.vo;
+
+import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
+import cn.iocoder.yudao.framework.excel.core.convert.DictConvert;
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
+import com.alibaba.excel.annotation.ExcelProperty;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+@Schema(description = "管理后台 - 标本回库信息 Response VO")
+@Data
+@ExcelIgnoreUnannotated
+public class SpecimenOutboundReturnRespVO {
+
+
+    @Schema(description = "主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
+    @ExcelProperty("主键")
+    private Long id;
+
+    @Schema(description = "关联到总表中的标本ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+    @ExcelProperty("关联到总表中的标本ID")
+    private String infoId;
+
+    @Schema(description = "申请出库的标本编号", requiredMode = Schema.RequiredMode.REQUIRED)
+    @ExcelProperty("申请出库的标本编号")
+    private String number;
+
+    @Schema(description = "申请人姓名", requiredMode = Schema.RequiredMode.REQUIRED, example = "张三")
+    @ExcelProperty("申请人姓名")
+    private String applicantName;
+
+    @Schema(description = "申请单位", requiredMode = Schema.RequiredMode.REQUIRED, example = "地质博物馆")
+    @ExcelProperty("申请单位")
+    private String applicationUsage;
+
+    @Schema(description = "电话号码", requiredMode = Schema.RequiredMode.REQUIRED, example = "19900000000")
+    @ExcelProperty("电话号码")
+    private String phoneNumber;
+
+    @Schema(description = "研究项目名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "研究")
+    @ExcelProperty("研究项目名称")
+    private String projectName;
+
+    @Schema(description = "项目开始时间")
+    @ExcelProperty("项目开始时间")
+    private LocalDateTime startTime;
+
+    @Schema(description = "项目结束时间")
+    @ExcelProperty("项目结束时间")
+    private LocalDateTime endTime;
+
+    @Schema(description = "出库备注信息")
+    @ExcelProperty("出库备注信息")
+    private String outboundRemarks;
+
+    @Schema(description = "出库附件上传")
+    @ExcelProperty("出库附件上传")
+    private String attachments;
+
+    @Schema(description = "审批状态", example = "2")
+    @ExcelProperty(value = "审批状态", converter = DictConvert.class)
+    @DictFormat("museums_specimen_info") // TODO 代码优化:建议设置到对应的 DictTypeConstants 枚举类中
+    private Integer status;
+
+    @Schema(description = "回库备注信息")
+    @ExcelProperty("回库备注信息")
+    private String remarks;
+
+    @Schema(description = "标本情况")
+    @ExcelProperty("标本情况")
+    private String specimenCondition;
+
+    @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
+    @ExcelProperty("创建时间")
+    private LocalDateTime createTime;
+
+    @Schema(description = "回库附件上传", example = "2")
+    @ExcelProperty(value = "回库附件上传")
+    private String sampleStatus;
+
+    @Schema(description = "一审驳回原因", example = "27504")
+    @ExcelProperty("一审驳回原因")
+    private String processInstanceId;
+
+    @Schema(description = "二审驳回原因", example = "27504")
+    @ExcelProperty("二审驳回原因")
+    private String rejectionReasons;
+
+    @Schema(description = "出库员")
+    @ExcelProperty("出库员")
+    private Long operator;
+
+    @Schema(description = "退还人")
+    @ExcelProperty("退还人")
+    private String returner;
+
+    @Schema(description = "点收人")
+    @ExcelProperty("点收人")
+    private String receiver;
+
+    @Schema(description = "退还日期")
+    @ExcelProperty("退还日期")
+    private LocalDateTime returnDate;
+
+    @Schema(description = "一审时间")
+    @ExcelProperty("一审时间")
+    private LocalDateTime approvalTime;
+
+    @Schema(description = "一审批员")
+    @ExcelProperty("一审批员")
+    private Long approveUsers;
+
+    @Schema(description = "二审批员")
+    @ExcelProperty("二审批员")
+    private Long twoApproveUsers;
+}

+ 1 - 1
yudao-module-museums/yudao-module-museums-biz/src/main/java/cn/iocoder/yudao/module/museums/controller/admin/specimenoutbound/vo/SpecimenOutboundSaveReqVO.java

@@ -22,7 +22,7 @@ public class SpecimenOutboundSaveReqVO {
 
     @Schema(description = "申请出库的标本编号", requiredMode = Schema.RequiredMode.REQUIRED)
 //    @NotEmpty(message = "申请出库的标本编号不能为空")
-    private String number;
+    private List<String> number;
 
     @Schema(description = "申请人姓名", requiredMode = Schema.RequiredMode.REQUIRED, example = "张三")
     @NotEmpty(message = "申请人姓名不能为空")

+ 11 - 40
yudao-module-museums/yudao-module-museums-biz/src/main/java/cn/iocoder/yudao/module/museums/dal/mysql/specimeninfo/SpecimenInfoMapper.java

@@ -76,17 +76,6 @@ public interface SpecimenInfoMapper extends BaseMapperX<SpecimenInfoDO> {
     @Select("SELECT * FROM museums_specimen_info " + "WHERE YEAR(entry_date) = #{year} " + "AND deleted = 0")
     List<SpecimenInfoDO> selectEntryStatisticsByYear(int year);
 
-    /**
-     * 根据标本类别统计库存数
-     *
-     * @param specimen_type 标本类型
-     * @return 标本类别信息列表
-     */
-    @Select("SELECT * FROM museums_specimen_info " +
-            "WHERE specimen_type = #{specimen_type} " +
-            "AND deleted = 0")
-    List<SpecimenInfoDO> selectSpecimenTypeStatistics(int specimen_type);
-
     /**
      * 查询各类标本的数量统计
      * @return 各类标本的类型及数量
@@ -110,35 +99,17 @@ public interface SpecimenInfoMapper extends BaseMapperX<SpecimenInfoDO> {
     @Select("SELECT * FROM museums_specimen_info WHERE deleted = 0")
     List<SpecimenInfoDO> getInStockRecords();
 
-    //标本库管理
-    //实现对标本操作记录进行追溯查看,包括入库记录、编辑记录、出库记录、回库记录等。
-    default List<SpecimenInfoDO> getSpecimenRecords(Long id) {
-        // TODO 其实只需要写一行id = id  即可,下面的条件你没有传进来,全部是无效的,
-        //  只有id生效,而且还是in,应该用eq 而且这里好像查的不是记录表
-        MPJLambdaWrapper<SpecimenInfoDO> wrapper = new MPJLambdaWrapper<>();
-        wrapper.selectAll(SpecimenInfoDO.class)
-                //出库申请记录
-                .selectAs(SpecimenOutboundDO::getCreator, SpecimenInfoDO::getOutboundCreator)//创建者
-                .selectAs(SpecimenOutboundDO::getCreateTime, SpecimenInfoDO::getApplicantCreateTime)//创建时间
-                .selectAs(SpecimenOutboundDO::getApplicantName, SpecimenInfoDO::getApplicantName)//申请人或申请单位
-                .selectAs(SpecimenOutboundDO::getApplicationUsage, SpecimenInfoDO::getApplicationUsage)//申请出库的用途
-                //出库审批记录
-                .selectAs(SpecimenOutboundDO::getApproveUsers, SpecimenInfoDO::getApproveUsers)//审批员
-                .selectAs(SpecimenOutboundDO::getApprovalTime, SpecimenInfoDO::getApprovalTime)//审批时间
-                .selectAs(SpecimenOutboundDO::getProcessInstanceId, SpecimenInfoDO::getProcessInstanceId)//驳回原因
-                //出库记录
-                .selectAs(SpecimenOutboundDO::getOperator, SpecimenInfoDO::getOperator)//出库员
-                .selectAs(SpecimenOutboundDO::getOutgoingTime, SpecimenInfoDO::getOutgoingTime)//出库时间
-                //回库记录
-                .selectAs(SpecimenOutboundDO::getReturner, SpecimenInfoDO::getReturner)//退还人
-                .selectAs(SpecimenOutboundDO::getReceiver, SpecimenInfoDO::getReceiver)//点收人
-                .selectAs(SpecimenOutboundDO::getReturnDate, SpecimenInfoDO::getReturnDate)//退还日期
-
-                .leftJoin(SpecimenOutboundDO.class, SpecimenOutboundDO::getInfoId, SpecimenInfoDO::getId)
-                .in(SpecimenOutboundDO::getInfoId, id); // 使用in条件
-
-        return selectJoinList(SpecimenInfoDO.class, wrapper);
-    }
+    @Select("SELECT YEAR(create_time) AS year, source, COUNT(*) AS count " +
+            "FROM museums_specimen_info " +
+            "GROUP BY YEAR(create_time), source")
+    List<Map<String, Object>> getYearlySourceStatistics();
+
+
+    @Select("SELECT YEAR(create_time) AS year, COUNT(*) AS in_stock_count " +
+            "FROM museums_specimen_info " +
+            "WHERE deleted = 0 " +
+            "GROUP BY YEAR(create_time)")
+    List<Map<String, Object>> getYearlyInStockRecords();
 
     default SpecimenInfoDO selectBySpecimenNumber(String specimenNumber){
         return selectOne(SpecimenInfoDO::getSpecimenNumber,specimenNumber);

+ 10 - 2
yudao-module-museums/yudao-module-museums-biz/src/main/java/cn/iocoder/yudao/module/museums/dal/mysql/specimenoutbound/SpecimenOutboundMapper.java

@@ -61,8 +61,16 @@ public interface SpecimenOutboundMapper extends BaseMapperX<SpecimenOutboundDO>
     List<SpecimenOutboundReturnReqVO> selectReturnStatisticsByYear(int year);
 
     //根据出、回、入库登记统计标本历年增减情况
-    @Select("SELECT * FROM museums_specimen_outbound WHERE deleted = 0")
-    List<SpecimenOutboundDO> getOutboundRecords();
+    @Select("SELECT YEAR(outgoing_time) AS year, COUNT(*) AS out_stock_count " +
+            "FROM museums_specimen_outbound " +
+            "GROUP BY YEAR(outgoing_time)")
+    List<Map<String, Object>> getYearlyOutboundRecords();
+
+    @Select("SELECT YEAR(return_date) AS year, COUNT(*) AS return_count " +
+            "FROM museums_specimen_outbound " +
+            "WHERE return_date IS NOT NULL " +
+            "GROUP BY YEAR(return_date)")
+    List<Map<String, Object>> getYearlyInboundRecords();
 
     @Select({
             "<script>",

+ 0 - 11
yudao-module-museums/yudao-module-museums-biz/src/main/java/cn/iocoder/yudao/module/museums/service/museumsdocument/MuseumsDocumentService.java

@@ -52,15 +52,4 @@ public interface MuseumsDocumentService {
      */
     PageResult<MuseumsDocumentDO> getDocumentPage(MuseumsDocumentPageReqVO pageReqVO);
 
-//    /**
-//     * 创建博物馆文件记录
-//     *
-//     * @param name     文件名称
-//     * @param path     文件路径
-//     * @param content  文件内容
-//     * @param uploadedBy 上传者
-//     * @return 文件 URL
-//     */
-//    String createDocument(String name, String path, byte[] content, String uploadedBy) throws Exception;
-
 }

+ 0 - 40
yudao-module-museums/yudao-module-museums-biz/src/main/java/cn/iocoder/yudao/module/museums/service/museumsdocument/MuseumsDocumentServiceImpl.java

@@ -77,44 +77,4 @@ public class MuseumsDocumentServiceImpl implements MuseumsDocumentService {
     public PageResult<MuseumsDocumentDO> getDocumentPage(MuseumsDocumentPageReqVO pageReqVO) {
         return documentMapper.selectPage(pageReqVO);
     }
-
-
-//    @Override
-//    @SneakyThrows
-//    public String createDocument(String name, String path, byte[] content, String uploadedBy) {
-//        // 计算默认的 path 名
-//        String type = FileTypeUtils.getMineType(content, name);
-//        if (StrUtil.isEmpty(path)) {
-//            path = FileUtils.generatePath(content, name);
-//        }
-//        // 如果 name 为空,则使用 path 填充
-//        if (StrUtil.isEmpty(name)) {
-//            name = path;
-//        }
-//
-//        // 上传到文件存储器
-//        Assert.notNull(file Client, "客户端(master) 不能为空");
-//        String url = fileClient.upload(content, path, type);
-//
-////        Fileclient client = fileconfigService.getMasterFileclient();
-////        Assert.notNull(client,"客户端(master)不能为空");
-////        String url= client.upload(content, path, type);
-//
-//        // 保存到数据库
-//        MuseumsDocumentDO document = new MuseumsDocumentDO();
-//        document.setFileName(name);
-//        document.setConfigId(fileClient.getId());
-//        document.setPath(path);
-//        document.setUrl(url);
-//        document.setFileType(type);
-//        document.setFileSize(content.length);
-//        document.setUploadedBy(uploadedBy);
-//        document.setCreator(uploadedBy); // 根据需求设置创建者
-//        document.setCreateTime(LocalDateTime.now()); // 设置创建时间
-//        document.setUpdateTime(LocalDateTime.now()); // 设置更新时间
-//        document.setDeleted(0); // 0表示未删除
-//        documentMapper.insert(document); // 保存到数据库
-//
-//        return url; // 返回文件 URL
-//    }
 }

+ 49 - 46
yudao-module-museums/yudao-module-museums-biz/src/main/java/cn/iocoder/yudao/module/museums/service/photogroup/PhotoGroupServiceImpl.java

@@ -9,10 +9,13 @@ import org.springframework.validation.annotation.Validated;
 import org.springframework.transaction.annotation.Transactional;
 
 import java.io.BufferedOutputStream;
+import java.io.ByteArrayOutputStream;
 import java.io.File;
 import java.io.FileOutputStream;
 import java.nio.file.Files;
 import java.time.LocalDateTime;
+import java.util.ArrayList;
+import java.util.List;
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipInputStream;
 
@@ -55,8 +58,6 @@ public class PhotoGroupServiceImpl implements PhotoGroupService {
         return photoGroup.getId();
     }
 
-
-
     @Override
     public void updatePhotoGroup(PhotoGroupSaveReqVO updateReqVO) {
         // 校验存在
@@ -66,14 +67,6 @@ public class PhotoGroupServiceImpl implements PhotoGroupService {
         photoGroupMapper.updateById(updateObj);
     }
 
-//    @Override
-//    public void deletePhotoGroup(Integer id) {
-//        // 校验存在
-//        validatePhotoGroupExists(id);
-//        // 删除
-//        photoGroupMapper.deleteById(id);
-//    }
-
     @Override
     public void deletePhotoGroup(Integer id) {
         // 校验存在
@@ -102,61 +95,71 @@ public class PhotoGroupServiceImpl implements PhotoGroupService {
     }
 
 
+    //公共方法
+    public List<Integer> processZipFile(ZipInputStream zipInputStream, Integer groupId) throws Exception {
+        List<Integer> photoIds = new ArrayList<>();
+        ZipEntry entry;
+        while ((entry = zipInputStream.getNextEntry()) != null) {
+            if (!entry.isDirectory()) {
+                // 检查文件类型,只处理图片
+                if (entry.getName().endsWith(".jpg") || entry.getName().endsWith(".png") || entry.getName().endsWith(".gif")
+                        || entry.getName().endsWith(".bmp") || entry.getName().endsWith(".tiff")
+                        || entry.getName().endsWith(".psd") || entry.getName().endsWith(".raw") || entry.getName().endsWith(".svg")) {
+
+                    // 使用 ByteArrayOutputStream 读取文件内容
+                    ByteArrayOutputStream bos = new ByteArrayOutputStream();
+                    byte[] buffer = new byte[1024];
+                    int length;
+                    while ((length = zipInputStream.read(buffer)) != -1) {
+                        bos.write(buffer, 0, length);
+                    }
+                    byte[] imageBytes = bos.toByteArray();
+
+                    // 上传图片并获取 URL
+                    String imagePath = fileApi.createFile(imageBytes);
+
+                    // 创建照片信息记录
+                    PhotosDO photoRecord = new PhotosDO();
+                    photoRecord.setGroupId(groupId);
+                    photoRecord.setPhotoUrl(imagePath);
+                    photosMapper.insert(photoRecord);
+
+                    // 获取并存储新插入的照片 ID
+                    photoIds.add(photoRecord.getId());
+                }
+            }
+        }
+        return photoIds;
+    }
+
     @Override
-    @Transactional(rollbackFor = Exception.class) // 添加事务,异常则回滚所有导入
+    @Transactional(rollbackFor = Exception.class)
     public Integer importPhotoGroup(String groupName, String groupDescription, LocalDateTime groupDate, MultipartFile file) throws Exception {
-         //TODO 同一个类型的方法怎么写了两种,可以尝试封装成公共方法,这里没有判断图片类型,隔壁方法判断了
-
-        // 校验文件类型
         if (!file.getOriginalFilename().endsWith(".zip")) {
             throw exception(PHOTO_GROUP_MUST_BE_COMPRESSED_PACKAGE);
         }
 
-        // 插入照片组信息
         PhotoGroupSaveReqVO createReqVO = new PhotoGroupSaveReqVO();
         createReqVO.setGroupName(groupName);
-        createReqVO.setGroupDescription(groupDescription); // 可为null
-        createReqVO.setGroupDate(groupDate); // 可为null
+        createReqVO.setGroupDescription(groupDescription);
+        createReqVO.setGroupDate(groupDate);
 
         PhotoGroupDO photoGroup = BeanUtils.toBean(createReqVO, PhotoGroupDO.class);
         photoGroupMapper.insert(photoGroup);
 
-        // 获取新创建的照片组 ID
         Integer groupId = photoGroup.getId();
-
-        // 创建临时目录存放解压后的文件
         File tempDir = Files.createTempDirectory("photo_group_images").toFile();
-        try (ZipInputStream zipInputStream = new ZipInputStream(file.getInputStream())) {
-            ZipEntry entry;
-            while ((entry = zipInputStream.getNextEntry()) != null) {
-                if (!entry.isDirectory()) {
-                    File newFile = new File(tempDir, entry.getName());
-                    // 进行解压
-                    try (BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(newFile))) {
-                        byte[] buffer = new byte[1024];
-                        int len;
-                        while ((len = zipInputStream.read(buffer)) > 0) {
-                            bos.write(buffer, 0, len);
-                        }
-                    }
-
-                    // 上传图片并获取URL
-                    String imagePath = fileApi.createFile(Files.readAllBytes(newFile.toPath()));
 
-                    // 创建照片信息记录
-                    PhotosDO photoRecord = new PhotosDO();
-                    photoRecord.setGroupId(groupId); // 设置照片组ID
-                    photoRecord.setPhotoUrl(imagePath); // 设置照片URL
-                    photosMapper.insert(photoRecord); // 插入照片记录
-                }
-            }
+        try (ZipInputStream zipInputStream = new ZipInputStream(file.getInputStream())) {
+            List<Integer> photoIds = processZipFile(zipInputStream, groupId);
         } catch (Exception e) {
             throw exception(PHOTO_GROUP_PACKAGE_FAILED_DECOMPRESS);
         } finally {
-            // 清理临时文件
-            FileUtils.deleteDirectory(tempDir); // 使用 FileUtils 清理
+            FileUtils.deleteDirectory(tempDir);
         }
-        return groupId; // 返回照片组ID
+
+        return groupId;
     }
 
+
 }

+ 8 - 36
yudao-module-museums/yudao-module-museums-biz/src/main/java/cn/iocoder/yudao/module/museums/service/photos/PhotosServiceImpl.java

@@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.museums.service.photos;
 
 
 import cn.iocoder.yudao.module.infra.api.file.FileApi;
+import cn.iocoder.yudao.module.museums.service.photogroup.PhotoGroupServiceImpl;
 import org.springframework.stereotype.Service;
 import javax.annotation.Resource;
 
@@ -37,6 +38,8 @@ public class PhotosServiceImpl implements PhotosService {
     private PhotosMapper photosMapper;
     @Resource
     private FileApi fileApi;
+    @Resource
+    private PhotoGroupServiceImpl photoGroupServiceImpl;
 
     @Override
     public Integer createPhotos(PhotosSaveReqVO createReqVO) {
@@ -89,58 +92,27 @@ public class PhotosServiceImpl implements PhotosService {
         return photosMapper.selectPage(pageReqVO);
     }
 
-
     @Override
     public List<PhotosDO> getPhotosByGroupId(Integer groupId) {
         return photosMapper.selectByGroupId(groupId);
     }
 
     @Override
-    @Transactional(rollbackFor = Exception.class) // 添加事务
+    @Transactional(rollbackFor = Exception.class)
     public List<Integer> uploadPhotos(Integer groupId, List<MultipartFile> files) throws Exception {
-        List<Integer> photoIds = new ArrayList<>();
+        List<Integer> allPhotoIds = new ArrayList<>();
 
         for (MultipartFile file : files) {
-            // 校验压缩包类型
             if (!file.getOriginalFilename().endsWith(".zip")) {
                 throw new IllegalArgumentException("上传的文件必须是压缩包 (zip)");
             }
 
-            // 解压缩文件并处理图片
             try (ZipInputStream zis = new ZipInputStream(file.getInputStream())) {
-                ZipEntry zipEntry;
-                while ((zipEntry = zis.getNextEntry()) != null) {
-                    // 检查文件类型,只处理图片
-                    //TODO 都存gif了怎么不考虑一下其他类型哈哈哈哈哈,图片类型太少了
-                    if (zipEntry.getName().endsWith(".jpg") || zipEntry.getName().endsWith(".png") || zipEntry.getName().endsWith(".gif")) {
-                        // 使用 ByteArrayOutputStream 读取文件内容
-                        ByteArrayOutputStream bos = new ByteArrayOutputStream();
-                        byte[] buffer = new byte[1024];
-                        int length;
-                        while ((length = zis.read(buffer)) != -1) {
-                            bos.write(buffer, 0, length);
-                        }
-                        byte[] imageBytes = bos.toByteArray();
-
-                        // 上传图片并获取 URL
-                        String imagePath = fileApi.createFile(imageBytes);
-
-                        // 创建照片信息记录
-                        PhotosDO photoRecord = new PhotosDO();
-                        photoRecord.setGroupId(groupId); // 设置照片组ID
-                        photoRecord.setPhotoUrl(imagePath); // 设置照片URL
-                        photosMapper.insert(photoRecord); // 插入照片记录
-
-                        // 获取并存储新插入的照片 ID
-                        photoIds.add(photoRecord.getId());
-                    }
-                }
+                List<Integer> photoIds = photoGroupServiceImpl.processZipFile(zis, groupId);
+                allPhotoIds.addAll(photoIds);
             }
         }
-
-        return photoIds; // 返回所有上传的照片 ID 列表
+        return allPhotoIds;
     }
 
-
-
 }

+ 1 - 28
yudao-module-museums/yudao-module-museums-biz/src/main/java/cn/iocoder/yudao/module/museums/service/specimeninfo/SpecimenInfoService.java

@@ -29,12 +29,6 @@ public interface SpecimenInfoService {
      */
     void updateSpecimenInfo(@Valid SpecimenInfoSaveReqVO updateReqVO);
 
-//    /**
-//     * 删除标本管理
-//     *
-//     * @param id 编号
-//     */
-//    void deleteSpecimenInfo(Integer id);
     /**
      * 删除标本管理
      *
@@ -43,7 +37,6 @@ public interface SpecimenInfoService {
      */
     void deleteSpecimenInfo(Integer id, String deletedReason);
 
-
     /**
      * 获得标本管理
      *
@@ -84,19 +77,12 @@ public interface SpecimenInfoService {
      * @return 每月标本入库数量列表
      */
     List<Map<String, Object>> getMonthlyEntryStatistics(int year);
-    /**
-     * 按标本类别统计库存数
-     *
-     * @param specimen_type 标本类别
-     * @return 标本类别信息列表
-     */
-    List<SpecimenInfoDO> getSpecimenTypeStatistics(int specimen_type);
     /**
      * 按标本类别统计所有库存数量
      *
      * @return 各类标本的库存数量统计
      */
-     List<Map<String, Object>> getAllSpecimenTypeStatistics();
+     Map<String, Integer> getSpecimenTypeStatistics();
     /**
      * 根据出、回、入库登记统计标本历年增减情况
      *
@@ -109,17 +95,4 @@ public interface SpecimenInfoService {
      * @return 年份与标本来源统计信息的映射
      */
     List<Map<String, Object>> getYearlySpecimenSourceStatistics();
-
-    //标本库管理
-    //实现对标本操作记录进行追溯查看,包括入库记录、编辑记录、出库记录、回库记录等。
-    /**
-     * 历年标本来源增减统计
-     *
-     * @param id 标本总表id
-     * @return 标本操作记录
-     */
-    List<SpecimenInfoDO> getSpecimenRecords(Long id);
-
-
-
 }

+ 84 - 85
yudao-module-museums/yudao-module-museums-biz/src/main/java/cn/iocoder/yudao/module/museums/service/specimeninfo/SpecimenInfoServiceImpl.java

@@ -311,84 +311,97 @@ public class SpecimenInfoServiceImpl implements SpecimenInfoService {
     //根据入库的登记情况统计本年标本入库信息
     @Override
     public List<Map<String, Object>> getMonthlyEntryStatistics(int year) {
-        return specimenInfoMapper.selectMonthlyEntryStatisticsByYear(year);
+        List<Map<String, Object>> entryStatistics = specimenInfoMapper.selectMonthlyEntryStatisticsByYear(year);
+        return entryStatistics.stream()
+                .map(stat -> {
+                    Map<String, Object> monthData = new HashMap<>();
+                    monthData.put("number", stat.get("entryCount")); // 获取入库数量
+                    monthData.put("month", stat.get("month") + "月"); // 获取月份并转换格式
+                    return monthData;
+                })
+                .collect(Collectors.toList());
     }
+
     //按标本类别统计库存数
     @Override
-    public List<SpecimenInfoDO> getSpecimenTypeStatistics(int specimen_type) {
-        return specimenInfoMapper.selectSpecimenTypeStatistics(specimen_type);
-    }
-    @Override
-    public List<Map<String, Object>> getAllSpecimenTypeStatistics() {
-        return specimenInfoMapper.selectAllSpecimenTypeStatistics();
-    }
+    public Map<String, Integer> getSpecimenTypeStatistics() {
+        List<Map<String, Object>> specimenTypeStatistics = specimenInfoMapper.selectAllSpecimenTypeStatistics();
+
+        Map<String, Integer> samples = new HashMap<>();
+        int totalCount = 0;
+        int rockMineralCount = 0;
+
+        for (Map<String, Object> specimen : specimenTypeStatistics) {
+            Integer typeId = (Integer) specimen.get("specimen_type");
+            Long countLong = (Long) specimen.get("count");
+            Integer count = countLong != null ? countLong.intValue() : 0;
+            totalCount += count; // 统计总数
+
+            switch (typeId) {
+                case 0:
+                    samples.put("矿物", samples.getOrDefault("矿物", 0) + count);
+                    break;
+                case 1:
+                case 2:
+                    rockMineralCount += count;
+                    break;
+                case 3:
+                    samples.put("化石", samples.getOrDefault("化石", 0) + count);
+                    break;
+                case 4:
+                    samples.put("陨石", samples.getOrDefault("陨石", 0) + count);
+                    break;
+                default:
+                    samples.put("未知", samples.getOrDefault("未知", 0) + count);
+                    break;
+            }
+        }
 
+        samples.put("岩石矿石", rockMineralCount);
+        samples.put("标本总数", totalCount);
+
+        return samples;
+    }
 
-    //根据出、回、入库登记统计标本历年增减情况
     @Override
     public Map<String, Object> getYearlySpecimenStatistics() {
-
-        // TODO 全部查出来然后循环,太慢了,属于偷懒写法了,这个最好改成数据库直查
-        //  ,并且返回的数据格式也不太合适,太容易出错了
-        // 创建一个列表来存放每年的统计数据
         List<Map<String, Object>> yearlyStatisticsList = new ArrayList<>();
 
-        // 获取入库记录
-        List<SpecimenInfoDO> inStockRecords = specimenInfoMapper.getInStockRecords();
-        if (inStockRecords == null) {
-            inStockRecords = new ArrayList<>(); // 初始化为空列表
-        }
+        List<Map<String, Object>> inStockRecords = specimenInfoMapper.getYearlyInStockRecords();
+        List<Map<String, Object>> outboundRecords = specimenOutboundMapper.getYearlyOutboundRecords();
+        List<Map<String, Object>> inboundRecords = specimenOutboundMapper.getYearlyInboundRecords();
 
         // 用于存储每年的统计数据
         Map<Integer, Map<String, Integer>> yearlyDataMap = new HashMap<>();
 
-        // 统计入库数量
-        for (SpecimenInfoDO record : inStockRecords) {
-            if (record.getCreateTime() != null) { // 检查时间字段
-                int year = record.getCreateTime().getYear(); // 获取年份
-                yearlyDataMap.putIfAbsent(year, new HashMap<>());
-                yearlyDataMap.get(year).put("inStockCount", yearlyDataMap.get(year).getOrDefault("inStockCount", 0) + 1);
-            }
+        // 整合入库统计
+        for (Map<String, Object> record : inStockRecords) {
+            long year = ((Number) record.get("year")).longValue();
+            int count = ((Number) record.get("in_stock_count")).intValue();
+            yearlyDataMap.putIfAbsent((int) year, new HashMap<>());
+            yearlyDataMap.get((int) year).put("inStockCount", count);
         }
-
-        // 获取出库记录
-        List<SpecimenOutboundDO> outboundRecords = specimenOutboundMapper.getOutboundRecords();
-        if (outboundRecords == null) {
-            outboundRecords = new ArrayList<>(); // 初始化为空列表
+        // 整合出库统计
+        for (Map<String, Object> record : outboundRecords) {
+            long year = ((Number) record.get("year")).longValue();
+            int count = ((Number) record.get("out_stock_count")).intValue();
+            yearlyDataMap.putIfAbsent((int) year, new HashMap<>());
+            yearlyDataMap.get((int) year).put("outStockCount", count);
         }
-
-        // 统计出库数量
-        for (SpecimenOutboundDO record : outboundRecords) {
-            if (record.getOutgoingTime() != null) { // 检查时间字段
-                int year = record.getOutgoingTime().getYear(); // 获取年份
-                yearlyDataMap.putIfAbsent(year, new HashMap<>());
-                yearlyDataMap.get(year).put("outStockCount", yearlyDataMap.get(year).getOrDefault("outStockCount", 0) + 1);
-            }
+        // 整合回库统计
+        for (Map<String, Object> record : inboundRecords) {
+            long year = ((Number) record.get("year")).longValue();
+            int count = ((Number) record.get("return_count")).intValue();
+            yearlyDataMap.putIfAbsent((int) year, new HashMap<>());
+            yearlyDataMap.get((int) year).put("returnCount", count);
         }
-
-        // 获取回库记录
-        List<SpecimenOutboundDO> inboundRecords = specimenOutboundMapper.getOutboundRecords();
-        if (inboundRecords == null) {
-            inboundRecords = new ArrayList<>(); // 初始化为空列表
-        }
-
-        // 统计回库数量
-        for (SpecimenOutboundDO record : inboundRecords) {
-            if (record.getReturnDate() != null) { // 检查时间字段
-                int year = record.getReturnDate().getYear(); // 获取年份
-                yearlyDataMap.putIfAbsent(year, new HashMap<>());
-                yearlyDataMap.get(year).put("returnCount", yearlyDataMap.get(year).getOrDefault("returnCount", 0) + 1);
-            }
-        }
-
         // 将统计结果转化为列表格式
         for (Map.Entry<Integer, Map<String, Integer>> entry : yearlyDataMap.entrySet()) {
             Map<String, Object> yearData = new HashMap<>();
             yearData.put("year", entry.getKey().toString());
-            yearData.putAll(entry.getValue()); // 添加对应的数量
+            yearData.putAll(entry.getValue());
             yearlyStatisticsList.add(yearData);
         }
-
         // 构建最终的返回结果
         Map<String, Object> resultMap = new HashMap<>();
         resultMap.put("code", 200);
@@ -400,36 +413,29 @@ public class SpecimenInfoServiceImpl implements SpecimenInfoService {
 
     @Override
     public List<Map<String, Object>> getYearlySpecimenSourceStatistics() {
+        // 从数据库直接获取统计数据
+        List<Map<String, Object>> yearlySourceStatistics = specimenInfoMapper.getYearlySourceStatistics();
 
-        // TODO 同理
-
-        // 年份与标本来源统计信息的映射
-        Map<Integer, Map<String, Integer>> yearlySourceDataMap = new HashMap<>();
+        // 创建结果列表
+        List<Map<String, Object>> resultList = new ArrayList<>();
 
-        // 获取入库记录
-        List<SpecimenInfoDO> inStockRecords = specimenInfoMapper.getInStockRecords();
-        if (inStockRecords == null) {
-            inStockRecords = new ArrayList<>(); // 初始化为空列表
-        }
+        // 使用 Map 来组织每年的数据
+        Map<Long, Map<String, Long>> yearlySourceDataMap = new HashMap<>();
 
-        // 统计入库记录
-        for (SpecimenInfoDO record : inStockRecords) {
-            if (record != null && record.getCreateTime() != null) { // 检查 record 和 createTime
-                int year = record.getCreateTime().getYear(); // 获取年份
-                yearlySourceDataMap.putIfAbsent(year, new HashMap<>());
+        for (Map<String, Object> record : yearlySourceStatistics) {
+            Long year = ((Number) record.get("year")).longValue(); // 处理 year
+            String sourceKey = getSourceKey((Integer) record.get("source")); // source 仍然可以用 Integer 处理
+            Long count = ((Number) record.get("count")).longValue(); // 处理 count
 
-                // 根据标本来源进行统计
-                String sourceKey = getSourceKey(record.getSource());
-                yearlySourceDataMap.get(year).put(sourceKey, yearlySourceDataMap.get(year).getOrDefault(sourceKey, 0) + 1);
-            }
+            yearlySourceDataMap.putIfAbsent(year, new HashMap<>());
+            yearlySourceDataMap.get(year).put(sourceKey, count);
         }
 
         // 转换为所需的 List<Map<String, Object>> 结构
-        List<Map<String, Object>> resultList = new ArrayList<>();
-        for (Map.Entry<Integer, Map<String, Integer>> entry : yearlySourceDataMap.entrySet()) {
+        for (Map.Entry<Long, Map<String, Long>> entry : yearlySourceDataMap.entrySet()) {
             Map<String, Object> yearData = new HashMap<>();
             yearData.put("year", String.valueOf(entry.getKey())); // 将年份转换为字符串
-            yearData.putAll(entry.getValue()); // 添加该年份的统计信息
+            entry.getValue().forEach((key, value) -> yearData.put(key, value)); // 添加该年份的统计信息
             resultList.add(yearData);
         }
 
@@ -438,7 +444,7 @@ public class SpecimenInfoServiceImpl implements SpecimenInfoService {
 
     // Helper 方法将整数源转换为字符串
     private String getSourceKey(Integer source) { // 使用 Integer 允许 null
-        if (source == null) return "未知"; // 处理 null 的情况
+        if (source == null) return "unknown"; // 处理 null 的情况
         switch (source) {
             case 0: return "purchase";
             case 1: return "donate";
@@ -446,11 +452,4 @@ public class SpecimenInfoServiceImpl implements SpecimenInfoService {
             default: return "other";
         }
     }
-
-    //标本库管理
-    //实现对标本操作记录进行追溯查看,包括入库记录、编辑记录、出库记录、回库记录等。
-    @Override
-    public List<SpecimenInfoDO> getSpecimenRecords(Long id) {
-        return specimenInfoMapper.getSpecimenRecords(id);
-    }
 }

+ 0 - 1
yudao-module-museums/yudao-module-museums-biz/src/main/java/cn/iocoder/yudao/module/museums/service/specimenoutbound/SpecimenOutboundService.java

@@ -61,7 +61,6 @@ public interface SpecimenOutboundService {
      */
     SpecimenOutboundDO getSpecimenReturnInformation(Long id);
 
-
     /**
      * 获得标本出库回库信息分页
      *

+ 6 - 56
yudao-module-museums/yudao-module-museums-biz/src/main/java/cn/iocoder/yudao/module/museums/service/specimenoutbound/SpecimenOutboundServiceImpl.java

@@ -46,56 +46,6 @@ public class SpecimenOutboundServiceImpl implements SpecimenOutboundService {
     private SpecimenInfoMapper specimenInfoMapper; // 引入标本信息的Mapper
 
     //创建出库申请
-//    @Override
-//    public Long createSpecimenOutbound(SpecimenOutboundSaveReqVO createReqVO) {
-//        // 插入
-//        SpecimenOutboundDO specimenOutbound = BeanUtils.toBean(createReqVO, SpecimenOutboundDO.class);
-//        //TODO 判断标本是否已经出库,如果已经出库,则要求先完成回库
-//        specimenOutboundMapper.insert(specimenOutbound);
-//        // 返回
-//        return specimenOutbound.getId();
-//    }
-
-//    @Override
-//    @Transactional(rollbackFor = Exception.class)
-//    @LogRecord(type = MUSEUMS_SPECIMEN_TYPE, subType = MUSEUMS_SPECIMEN_OUTBOUND_SUB_TYPE,
-//            bizNo = "{{#specimenOutbound.id}}", // 使用新增的出库单 ID
-//            success = MUSEUMS_SPECIMEN_CREATE_OUTBOUND_SUCCESS, extra = "{{#createReqVO.infoId}}")
-//    public Long createSpecimenOutbound(SpecimenOutboundSaveReqVO createReqVO) {
-//        // 将逗号分隔的字符串拆分为List<String>
-//        List<String> infoIds = Arrays.asList(createReqVO.getInfoId().split(","));
-//
-//        // 校验标本状态,收集有效的ID
-//        List<Long> validInfoIds = infoIds.stream()
-//                .map(infoId -> {
-//                    SpecimenInfoDO specimenInfo = specimenInfoMapper.selectById(infoId.trim());
-//                    if (specimenInfo == null) {
-//                        throw exception(SPECIMEN_OUTBOUND_NOT_EXISTS);
-//                    }
-//                    if (specimenInfo.getCollectionStatus() == 0 || specimenInfo.getCollectionStatus() == 2) {
-//                        return Long.valueOf(infoId);
-//                    } else {
-//                        throw exception(SPECIMEN_IS_LENDING_OUT);
-//                    }
-//                })
-//                .collect(Collectors.toList());
-//
-//        // 拼接info_id字符串
-//        String infoIdString = String.join(",", validInfoIds.stream().map(String::valueOf).toArray(String[]::new));
-//
-//        // 创建出库记录
-//        SpecimenOutboundDO specimenOutbound = BeanUtils.toBean(createReqVO, SpecimenOutboundDO.class);
-//        specimenOutbound.setInfoId(infoIdString);
-//        specimenOutboundMapper.insert(specimenOutbound);
-//
-//        // 记录日志上下文
-//        LogRecordContext.putVariable("specimenOutbound", specimenOutbound); // 添加出库单对象
-//        LogRecordContext.putVariable("createReqVO", createReqVO); // 添加请求对象
-//
-//        // 返回出库记录ID
-//        return specimenOutbound.getId();
-//    }
-
     @Override
     @Transactional(rollbackFor = Exception.class)
     @LogRecord(type = MUSEUMS_SPECIMEN_TYPE, subType = MUSEUMS_SPECIMEN_OUTBOUND_SUB_TYPE,
@@ -104,20 +54,21 @@ public class SpecimenOutboundServiceImpl implements SpecimenOutboundService {
     public Long createSpecimenOutbound(SpecimenOutboundSaveReqVO createReqVO) {
         // 校验标本状态,收集有效的ID
         List<String> validInfoIds = new ArrayList<>();
-        for (String id : createReqVO.getInfoId()) {
-            SpecimenInfoDO specimenInfo = specimenInfoMapper.selectById(id);
+
+        for (String number : createReqVO.getNumber()) {
+            SpecimenInfoDO specimenInfo = specimenInfoMapper.selectBySpecimenNumber(number);
             if (specimenInfo == null) {
-                throw exception(SPECIMEN_OUTBOUND_NOT_EXISTS);
+                throw exception(SPECIMEN_NUMBER_NOT_EXISTS);
             }
             if (specimenInfo.getCollectionStatus() == 0 || specimenInfo.getCollectionStatus() == 2) {
-                validInfoIds.add(id);
+                validInfoIds.add(String.valueOf(specimenInfo.getId()));
             } else {
                 throw exception(SPECIMEN_IS_LENDING_OUT);
             }
         }
 
         // 将有效ID转换为字符串
-        String infoIdString = validInfoIds.toString();
+        String infoIdString = String.join(",", validInfoIds);
 
         // 创建出库记录
         SpecimenOutboundDO specimenOutbound = BeanUtils.toBean(createReqVO, SpecimenOutboundDO.class);
@@ -356,7 +307,6 @@ public class SpecimenOutboundServiceImpl implements SpecimenOutboundService {
         return specimenOutboundMapper.getMonthlyReturnStatistics(year);
     }
 
-
     //获取出库表单的方法
     @Override
     public SpecimenOutboundWithInfoRespVO getSpecimenOutboundWithInfo(Long id) {

+ 4 - 0
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/logger/vo/operatelog/OperateLogPageReqVO.java

@@ -6,6 +6,7 @@ import lombok.Data;
 import org.springframework.format.annotation.DateTimeFormat;
 
 import java.time.LocalDateTime;
+import java.util.List;
 
 import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
 
@@ -28,6 +29,9 @@ public class OperateLogPageReqVO extends PageParam {
     @Schema(description = "操作明细,模拟匹配", example = "修改编号为 1 的用户信息")
     private String action;
 
+    @Schema(description = "操作明细,模拟匹配", example = "修改编号为 1 的用户信息")
+    private List<String> extra;
+
     @Schema(description = "开始时间", example = "[2022-07-01 00:00:00,2022-07-01 23:59:59]")
     @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
     private LocalDateTime[] createTime;

+ 2 - 0
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/logger/OperateLogDO.java

@@ -7,6 +7,8 @@ import com.baomidou.mybatisplus.annotation.TableId;
 import com.baomidou.mybatisplus.annotation.TableName;
 import lombok.Data;
 
+import java.util.List;
+
 /**
  * 操作日志表
  *

+ 7 - 0
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/logger/OperateLogMapper.java

@@ -15,13 +15,20 @@ import java.util.List;
 public interface OperateLogMapper extends BaseMapperX<OperateLogDO> {
 
     default PageResult<OperateLogDO> selectPage(OperateLogPageReqVO pageReqDTO) {
+
+        String id = pageReqDTO.getExtra().get(0).toString();
         return selectPage(pageReqDTO, new LambdaQueryWrapperX<OperateLogDO>()
                 .eqIfPresent(OperateLogDO::getUserId, pageReqDTO.getUserId())
                 .eqIfPresent(OperateLogDO::getBizId, pageReqDTO.getBizId())
                 .likeIfPresent(OperateLogDO::getType, pageReqDTO.getType())
                 .likeIfPresent(OperateLogDO::getSubType, pageReqDTO.getSubType())
                 .likeIfPresent(OperateLogDO::getAction, pageReqDTO.getAction())
+//                .inIfPresent(OperateLogDO::getExtra,pageReqDTO.getExtra())
                 .betweenIfPresent(OperateLogDO::getCreateTime, pageReqDTO.getCreateTime())
+                .likeIfPresent(OperateLogDO::getExtra, "[" + id + ", ")
+                .or(qw->qw.like(OperateLogDO::getExtra, "["+ id + "]"))
+                .or(qw->qw.like(OperateLogDO::getExtra, ", "+ id + ","))
+                .or(qw->qw.like(OperateLogDO::getExtra, ", "+ id + "]"))
                 .orderByDesc(OperateLogDO::getId));
     }
 

+ 1 - 3
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/logger/OperateLogService.java

@@ -41,10 +41,8 @@ public interface OperateLogService {
     /**
      * 根据标本编号和操作模块类型获取系统日志
      *
-     * @param specimenId 标本编号
-     * @param moduleType 操作模块类型
      * @return 系统日志列表
      */
-    List<OperateLogDO> getLogsBySpecimenIdAndType(Integer specimenId, String moduleType);
+    List<OperateLogDO> getLogsBySpecimenIdAndType(OperateLogPageReqVO pageReqDTO);
 
 }

+ 7 - 2
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/logger/OperateLogServiceImpl.java

@@ -43,9 +43,14 @@ public class OperateLogServiceImpl implements OperateLogService {
         return operateLogMapper.selectPage(pageReqDTO);
     }
 
+//    @Override
+//    public List<OperateLogDO> getLogsBySpecimenIdAndType(Integer specimenId, String moduleType) {
+//        return operateLogMapper.selectBySpecimenIdAndType(specimenId, moduleType);
+//    }
+
     @Override
-    public List<OperateLogDO> getLogsBySpecimenIdAndType(Integer specimenId, String moduleType) {
-        return operateLogMapper.selectBySpecimenIdAndType(specimenId, moduleType);
+    public List<OperateLogDO> getLogsBySpecimenIdAndType(OperateLogPageReqVO pageReqDTO) {
+        return operateLogMapper.selectPage(pageReqDTO).getList();
     }
 
 }