Browse Source

Merge remote-tracking branch 'refs/remotes/origin/master'

# Conflicts:
#	pom.xml
#	yudao-server/pom.xml
#	yudao-server/src/main/resources/application-local.yaml
yzx 5 months ago
parent
commit
fbec379961
59 changed files with 3836 additions and 9 deletions
  1. 5 0
      pom.xml
  2. 38 0
      yudao-module-museums/pom.xml
  3. 26 0
      yudao-module-museums/yudao-module-museums-api/pom.xml
  4. 25 0
      yudao-module-museums/yudao-module-museums-api/src/main/java/cn/iocoder/yudao/module/museums/enums/ErrorCodeConstants.java
  5. 56 0
      yudao-module-museums/yudao-module-museums-biz/pom.xml
  6. 95 0
      yudao-module-museums/yudao-module-museums-biz/src/main/java/cn/iocoder/yudao/module/museums/controller/admin/museumsdocument/MuseumsDocumentController.java
  7. 47 0
      yudao-module-museums/yudao-module-museums-biz/src/main/java/cn/iocoder/yudao/module/museums/controller/admin/museumsdocument/vo/MuseumsDocumentPageReqVO.java
  8. 55 0
      yudao-module-museums/yudao-module-museums-biz/src/main/java/cn/iocoder/yudao/module/museums/controller/admin/museumsdocument/vo/MuseumsDocumentRespVO.java
  9. 46 0
      yudao-module-museums/yudao-module-museums-biz/src/main/java/cn/iocoder/yudao/module/museums/controller/admin/museumsdocument/vo/MuseumsDocumentSaveReqVO.java
  10. 95 0
      yudao-module-museums/yudao-module-museums-biz/src/main/java/cn/iocoder/yudao/module/museums/controller/admin/photogroup/PhotoGroupController.java
  11. 38 0
      yudao-module-museums/yudao-module-museums-biz/src/main/java/cn/iocoder/yudao/module/museums/controller/admin/photogroup/vo/PhotoGroupPageReqVO.java
  12. 43 0
      yudao-module-museums/yudao-module-museums-biz/src/main/java/cn/iocoder/yudao/module/museums/controller/admin/photogroup/vo/PhotoGroupRespVO.java
  13. 34 0
      yudao-module-museums/yudao-module-museums-biz/src/main/java/cn/iocoder/yudao/module/museums/controller/admin/photogroup/vo/PhotoGroupSaveReqVO.java
  14. 95 0
      yudao-module-museums/yudao-module-museums-biz/src/main/java/cn/iocoder/yudao/module/museums/controller/admin/photos/PhotosController.java
  15. 31 0
      yudao-module-museums/yudao-module-museums-biz/src/main/java/cn/iocoder/yudao/module/museums/controller/admin/photos/vo/PhotosPageReqVO.java
  16. 35 0
      yudao-module-museums/yudao-module-museums-biz/src/main/java/cn/iocoder/yudao/module/museums/controller/admin/photos/vo/PhotosRespVO.java
  17. 28 0
      yudao-module-museums/yudao-module-museums-biz/src/main/java/cn/iocoder/yudao/module/museums/controller/admin/photos/vo/PhotosSaveReqVO.java
  18. 95 0
      yudao-module-museums/yudao-module-museums-biz/src/main/java/cn/iocoder/yudao/module/museums/controller/admin/specimeninfo/SpecimenInfoController.java
  19. 116 0
      yudao-module-museums/yudao-module-museums-biz/src/main/java/cn/iocoder/yudao/module/museums/controller/admin/specimeninfo/vo/SpecimenInfoPageReqVO.java
  20. 142 0
      yudao-module-museums/yudao-module-museums-biz/src/main/java/cn/iocoder/yudao/module/museums/controller/admin/specimeninfo/vo/SpecimenInfoRespVO.java
  21. 109 0
      yudao-module-museums/yudao-module-museums-biz/src/main/java/cn/iocoder/yudao/module/museums/controller/admin/specimeninfo/vo/SpecimenInfoSaveReqVO.java
  22. 95 0
      yudao-module-museums/yudao-module-museums-biz/src/main/java/cn/iocoder/yudao/module/museums/controller/admin/specimenoutbound/SpecimenOutboundController.java
  23. 76 0
      yudao-module-museums/yudao-module-museums-biz/src/main/java/cn/iocoder/yudao/module/museums/controller/admin/specimenoutbound/vo/SpecimenOutboundPageReqVO.java
  24. 91 0
      yudao-module-museums/yudao-module-museums-biz/src/main/java/cn/iocoder/yudao/module/museums/controller/admin/specimenoutbound/vo/SpecimenOutboundRespVO.java
  25. 77 0
      yudao-module-museums/yudao-module-museums-biz/src/main/java/cn/iocoder/yudao/module/museums/controller/admin/specimenoutbound/vo/SpecimenOutboundSaveReqVO.java
  26. 64 0
      yudao-module-museums/yudao-module-museums-biz/src/main/java/cn/iocoder/yudao/module/museums/dal/dataobject/museumsdocument/MuseumsDocumentDO.java
  27. 53 0
      yudao-module-museums/yudao-module-museums-biz/src/main/java/cn/iocoder/yudao/module/museums/dal/dataobject/photogroup/PhotoGroupDO.java
  28. 44 0
      yudao-module-museums/yudao-module-museums-biz/src/main/java/cn/iocoder/yudao/module/museums/dal/dataobject/photos/PhotosDO.java
  29. 149 0
      yudao-module-museums/yudao-module-museums-biz/src/main/java/cn/iocoder/yudao/module/museums/dal/dataobject/specimeninfo/SpecimenInfoDO.java
  30. 102 0
      yudao-module-museums/yudao-module-museums-biz/src/main/java/cn/iocoder/yudao/module/museums/dal/dataobject/specimenoutbound/SpecimenOutboundDO.java
  31. 34 0
      yudao-module-museums/yudao-module-museums-biz/src/main/java/cn/iocoder/yudao/module/museums/dal/mysql/museumsdocument/MuseumsDocumentMapper.java
  32. 31 0
      yudao-module-museums/yudao-module-museums-biz/src/main/java/cn/iocoder/yudao/module/museums/dal/mysql/photogroup/PhotoGroupMapper.java
  33. 29 0
      yudao-module-museums/yudao-module-museums-biz/src/main/java/cn/iocoder/yudao/module/museums/dal/mysql/photos/PhotosMapper.java
  34. 55 0
      yudao-module-museums/yudao-module-museums-biz/src/main/java/cn/iocoder/yudao/module/museums/dal/mysql/specimeninfo/SpecimenInfoMapper.java
  35. 43 0
      yudao-module-museums/yudao-module-museums-biz/src/main/java/cn/iocoder/yudao/module/museums/dal/mysql/specimenoutbound/SpecimenOutboundMapper.java
  36. 55 0
      yudao-module-museums/yudao-module-museums-biz/src/main/java/cn/iocoder/yudao/module/museums/service/museumsdocument/MuseumsDocumentService.java
  37. 74 0
      yudao-module-museums/yudao-module-museums-biz/src/main/java/cn/iocoder/yudao/module/museums/service/museumsdocument/MuseumsDocumentServiceImpl.java
  38. 55 0
      yudao-module-museums/yudao-module-museums-biz/src/main/java/cn/iocoder/yudao/module/museums/service/photogroup/PhotoGroupService.java
  39. 74 0
      yudao-module-museums/yudao-module-museums-biz/src/main/java/cn/iocoder/yudao/module/museums/service/photogroup/PhotoGroupServiceImpl.java
  40. 55 0
      yudao-module-museums/yudao-module-museums-biz/src/main/java/cn/iocoder/yudao/module/museums/service/photos/PhotosService.java
  41. 74 0
      yudao-module-museums/yudao-module-museums-biz/src/main/java/cn/iocoder/yudao/module/museums/service/photos/PhotosServiceImpl.java
  42. 55 0
      yudao-module-museums/yudao-module-museums-biz/src/main/java/cn/iocoder/yudao/module/museums/service/specimeninfo/SpecimenInfoService.java
  43. 73 0
      yudao-module-museums/yudao-module-museums-biz/src/main/java/cn/iocoder/yudao/module/museums/service/specimeninfo/SpecimenInfoServiceImpl.java
  44. 55 0
      yudao-module-museums/yudao-module-museums-biz/src/main/java/cn/iocoder/yudao/module/museums/service/specimenoutbound/SpecimenOutboundService.java
  45. 74 0
      yudao-module-museums/yudao-module-museums-biz/src/main/java/cn/iocoder/yudao/module/museums/service/specimenoutbound/SpecimenOutboundServiceImpl.java
  46. 12 0
      yudao-module-museums/yudao-module-museums-biz/src/main/resources/mapper/museumsdocument/MuseumsDocumentMapper.xml
  47. 12 0
      yudao-module-museums/yudao-module-museums-biz/src/main/resources/mapper/photogroup/PhotoGroupMapper.xml
  48. 12 0
      yudao-module-museums/yudao-module-museums-biz/src/main/resources/mapper/photos/PhotosMapper.xml
  49. 12 0
      yudao-module-museums/yudao-module-museums-biz/src/main/resources/mapper/specimeninfo/SpecimenInfoMapper.xml
  50. 12 0
      yudao-module-museums/yudao-module-museums-biz/src/main/resources/mapper/specimenoutbound/SpecimenOutboundMapper.xml
  51. 162 0
      yudao-module-museums/yudao-module-museums-biz/src/test/java/cn/iocoder/yudao/module/museums/service/museumsdocument/MuseumsDocumentServiceImplTest.java
  52. 150 0
      yudao-module-museums/yudao-module-museums-biz/src/test/java/cn/iocoder/yudao/module/museums/service/photogroup/PhotoGroupServiceImplTest.java
  53. 142 0
      yudao-module-museums/yudao-module-museums-biz/src/test/java/cn/iocoder/yudao/module/museums/service/photos/PhotosServiceImplTest.java
  54. 234 0
      yudao-module-museums/yudao-module-museums-biz/src/test/java/cn/iocoder/yudao/module/museums/service/specimeninfo/SpecimenInfoServiceImplTest.java
  55. 198 0
      yudao-module-museums/yudao-module-museums-biz/src/test/java/cn/iocoder/yudao/module/museums/service/specimenoutbound/SpecimenOutboundServiceImplTest.java
  56. 1 0
      yudao-module-museums/yudao-module-museums-biz/src/test/resources/clean.sql
  57. 27 0
      yudao-module-museums/yudao-module-museums-biz/src/test/resources/create_tables.sql
  58. 12 0
      yudao-server/pom.xml
  59. 9 9
      yudao-server/src/main/resources/application-local.yaml

+ 5 - 0
pom.xml

@@ -16,6 +16,11 @@
         <module>yudao-module-system</module>
         <module>yudao-module-infra</module>
 <!--        <module>yudao-module-member</module>-->
+        <module>yudao-module-museums</module>
+
+<!--        <module>yudao-module-museums-api</module>-->
+<!--        <module>yudao-module-museums-biz</module>-->
+        <!--        <module>yudao-module-member</module>-->
 <!--        <module>yudao-module-bpm</module>-->
 <!--        <module>yudao-module-report</module>-->
 <!--        <module>yudao-module-mp</module>-->

+ 38 - 0
yudao-module-museums/pom.xml

@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+<!--    <modelVersion>4.0.0</modelVersion>-->
+<!--    <parent>-->
+<!--        <groupId>cn.iocoder.boot</groupId>-->
+<!--        <artifactId>yudao</artifactId>-->
+<!--        <version>2.2.0-jdk8-snapshot</version>-->
+<!--    </parent>-->
+
+<!--    <artifactId>yudao_module_museums</artifactId>-->
+
+<!--    <properties>-->
+<!--        <maven.compiler.source>22</maven.compiler.source>-->
+<!--        <maven.compiler.target>22</maven.compiler.target>-->
+<!--        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>-->
+<!--    </properties>-->
+    <parent>
+        <artifactId>yudao</artifactId>
+        <groupId>cn.iocoder.boot</groupId>
+        <version>${revision}</version>
+    </parent>
+    <modules>
+        <module>yudao-module-museums-api</module>
+        <module>yudao-module-museums-biz</module>
+
+    </modules>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>yudao-module-museums</artifactId>
+    <packaging>pom</packaging>
+
+    <name>${project.artifactId}</name>
+    <description>
+        museums模块,主要实现工作台、标本库管理、博物馆照片和文件管理等功能。
+    </description>
+</project>

+ 26 - 0
yudao-module-museums/yudao-module-museums-api/pom.xml

@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>yudao-module-museums</artifactId>
+        <groupId>cn.iocoder.boot</groupId>
+        <version>${revision}</version> <!-- 1. 修改 version 为 ${revision} -->
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+    <artifactId>yudao-module-museums-api</artifactId>
+    <packaging>jar</packaging> <!-- 2. 新增 packaging 为 jar -->
+
+    <name>${project.artifactId}</name> <!-- 3. 新增 name 为 ${project.artifactId} -->
+    <description> <!-- 4. 新增 description 为该模块的描述 -->
+        demo 模块 API,暴露给其它模块调用
+    </description>
+
+    <dependencies>  <!-- 5. 新增 yudao-common 依赖 -->
+        <dependency>
+            <groupId>cn.iocoder.boot</groupId>
+            <artifactId>yudao-common</artifactId>
+        </dependency>
+    </dependencies>
+
+</project>

+ 25 - 0
yudao-module-museums/yudao-module-museums-api/src/main/java/cn/iocoder/yudao/module/museums/enums/ErrorCodeConstants.java

@@ -0,0 +1,25 @@
+package cn.iocoder.yudao.module.museums.enums;
+
+import cn.iocoder.yudao.framework.common.exception.ErrorCode;
+
+/**
+ * Museums 错误码枚举类
+ * <p>
+ * museums 系统,使用 1-018-000-000 段
+ */
+public class ErrorCodeConstants {
+    // ========== 标本管理 1-016-000-000 ==========
+   public static final ErrorCode SPECIMEN_INFO_NOT_EXISTS = new ErrorCode(1-016-000-000, "标本管理不存在");
+
+    // ========== 标本出库回库信息 1-016-001-000 ==========
+    public static final ErrorCode SPECIMEN_OUTBOUND_NOT_EXISTS = new ErrorCode(1-016-001-000, "标本出库回库信息不存在");
+
+    // ========== 博物馆照片组 1-016-002-000 ==========
+    public static final ErrorCode PHOTO_GROUP_NOT_EXISTS = new ErrorCode(1-016-002-000, "博物馆照片组不存在");
+
+    // ========== 博物馆文件管理 1-016-003-000 ==========
+    public static final ErrorCode DOCUMENT_NOT_EXISTS = new ErrorCode(1-016-003-000, "博物馆文件管理不存在");
+
+    // ========== 博物馆照片 1-016-004-000 ==========
+    public static final ErrorCode PHOTOS_NOT_EXISTS = new ErrorCode(1-016-004-000, "博物馆照片不存在");
+}

+ 56 - 0
yudao-module-museums/yudao-module-museums-biz/pom.xml

@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>yudao-module-museums</artifactId>
+        <groupId>cn.iocoder.boot</groupId>
+        <version>${revision}</version> <!-- 1. 修改 version 为 ${revision} -->
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+    <packaging>jar</packaging> <!-- 2. 新增 packaging 为 jar -->
+
+    <artifactId>yudao-module-museums-biz</artifactId>
+
+    <name>${project.artifactId}</name> <!-- 3. 新增 name 为 ${project.artifactId} -->
+    <description> <!-- 4. 新增 description 为该模块的描述 -->
+        demo 模块,主要实现 XXX、YYY、ZZZ 等功能。
+    </description>
+
+    <dependencies>  <!-- 5. 新增依赖,这里引入的都是比较常用的业务组件、技术组件 -->
+        <dependency>
+            <groupId>cn.iocoder.boot</groupId>
+            <artifactId>yudao-module-museums-api</artifactId>
+            <version>${revision}</version>
+        </dependency>
+
+        <!-- Web 相关 -->
+        <dependency>
+            <groupId>cn.iocoder.boot</groupId>
+            <artifactId>yudao-spring-boot-starter-web</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>cn.iocoder.boot</groupId>
+            <artifactId>yudao-spring-boot-starter-security</artifactId>
+        </dependency>
+
+        <!-- DB 相关 -->
+        <dependency>
+            <groupId>cn.iocoder.boot</groupId>
+            <artifactId>yudao-spring-boot-starter-mybatis</artifactId>
+        </dependency>
+
+        <!-- Test 测试相关 -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-test</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>cn.iocoder.boot</groupId>
+            <artifactId>yudao-spring-boot-starter-excel</artifactId>
+        </dependency>
+    </dependencies>
+
+</project>

+ 95 - 0
yudao-module-museums/yudao-module-museums-biz/src/main/java/cn/iocoder/yudao/module/museums/controller/admin/museumsdocument/MuseumsDocumentController.java

@@ -0,0 +1,95 @@
+package cn.iocoder.yudao.module.museums.controller.admin.museumsdocument;
+
+import org.springframework.web.bind.annotation.*;
+import javax.annotation.Resource;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.security.access.prepost.PreAuthorize;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.Operation;
+
+import javax.validation.constraints.*;
+import javax.validation.*;
+import javax.servlet.http.*;
+import java.util.*;
+import java.io.IOException;
+
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+
+import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
+
+import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog;
+import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.*;
+
+import cn.iocoder.yudao.module.museums.controller.admin.museumsdocument.vo.*;
+import cn.iocoder.yudao.module.museums.dal.dataobject.museumsdocument.MuseumsDocumentDO;
+import cn.iocoder.yudao.module.museums.service.museumsdocument.MuseumsDocumentService;
+
+@Tag(name = "管理后台 - 博物馆文件管理")
+@RestController
+@RequestMapping("/museums/document")
+@Validated
+public class MuseumsDocumentController {
+
+    @Resource
+    private MuseumsDocumentService documentService;
+
+    @PostMapping("/create")
+    @Operation(summary = "创建博物馆文件管理")
+    @PreAuthorize("@ss.hasPermission('museums:document:create')")
+    public CommonResult<Integer> createDocument(@Valid @RequestBody MuseumsDocumentSaveReqVO createReqVO) {
+        return success(documentService.createDocument(createReqVO));
+    }
+
+    @PutMapping("/update")
+    @Operation(summary = "更新博物馆文件管理")
+    @PreAuthorize("@ss.hasPermission('museums:document:update')")
+    public CommonResult<Boolean> updateDocument(@Valid @RequestBody MuseumsDocumentSaveReqVO updateReqVO) {
+        documentService.updateDocument(updateReqVO);
+        return success(true);
+    }
+
+    @DeleteMapping("/delete")
+    @Operation(summary = "删除博物馆文件管理")
+    @Parameter(name = "id", description = "编号", required = true)
+    @PreAuthorize("@ss.hasPermission('museums:document:delete')")
+    public CommonResult<Boolean> deleteDocument(@RequestParam("id") Integer id) {
+        documentService.deleteDocument(id);
+        return success(true);
+    }
+
+    @GetMapping("/get")
+    @Operation(summary = "获得博物馆文件管理")
+    @Parameter(name = "id", description = "编号", required = true, example = "1024")
+    @PreAuthorize("@ss.hasPermission('museums:document:query')")
+    public CommonResult<MuseumsDocumentRespVO> getDocument(@RequestParam("id") Integer id) {
+        MuseumsDocumentDO document = documentService.getDocument(id);
+        return success(BeanUtils.toBean(document, MuseumsDocumentRespVO.class));
+    }
+
+    @GetMapping("/page")
+    @Operation(summary = "获得博物馆文件管理分页")
+    @PreAuthorize("@ss.hasPermission('museums:document:query')")
+    public CommonResult<PageResult<MuseumsDocumentRespVO>> getDocumentPage(@Valid MuseumsDocumentPageReqVO pageReqVO) {
+        PageResult<MuseumsDocumentDO> pageResult = documentService.getDocumentPage(pageReqVO);
+        return success(BeanUtils.toBean(pageResult, MuseumsDocumentRespVO.class));
+    }
+
+    @GetMapping("/export-excel")
+    @Operation(summary = "导出博物馆文件管理 Excel")
+    @PreAuthorize("@ss.hasPermission('museums:document:export')")
+    @ApiAccessLog(operateType = EXPORT)
+    public void exportDocumentExcel(@Valid MuseumsDocumentPageReqVO pageReqVO,
+              HttpServletResponse response) throws IOException {
+        pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
+        List<MuseumsDocumentDO> list = documentService.getDocumentPage(pageReqVO).getList();
+        // 导出 Excel
+        ExcelUtils.write(response, "博物馆文件管理.xls", "数据", MuseumsDocumentRespVO.class,
+                        BeanUtils.toBean(list, MuseumsDocumentRespVO.class));
+    }
+
+}

+ 47 - 0
yudao-module-museums/yudao-module-museums-biz/src/main/java/cn/iocoder/yudao/module/museums/controller/admin/museumsdocument/vo/MuseumsDocumentPageReqVO.java

@@ -0,0 +1,47 @@
+package cn.iocoder.yudao.module.museums.controller.admin.museumsdocument.vo;
+
+import lombok.*;
+import java.util.*;
+import io.swagger.v3.oas.annotations.media.Schema;
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import org.springframework.format.annotation.DateTimeFormat;
+import java.time.LocalDateTime;
+
+import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
+
+@Schema(description = "管理后台 - 博物馆文件管理分页 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class MuseumsDocumentPageReqVO extends PageParam {
+
+    @Schema(description = "文件名称", example = "赵六")
+    private String fileName;
+
+    @Schema(description = "配置编号", example = "5723")
+    private Integer configId;
+
+    @Schema(description = "路径")
+    private String path;
+
+    @Schema(description = "文件 URL", example = "https://www.iocoder.cn")
+    private String url;
+
+    @Schema(description = "文件大小(字节)")
+    private Integer fileSize;
+
+    @Schema(description = "文件类型", example = "1")
+    private String fileType;
+
+    @Schema(description = "上传时间")
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    private LocalDateTime[] uploadDate;
+
+    @Schema(description = "上传者")
+    private String uploadedBy;
+
+    @Schema(description = "创建时间")
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    private LocalDateTime[] createTime;
+
+}

+ 55 - 0
yudao-module-museums/yudao-module-museums-biz/src/main/java/cn/iocoder/yudao/module/museums/controller/admin/museumsdocument/vo/MuseumsDocumentRespVO.java

@@ -0,0 +1,55 @@
+package cn.iocoder.yudao.module.museums.controller.admin.museumsdocument.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.*;
+import java.util.*;
+import org.springframework.format.annotation.DateTimeFormat;
+import java.time.LocalDateTime;
+import com.alibaba.excel.annotation.*;
+
+@Schema(description = "管理后台 - 博物馆文件管理 Response VO")
+@Data
+@ExcelIgnoreUnannotated
+public class MuseumsDocumentRespVO {
+
+    @Schema(description = "主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "31768")
+    @ExcelProperty("主键")
+    private Integer id;
+
+    @Schema(description = "文件名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "赵六")
+    @ExcelProperty("文件名称")
+    private String fileName;
+
+    @Schema(description = "配置编号", example = "5723")
+    @ExcelProperty("配置编号")
+    private Integer configId;
+
+    @Schema(description = "路径", requiredMode = Schema.RequiredMode.REQUIRED)
+    @ExcelProperty("路径")
+    private String path;
+
+    @Schema(description = "文件 URL", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn")
+    @ExcelProperty("文件 URL")
+    private String url;
+
+    @Schema(description = "文件大小(字节)", requiredMode = Schema.RequiredMode.REQUIRED)
+    @ExcelProperty("文件大小(字节)")
+    private Integer fileSize;
+
+    @Schema(description = "文件类型", example = "1")
+    @ExcelProperty("文件类型")
+    private String fileType;
+
+    @Schema(description = "上传时间")
+    @ExcelProperty("上传时间")
+    private LocalDateTime uploadDate;
+
+    @Schema(description = "上传者", requiredMode = Schema.RequiredMode.REQUIRED)
+    @ExcelProperty("上传者")
+    private String uploadedBy;
+
+    @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
+    @ExcelProperty("创建时间")
+    private LocalDateTime createTime;
+
+}

+ 46 - 0
yudao-module-museums/yudao-module-museums-biz/src/main/java/cn/iocoder/yudao/module/museums/controller/admin/museumsdocument/vo/MuseumsDocumentSaveReqVO.java

@@ -0,0 +1,46 @@
+package cn.iocoder.yudao.module.museums.controller.admin.museumsdocument.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.*;
+import java.util.*;
+import javax.validation.constraints.*;
+import org.springframework.format.annotation.DateTimeFormat;
+import java.time.LocalDateTime;
+
+@Schema(description = "管理后台 - 博物馆文件管理新增/修改 Request VO")
+@Data
+public class MuseumsDocumentSaveReqVO {
+
+    @Schema(description = "主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "31768")
+    private Integer id;
+
+    @Schema(description = "文件名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "赵六")
+    @NotEmpty(message = "文件名称不能为空")
+    private String fileName;
+
+    @Schema(description = "配置编号", example = "5723")
+    private Integer configId;
+
+    @Schema(description = "路径", requiredMode = Schema.RequiredMode.REQUIRED)
+    @NotEmpty(message = "路径不能为空")
+    private String path;
+
+    @Schema(description = "文件 URL", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn")
+    @NotEmpty(message = "文件 URL不能为空")
+    private String url;
+
+    @Schema(description = "文件大小(字节)", requiredMode = Schema.RequiredMode.REQUIRED)
+    @NotNull(message = "文件大小(字节)不能为空")
+    private Integer fileSize;
+
+    @Schema(description = "文件类型", example = "1")
+    private String fileType;
+
+    @Schema(description = "上传时间")
+    private LocalDateTime uploadDate;
+
+    @Schema(description = "上传者", requiredMode = Schema.RequiredMode.REQUIRED)
+    @NotEmpty(message = "上传者不能为空")
+    private String uploadedBy;
+
+}

+ 95 - 0
yudao-module-museums/yudao-module-museums-biz/src/main/java/cn/iocoder/yudao/module/museums/controller/admin/photogroup/PhotoGroupController.java

@@ -0,0 +1,95 @@
+package cn.iocoder.yudao.module.museums.controller.admin.photogroup;
+
+import org.springframework.web.bind.annotation.*;
+import javax.annotation.Resource;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.security.access.prepost.PreAuthorize;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.Operation;
+
+import javax.validation.constraints.*;
+import javax.validation.*;
+import javax.servlet.http.*;
+import java.util.*;
+import java.io.IOException;
+
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+
+import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
+
+import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog;
+import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.*;
+
+import cn.iocoder.yudao.module.museums.controller.admin.photogroup.vo.*;
+import cn.iocoder.yudao.module.museums.dal.dataobject.photogroup.PhotoGroupDO;
+import cn.iocoder.yudao.module.museums.service.photogroup.PhotoGroupService;
+
+@Tag(name = "管理后台 - 博物馆照片组")
+@RestController
+@RequestMapping("/museums/photo-group")
+@Validated
+public class PhotoGroupController {
+
+    @Resource
+    private PhotoGroupService photoGroupService;
+
+    @PostMapping("/create")
+    @Operation(summary = "创建博物馆照片组")
+    @PreAuthorize("@ss.hasPermission('museums:photo-group:create')")
+    public CommonResult<Integer> createPhotoGroup(@Valid @RequestBody PhotoGroupSaveReqVO createReqVO) {
+        return success(photoGroupService.createPhotoGroup(createReqVO));
+    }
+
+    @PutMapping("/update")
+    @Operation(summary = "更新博物馆照片组")
+    @PreAuthorize("@ss.hasPermission('museums:photo-group:update')")
+    public CommonResult<Boolean> updatePhotoGroup(@Valid @RequestBody PhotoGroupSaveReqVO updateReqVO) {
+        photoGroupService.updatePhotoGroup(updateReqVO);
+        return success(true);
+    }
+
+    @DeleteMapping("/delete")
+    @Operation(summary = "删除博物馆照片组")
+    @Parameter(name = "id", description = "编号", required = true)
+    @PreAuthorize("@ss.hasPermission('museums:photo-group:delete')")
+    public CommonResult<Boolean> deletePhotoGroup(@RequestParam("id") Integer id) {
+        photoGroupService.deletePhotoGroup(id);
+        return success(true);
+    }
+
+    @GetMapping("/get")
+    @Operation(summary = "获得博物馆照片组")
+    @Parameter(name = "id", description = "编号", required = true, example = "1024")
+    @PreAuthorize("@ss.hasPermission('museums:photo-group:query')")
+    public CommonResult<PhotoGroupRespVO> getPhotoGroup(@RequestParam("id") Integer id) {
+        PhotoGroupDO photoGroup = photoGroupService.getPhotoGroup(id);
+        return success(BeanUtils.toBean(photoGroup, PhotoGroupRespVO.class));
+    }
+
+    @GetMapping("/page")
+    @Operation(summary = "获得博物馆照片组分页")
+    @PreAuthorize("@ss.hasPermission('museums:photo-group:query')")
+    public CommonResult<PageResult<PhotoGroupRespVO>> getPhotoGroupPage(@Valid PhotoGroupPageReqVO pageReqVO) {
+        PageResult<PhotoGroupDO> pageResult = photoGroupService.getPhotoGroupPage(pageReqVO);
+        return success(BeanUtils.toBean(pageResult, PhotoGroupRespVO.class));
+    }
+
+    @GetMapping("/export-excel")
+    @Operation(summary = "导出博物馆照片组 Excel")
+    @PreAuthorize("@ss.hasPermission('museums:photo-group:export')")
+    @ApiAccessLog(operateType = EXPORT)
+    public void exportPhotoGroupExcel(@Valid PhotoGroupPageReqVO pageReqVO,
+              HttpServletResponse response) throws IOException {
+        pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
+        List<PhotoGroupDO> list = photoGroupService.getPhotoGroupPage(pageReqVO).getList();
+        // 导出 Excel
+        ExcelUtils.write(response, "博物馆照片组.xls", "数据", PhotoGroupRespVO.class,
+                        BeanUtils.toBean(list, PhotoGroupRespVO.class));
+    }
+
+}

+ 38 - 0
yudao-module-museums/yudao-module-museums-biz/src/main/java/cn/iocoder/yudao/module/museums/controller/admin/photogroup/vo/PhotoGroupPageReqVO.java

@@ -0,0 +1,38 @@
+package cn.iocoder.yudao.module.museums.controller.admin.photogroup.vo;
+
+import lombok.*;
+import java.util.*;
+import io.swagger.v3.oas.annotations.media.Schema;
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import org.springframework.format.annotation.DateTimeFormat;
+import java.time.LocalDateTime;
+
+import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
+
+@Schema(description = "管理后台 - 博物馆照片组分页 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class PhotoGroupPageReqVO extends PageParam {
+
+    @Schema(description = "照片组名称", example = "赵六")
+    private String groupName;
+
+    @Schema(description = "照片组时间")
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    private LocalDateTime[] groupDate;
+
+    @Schema(description = "照片组简介", example = "你说的对")
+    private String groupDescription;
+
+    @Schema(description = "创建时间")
+    private LocalDateTime createdAt;
+
+    @Schema(description = "创建时间")
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    private LocalDateTime[] createTime;
+
+    @Schema(description = "照片组上传")
+    private String uploadPhotos;
+
+}

+ 43 - 0
yudao-module-museums/yudao-module-museums-biz/src/main/java/cn/iocoder/yudao/module/museums/controller/admin/photogroup/vo/PhotoGroupRespVO.java

@@ -0,0 +1,43 @@
+package cn.iocoder.yudao.module.museums.controller.admin.photogroup.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.*;
+import java.util.*;
+import org.springframework.format.annotation.DateTimeFormat;
+import java.time.LocalDateTime;
+import com.alibaba.excel.annotation.*;
+
+@Schema(description = "管理后台 - 博物馆照片组 Response VO")
+@Data
+@ExcelIgnoreUnannotated
+public class PhotoGroupRespVO {
+
+    @Schema(description = "主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "24373")
+    @ExcelProperty("主键")
+    private Integer id;
+
+    @Schema(description = "照片组名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "赵六")
+    @ExcelProperty("照片组名称")
+    private String groupName;
+
+    @Schema(description = "照片组时间", requiredMode = Schema.RequiredMode.REQUIRED)
+    @ExcelProperty("照片组时间")
+    private LocalDateTime groupDate;
+
+    @Schema(description = "照片组简介", example = "你说的对")
+    @ExcelProperty("照片组简介")
+    private String groupDescription;
+
+    @Schema(description = "创建时间")
+    @ExcelProperty("创建时间")
+    private LocalDateTime createdAt;
+
+    @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
+    @ExcelProperty("创建时间")
+    private LocalDateTime createTime;
+
+    @Schema(description = "照片组上传")
+    @ExcelProperty("照片组上传")
+    private String uploadPhotos;
+
+}

+ 34 - 0
yudao-module-museums/yudao-module-museums-biz/src/main/java/cn/iocoder/yudao/module/museums/controller/admin/photogroup/vo/PhotoGroupSaveReqVO.java

@@ -0,0 +1,34 @@
+package cn.iocoder.yudao.module.museums.controller.admin.photogroup.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.*;
+import java.util.*;
+import javax.validation.constraints.*;
+import org.springframework.format.annotation.DateTimeFormat;
+import java.time.LocalDateTime;
+
+@Schema(description = "管理后台 - 博物馆照片组新增/修改 Request VO")
+@Data
+public class PhotoGroupSaveReqVO {
+
+    @Schema(description = "主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "24373")
+    private Integer id;
+
+    @Schema(description = "照片组名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "赵六")
+    @NotEmpty(message = "照片组名称不能为空")
+    private String groupName;
+
+    @Schema(description = "照片组时间", requiredMode = Schema.RequiredMode.REQUIRED)
+    @NotNull(message = "照片组时间不能为空")
+    private LocalDateTime groupDate;
+
+    @Schema(description = "照片组简介", example = "你说的对")
+    private String groupDescription;
+
+    @Schema(description = "创建时间")
+    private LocalDateTime createdAt;
+
+    @Schema(description = "照片组上传")
+    private List<String> uploadPhotos;
+
+}

+ 95 - 0
yudao-module-museums/yudao-module-museums-biz/src/main/java/cn/iocoder/yudao/module/museums/controller/admin/photos/PhotosController.java

@@ -0,0 +1,95 @@
+package cn.iocoder.yudao.module.museums.controller.admin.photos;
+
+import org.springframework.web.bind.annotation.*;
+import javax.annotation.Resource;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.security.access.prepost.PreAuthorize;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.Operation;
+
+import javax.validation.constraints.*;
+import javax.validation.*;
+import javax.servlet.http.*;
+import java.util.*;
+import java.io.IOException;
+
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+
+import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
+
+import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog;
+import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.*;
+
+import cn.iocoder.yudao.module.museums.controller.admin.photos.vo.*;
+import cn.iocoder.yudao.module.museums.dal.dataobject.photos.PhotosDO;
+import cn.iocoder.yudao.module.museums.service.photos.PhotosService;
+
+@Tag(name = "管理后台 - 博物馆照片")
+@RestController
+@RequestMapping("/museums/photos")
+@Validated
+public class PhotosController {
+
+    @Resource
+    private PhotosService photosService;
+
+    @PostMapping("/create")
+    @Operation(summary = "创建博物馆照片")
+    @PreAuthorize("@ss.hasPermission('museums:photos:create')")
+    public CommonResult<Integer> createPhotos(@Valid @RequestBody PhotosSaveReqVO createReqVO) {
+        return success(photosService.createPhotos(createReqVO));
+    }
+
+    @PutMapping("/update")
+    @Operation(summary = "更新博物馆照片")
+    @PreAuthorize("@ss.hasPermission('museums:photos:update')")
+    public CommonResult<Boolean> updatePhotos(@Valid @RequestBody PhotosSaveReqVO updateReqVO) {
+        photosService.updatePhotos(updateReqVO);
+        return success(true);
+    }
+
+    @DeleteMapping("/delete")
+    @Operation(summary = "删除博物馆照片")
+    @Parameter(name = "id", description = "编号", required = true)
+    @PreAuthorize("@ss.hasPermission('museums:photos:delete')")
+    public CommonResult<Boolean> deletePhotos(@RequestParam("id") Integer id) {
+        photosService.deletePhotos(id);
+        return success(true);
+    }
+
+    @GetMapping("/get")
+    @Operation(summary = "获得博物馆照片")
+    @Parameter(name = "id", description = "编号", required = true, example = "1024")
+    @PreAuthorize("@ss.hasPermission('museums:photos:query')")
+    public CommonResult<PhotosRespVO> getPhotos(@RequestParam("id") Integer id) {
+        PhotosDO photos = photosService.getPhotos(id);
+        return success(BeanUtils.toBean(photos, PhotosRespVO.class));
+    }
+
+    @GetMapping("/page")
+    @Operation(summary = "获得博物馆照片分页")
+    @PreAuthorize("@ss.hasPermission('museums:photos:query')")
+    public CommonResult<PageResult<PhotosRespVO>> getPhotosPage(@Valid PhotosPageReqVO pageReqVO) {
+        PageResult<PhotosDO> pageResult = photosService.getPhotosPage(pageReqVO);
+        return success(BeanUtils.toBean(pageResult, PhotosRespVO.class));
+    }
+
+    @GetMapping("/export-excel")
+    @Operation(summary = "导出博物馆照片 Excel")
+    @PreAuthorize("@ss.hasPermission('museums:photos:export')")
+    @ApiAccessLog(operateType = EXPORT)
+    public void exportPhotosExcel(@Valid PhotosPageReqVO pageReqVO,
+              HttpServletResponse response) throws IOException {
+        pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
+        List<PhotosDO> list = photosService.getPhotosPage(pageReqVO).getList();
+        // 导出 Excel
+        ExcelUtils.write(response, "博物馆照片.xls", "数据", PhotosRespVO.class,
+                        BeanUtils.toBean(list, PhotosRespVO.class));
+    }
+
+}

+ 31 - 0
yudao-module-museums/yudao-module-museums-biz/src/main/java/cn/iocoder/yudao/module/museums/controller/admin/photos/vo/PhotosPageReqVO.java

@@ -0,0 +1,31 @@
+package cn.iocoder.yudao.module.museums.controller.admin.photos.vo;
+
+import lombok.*;
+import java.util.*;
+import io.swagger.v3.oas.annotations.media.Schema;
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import org.springframework.format.annotation.DateTimeFormat;
+import java.time.LocalDateTime;
+
+import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
+
+@Schema(description = "管理后台 - 博物馆照片分页 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class PhotosPageReqVO extends PageParam {
+
+    @Schema(description = "照片组表id", example = "5803")
+    private Integer groupId;
+
+    @Schema(description = "照片存储路径", example = "https://www.iocoder.cn")
+    private String photoUrl;
+
+    @Schema(description = "上传时间")
+    private LocalDateTime createdAt;
+
+    @Schema(description = "创建时间")
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    private LocalDateTime[] createTime;
+
+}

+ 35 - 0
yudao-module-museums/yudao-module-museums-biz/src/main/java/cn/iocoder/yudao/module/museums/controller/admin/photos/vo/PhotosRespVO.java

@@ -0,0 +1,35 @@
+package cn.iocoder.yudao.module.museums.controller.admin.photos.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.*;
+import java.util.*;
+import org.springframework.format.annotation.DateTimeFormat;
+import java.time.LocalDateTime;
+import com.alibaba.excel.annotation.*;
+
+@Schema(description = "管理后台 - 博物馆照片 Response VO")
+@Data
+@ExcelIgnoreUnannotated
+public class PhotosRespVO {
+
+    @Schema(description = "主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "29516")
+    @ExcelProperty("主键")
+    private Integer id;
+
+    @Schema(description = "照片组表id", requiredMode = Schema.RequiredMode.REQUIRED, example = "5803")
+    @ExcelProperty("照片组表id")
+    private Integer groupId;
+
+    @Schema(description = "照片存储路径", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn")
+    @ExcelProperty("照片存储路径")
+    private String photoUrl;
+
+    @Schema(description = "上传时间")
+    @ExcelProperty("上传时间")
+    private LocalDateTime createdAt;
+
+    @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
+    @ExcelProperty("创建时间")
+    private LocalDateTime createTime;
+
+}

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

@@ -0,0 +1,28 @@
+package cn.iocoder.yudao.module.museums.controller.admin.photos.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.*;
+import java.util.*;
+import javax.validation.constraints.*;
+import org.springframework.format.annotation.DateTimeFormat;
+import java.time.LocalDateTime;
+
+@Schema(description = "管理后台 - 博物馆照片新增/修改 Request VO")
+@Data
+public class PhotosSaveReqVO {
+
+    @Schema(description = "主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "29516")
+    private Integer id;
+
+    @Schema(description = "照片组表id", requiredMode = Schema.RequiredMode.REQUIRED, example = "5803")
+    @NotNull(message = "照片组表id不能为空")
+    private Integer groupId;
+
+    @Schema(description = "照片存储路径", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn")
+    @NotEmpty(message = "照片存储路径不能为空")
+    private String photoUrl;
+
+    @Schema(description = "上传时间")
+    private LocalDateTime createdAt;
+
+}

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

@@ -0,0 +1,95 @@
+package cn.iocoder.yudao.module.museums.controller.admin.specimeninfo;
+
+import org.springframework.web.bind.annotation.*;
+import javax.annotation.Resource;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.security.access.prepost.PreAuthorize;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.Operation;
+
+import javax.validation.constraints.*;
+import javax.validation.*;
+import javax.servlet.http.*;
+import java.util.*;
+import java.io.IOException;
+
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+
+import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
+
+import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog;
+import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.*;
+
+import cn.iocoder.yudao.module.museums.controller.admin.specimeninfo.vo.*;
+import cn.iocoder.yudao.module.museums.dal.dataobject.specimeninfo.SpecimenInfoDO;
+import cn.iocoder.yudao.module.museums.service.specimeninfo.SpecimenInfoService;
+
+@Tag(name = "管理后台 - 标本管理")
+@RestController
+@RequestMapping("/museums/specimen-info")
+@Validated
+public class SpecimenInfoController {
+
+    @Resource
+    private SpecimenInfoService specimenInfoService;
+
+    @PostMapping("/create")
+    @Operation(summary = "创建标本管理")
+    @PreAuthorize("@ss.hasPermission('museums:specimen-info:create')")
+    public CommonResult<Integer> createSpecimenInfo(@Valid @RequestBody SpecimenInfoSaveReqVO createReqVO) {
+        return success(specimenInfoService.createSpecimenInfo(createReqVO));
+    }
+
+    @PutMapping("/update")
+    @Operation(summary = "更新标本管理")
+    @PreAuthorize("@ss.hasPermission('museums:specimen-info:update')")
+    public CommonResult<Boolean> updateSpecimenInfo(@Valid @RequestBody SpecimenInfoSaveReqVO updateReqVO) {
+        specimenInfoService.updateSpecimenInfo(updateReqVO);
+        return success(true);
+    }
+
+    @DeleteMapping("/delete")
+    @Operation(summary = "删除标本管理")
+    @Parameter(name = "id", description = "编号", required = true)
+    @PreAuthorize("@ss.hasPermission('museums:specimen-info:delete')")
+    public CommonResult<Boolean> deleteSpecimenInfo(@RequestParam("id") Integer id) {
+        specimenInfoService.deleteSpecimenInfo(id);
+        return success(true);
+    }
+
+    @GetMapping("/get")
+    @Operation(summary = "获得标本管理")
+    @Parameter(name = "id", description = "编号", required = true, example = "1024")
+    @PreAuthorize("@ss.hasPermission('museums:specimen-info:query')")
+    public CommonResult<SpecimenInfoRespVO> getSpecimenInfo(@RequestParam("id") Integer id) {
+        SpecimenInfoDO specimenInfo = specimenInfoService.getSpecimenInfo(id);
+        return success(BeanUtils.toBean(specimenInfo, SpecimenInfoRespVO.class));
+    }
+
+    @GetMapping("/page")
+    @Operation(summary = "获得标本管理分页")
+    @PreAuthorize("@ss.hasPermission('museums:specimen-info:query')")
+    public CommonResult<PageResult<SpecimenInfoRespVO>> getSpecimenInfoPage(@Valid SpecimenInfoPageReqVO pageReqVO) {
+        PageResult<SpecimenInfoDO> pageResult = specimenInfoService.getSpecimenInfoPage(pageReqVO);
+        return success(BeanUtils.toBean(pageResult, SpecimenInfoRespVO.class));
+    }
+
+    @GetMapping("/export-excel")
+    @Operation(summary = "导出标本管理 Excel")
+    @PreAuthorize("@ss.hasPermission('museums:specimen-info:export')")
+    @ApiAccessLog(operateType = EXPORT)
+    public void exportSpecimenInfoExcel(@Valid SpecimenInfoPageReqVO pageReqVO,
+              HttpServletResponse response) throws IOException {
+        pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
+        List<SpecimenInfoDO> list = specimenInfoService.getSpecimenInfoPage(pageReqVO).getList();
+        // 导出 Excel
+        ExcelUtils.write(response, "标本管理.xls", "数据", SpecimenInfoRespVO.class,
+                        BeanUtils.toBean(list, SpecimenInfoRespVO.class));
+    }
+
+}

+ 116 - 0
yudao-module-museums/yudao-module-museums-biz/src/main/java/cn/iocoder/yudao/module/museums/controller/admin/specimeninfo/vo/SpecimenInfoPageReqVO.java

@@ -0,0 +1,116 @@
+package cn.iocoder.yudao.module.museums.controller.admin.specimeninfo.vo;
+
+import lombok.*;
+
+import java.time.LocalDate;
+import java.util.*;
+import io.swagger.v3.oas.annotations.media.Schema;
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import java.math.BigDecimal;
+import org.springframework.format.annotation.DateTimeFormat;
+import java.time.LocalDateTime;
+
+import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
+
+@Schema(description = "管理后台 - 标本管理分页 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class SpecimenInfoPageReqVO extends PageParam {
+
+    @Schema(description = "标本类型(矿物、岩石矿石、化石、陨石)", example = "1")
+    private Integer specimenType;
+
+    @Schema(description = "标本编号")
+    private String specimenNumber;
+
+    @Schema(description = "资产号")
+    private String assetNumber;
+
+    @Schema(description = "存放位置")
+    private String storageLocation;
+
+    @Schema(description = "中文名称", example = "赵六")
+    private String chineseName;
+
+    @Schema(description = "英文名称", example = "Maven")
+    private String englishName;
+
+    @Schema(description = "成分")
+    private String composition;
+
+    @Schema(description = "产地")
+    private String origin;
+
+    @Schema(description = "时代")
+    private String era;
+
+    @Schema(description = "保存地层")
+    private String preservedLayer;
+
+    @Schema(description = "陨石类型", example = "2")
+    private String meteoriteType;
+
+    @Schema(description = "国际命名", example = "王五")
+    private String internationalName;
+
+    @Schema(description = "发现时间")
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    private LocalDate[] discoveryTime;
+
+    @Schema(description = "降落时间")
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    private LocalDate[] fallTime;
+
+    @Schema(description = "保存类型(标本、光片、薄片模型及其他)", example = "1")
+    private Integer preservationType;
+
+    @Schema(description = "尺寸")
+    private String size;
+
+    @Schema(description = "重量")
+    private BigDecimal weight;
+
+    @Schema(description = "来源(采购、捐赠、采集)")
+    private Integer source;
+
+    @Schema(description = "标本提供者(供应商、捐赠人、采集人)")
+    private String provider;
+
+    @Schema(description = "入藏时间(购买、捐赠、采集时间)")
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    private LocalDate[] acquisitionTime;
+
+    @Schema(description = "用途")
+    private String purpose;
+
+    @Schema(description = "描述", example = "黑红色陨石")
+    private String description;
+
+    @Schema(description = "馆藏状态(在馆、借出)", example = "2")
+    private Integer collectionStatus;
+
+    @Schema(description = "备注")
+    private String notes;
+
+    @Schema(description = "图片名称", example = "芋艿")
+    private String imageName;
+
+    @Schema(description = "图片路径")
+    private String imagePath;
+
+    @Schema(description = "创建时间")
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    private LocalDate[] createTime;
+
+    @Schema(description = "注销原因", example = "不香")
+    private String deletedReason;
+
+    @Schema(description = "入库操作员")
+    private String operator;
+
+    @Schema(description = "入库时间")
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    private LocalDateTime[] entryDate;
+
+}

+ 142 - 0
yudao-module-museums/yudao-module-museums-biz/src/main/java/cn/iocoder/yudao/module/museums/controller/admin/specimeninfo/vo/SpecimenInfoRespVO.java

@@ -0,0 +1,142 @@
+package cn.iocoder.yudao.module.museums.controller.admin.specimeninfo.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.*;
+
+import java.time.LocalDate;
+import java.util.*;
+import java.math.BigDecimal;
+import org.springframework.format.annotation.DateTimeFormat;
+import java.time.LocalDateTime;
+import com.alibaba.excel.annotation.*;
+
+@Schema(description = "管理后台 - 标本管理 Response VO")
+@Data
+@ExcelIgnoreUnannotated
+public class SpecimenInfoRespVO {
+
+    @Schema(description = "主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+    @ExcelProperty("主键")
+    private Integer id;
+
+    @Schema(description = "标本类型(矿物、岩石矿石、化石、陨石)", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+    @ExcelProperty("标本类型(矿物、岩石矿石、化石、陨石)")
+    private Integer specimenType;
+
+    @Schema(description = "标本编号", requiredMode = Schema.RequiredMode.REQUIRED)
+    @ExcelProperty("标本编号")
+    private String specimenNumber;
+
+    @Schema(description = "资产号")
+    @ExcelProperty("资产号")
+    private String assetNumber;
+
+    @Schema(description = "存放位置")
+    @ExcelProperty("存放位置")
+    private String storageLocation;
+
+    @Schema(description = "中文名称", example = "赵六")
+    @ExcelProperty("中文名称")
+    private String chineseName;
+
+    @Schema(description = "英文名称", example = "Maven")
+    @ExcelProperty("英文名称")
+    private String englishName;
+
+    @Schema(description = "成分")
+    @ExcelProperty("成分")
+    private String composition;
+
+    @Schema(description = "产地")
+    @ExcelProperty("产地")
+    private String origin;
+
+    @Schema(description = "时代")
+    @ExcelProperty("时代")
+    private String era;
+
+    @Schema(description = "保存地层")
+    @ExcelProperty("保存地层")
+    private String preservedLayer;
+
+    @Schema(description = "陨石类型", example = "2")
+    @ExcelProperty("陨石类型")
+    private String meteoriteType;
+
+    @Schema(description = "国际命名", example = "王五")
+    @ExcelProperty("国际命名")
+    private String internationalName;
+
+    @Schema(description = "发现时间")
+    @ExcelProperty("发现时间")
+    private LocalDate discoveryTime;
+
+    @Schema(description = "降落时间")
+    @ExcelProperty("降落时间")
+    private LocalDate fallTime;
+
+    @Schema(description = "保存类型(标本、光片、薄片模型及其他)", example = "1")
+    @ExcelProperty("保存类型(标本、光片、薄片模型及其他)")
+    private Integer preservationType;
+
+    @Schema(description = "尺寸")
+    @ExcelProperty("尺寸")
+    private String size;
+
+    @Schema(description = "重量")
+    @ExcelProperty("重量")
+    private BigDecimal weight;
+
+    @Schema(description = "来源(采购、捐赠、采集)")
+    @ExcelProperty("来源(采购、捐赠、采集)")
+    private Integer source;
+
+    @Schema(description = "标本提供者(供应商、捐赠人、采集人)")
+    @ExcelProperty("标本提供者(供应商、捐赠人、采集人)")
+    private String provider;
+
+    @Schema(description = "入藏时间(购买、捐赠、采集时间)")
+    @ExcelProperty("入藏时间(购买、捐赠、采集时间)")
+    private LocalDate acquisitionTime;
+
+    @Schema(description = "用途")
+    @ExcelProperty("用途")
+    private String purpose;
+
+    @Schema(description = "描述", example = "黑红色陨石")
+    @ExcelProperty("描述")
+    private String description;
+
+    @Schema(description = "馆藏状态(在馆、借出)", example = "2")
+    @ExcelProperty("馆藏状态(在馆、借出)")
+    private Integer collectionStatus;
+
+    @Schema(description = "备注")
+    @ExcelProperty("备注")
+    private String notes;
+
+    @Schema(description = "图片名称", example = "芋艿")
+    @ExcelProperty("图片名称")
+    private String imageName;
+
+    @Schema(description = "图片路径")
+    @ExcelProperty("图片路径")
+    private String imagePath;
+
+    @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
+    @ExcelProperty("创建时间")
+    private LocalDate createTime;
+
+    @Schema(description = "注销原因", example = "不香")
+    @ExcelProperty("注销原因")
+    private String deletedReason;
+
+    @Schema(description = "入库操作员")
+    @ExcelProperty("入库操作员")
+    private String operator;
+
+    @Schema(description = "入库时间")
+    @ExcelProperty("入库时间")
+    private LocalDateTime entryDate;
+
+}

+ 109 - 0
yudao-module-museums/yudao-module-museums-biz/src/main/java/cn/iocoder/yudao/module/museums/controller/admin/specimeninfo/vo/SpecimenInfoSaveReqVO.java

@@ -0,0 +1,109 @@
+package cn.iocoder.yudao.module.museums.controller.admin.specimeninfo.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.*;
+
+import java.time.LocalDate;
+import java.util.*;
+import javax.validation.constraints.*;
+import java.math.BigDecimal;
+import org.springframework.format.annotation.DateTimeFormat;
+import java.time.LocalDateTime;
+
+@Schema(description = "管理后台 - 标本管理新增/修改 Request VO")
+@Data
+public class SpecimenInfoSaveReqVO {
+
+    @Schema(description = "主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+    private Integer id;
+
+    @Schema(description = "标本类型(矿物、岩石矿石、化石、陨石)", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+    @NotNull(message = "标本类型(矿物、岩石矿石、化石、陨石)不能为空")
+    private Integer specimenType;
+
+    @Schema(description = "标本编号", requiredMode = Schema.RequiredMode.REQUIRED)
+    @NotEmpty(message = "标本编号不能为空")
+    private String specimenNumber;
+
+    @Schema(description = "资产号")
+    private String assetNumber;
+
+    @Schema(description = "存放位置")
+    private String storageLocation;
+
+    @Schema(description = "中文名称", example = "赵六")
+    private String chineseName;
+
+    @Schema(description = "英文名称", example = "Maven")
+    private String englishName;
+
+    @Schema(description = "成分")
+    private String composition;
+
+    @Schema(description = "产地")
+    private String origin;
+
+    @Schema(description = "时代")
+    private String era;
+
+    @Schema(description = "保存地层")
+    private String preservedLayer;
+
+    @Schema(description = "陨石类型", example = "2")
+    private String meteoriteType;
+
+    @Schema(description = "国际命名", example = "王五")
+    private String internationalName;
+
+    @Schema(description = "发现时间")
+    private LocalDate discoveryTime;
+
+    @Schema(description = "降落时间")
+    private LocalDate fallTime;
+
+    @Schema(description = "保存类型(标本、光片、薄片模型及其他)", example = "1")
+    private Integer preservationType;
+
+    @Schema(description = "尺寸")
+    private String size;
+
+    @Schema(description = "重量")
+    private BigDecimal weight;
+
+    @Schema(description = "来源(采购、捐赠、采集)")
+    private Integer source;
+
+    @Schema(description = "标本提供者(供应商、捐赠人、采集人)")
+    private String provider;
+
+    @Schema(description = "入藏时间(购买、捐赠、采集时间)")
+    private LocalDate acquisitionTime;
+
+    @Schema(description = "用途")
+    private String purpose;
+
+    @Schema(description = "描述", example = "黑红色陨石")
+    private String description;
+
+    @Schema(description = "馆藏状态(在馆、借出)", example = "2")
+    private Integer collectionStatus;
+
+    @Schema(description = "备注")
+    private String notes;
+
+    @Schema(description = "图片名称", example = "芋艿")
+    private String imageName;
+
+    @Schema(description = "图片路径")
+    private String imagePath;
+
+    @Schema(description = "注销原因", example = "不香")
+    private String deletedReason;
+
+    @Schema(description = "入库操作员")
+    private String operator;
+
+    @Schema(description = "入库时间")
+    private LocalDateTime entryDate;
+
+}

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

@@ -0,0 +1,95 @@
+package cn.iocoder.yudao.module.museums.controller.admin.specimenoutbound;
+
+import org.springframework.web.bind.annotation.*;
+import javax.annotation.Resource;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.security.access.prepost.PreAuthorize;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.Operation;
+
+import javax.validation.constraints.*;
+import javax.validation.*;
+import javax.servlet.http.*;
+import java.util.*;
+import java.io.IOException;
+
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+
+import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
+
+import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog;
+import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.*;
+
+import cn.iocoder.yudao.module.museums.controller.admin.specimenoutbound.vo.*;
+import cn.iocoder.yudao.module.museums.dal.dataobject.specimenoutbound.SpecimenOutboundDO;
+import cn.iocoder.yudao.module.museums.service.specimenoutbound.SpecimenOutboundService;
+
+@Tag(name = "管理后台 - 标本出库回库信息")
+@RestController
+@RequestMapping("/museums/specimen-outbound")
+@Validated
+public class SpecimenOutboundController {
+
+    @Resource
+    private SpecimenOutboundService specimenOutboundService;
+
+    @PostMapping("/create")
+    @Operation(summary = "创建标本出库回库信息")
+    @PreAuthorize("@ss.hasPermission('museums:specimen-outbound:create')")
+    public CommonResult<Integer> createSpecimenOutbound(@Valid @RequestBody SpecimenOutboundSaveReqVO createReqVO) {
+        return success(specimenOutboundService.createSpecimenOutbound(createReqVO));
+    }
+
+    @PutMapping("/update")
+    @Operation(summary = "更新标本出库回库信息")
+    @PreAuthorize("@ss.hasPermission('museums:specimen-outbound:update')")
+    public CommonResult<Boolean> updateSpecimenOutbound(@Valid @RequestBody SpecimenOutboundSaveReqVO updateReqVO) {
+        specimenOutboundService.updateSpecimenOutbound(updateReqVO);
+        return success(true);
+    }
+
+    @DeleteMapping("/delete")
+    @Operation(summary = "删除标本出库回库信息")
+    @Parameter(name = "id", description = "编号", required = true)
+    @PreAuthorize("@ss.hasPermission('museums:specimen-outbound:delete')")
+    public CommonResult<Boolean> deleteSpecimenOutbound(@RequestParam("id") Integer id) {
+        specimenOutboundService.deleteSpecimenOutbound(id);
+        return success(true);
+    }
+
+    @GetMapping("/get")
+    @Operation(summary = "获得标本出库回库信息")
+    @Parameter(name = "id", description = "编号", required = true, example = "1024")
+    @PreAuthorize("@ss.hasPermission('museums:specimen-outbound:query')")
+    public CommonResult<SpecimenOutboundRespVO> getSpecimenOutbound(@RequestParam("id") Integer id) {
+        SpecimenOutboundDO specimenOutbound = specimenOutboundService.getSpecimenOutbound(id);
+        return success(BeanUtils.toBean(specimenOutbound, SpecimenOutboundRespVO.class));
+    }
+
+    @GetMapping("/page")
+    @Operation(summary = "获得标本出库回库信息分页")
+    @PreAuthorize("@ss.hasPermission('museums:specimen-outbound:query')")
+    public CommonResult<PageResult<SpecimenOutboundRespVO>> getSpecimenOutboundPage(@Valid SpecimenOutboundPageReqVO pageReqVO) {
+        PageResult<SpecimenOutboundDO> pageResult = specimenOutboundService.getSpecimenOutboundPage(pageReqVO);
+        return success(BeanUtils.toBean(pageResult, SpecimenOutboundRespVO.class));
+    }
+
+    @GetMapping("/export-excel")
+    @Operation(summary = "导出标本出库回库信息 Excel")
+    @PreAuthorize("@ss.hasPermission('museums:specimen-outbound:export')")
+    @ApiAccessLog(operateType = EXPORT)
+    public void exportSpecimenOutboundExcel(@Valid SpecimenOutboundPageReqVO pageReqVO,
+              HttpServletResponse response) throws IOException {
+        pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
+        List<SpecimenOutboundDO> list = specimenOutboundService.getSpecimenOutboundPage(pageReqVO).getList();
+        // 导出 Excel
+        ExcelUtils.write(response, "标本出库回库信息.xls", "数据", SpecimenOutboundRespVO.class,
+                        BeanUtils.toBean(list, SpecimenOutboundRespVO.class));
+    }
+
+}

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

@@ -0,0 +1,76 @@
+package cn.iocoder.yudao.module.museums.controller.admin.specimenoutbound.vo;
+
+import lombok.*;
+import java.util.*;
+import io.swagger.v3.oas.annotations.media.Schema;
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import org.springframework.format.annotation.DateTimeFormat;
+import java.time.LocalDateTime;
+
+import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
+
+@Schema(description = "管理后台 - 标本出库回库信息分页 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class SpecimenOutboundPageReqVO extends PageParam {
+
+    @Schema(description = "关联到总表中的标本ID", example = "1")
+    private String infoId;
+
+    @Schema(description = "中文名称", example = "张三")
+    private String chineseName;
+
+    @Schema(description = "申请出库的标本编号")
+    private String specimenNumber;
+
+    @Schema(description = "申请人或申请单位", example = "张三")
+    private String applicantName;
+
+    @Schema(description = "申请日期")
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    private LocalDateTime[] applicationDate;
+
+    @Schema(description = "申请出库的用途")
+    private String applicationUsage;
+
+    @Schema(description = "附件上传")
+    private String attachments;
+
+    @Schema(description = "审批状态", example = "2")
+    private Integer status;
+
+    @Schema(description = "备注信息")
+    private String remarks;
+
+    @Schema(description = "流程实例的编号", example = "19175")
+    private String processInstanceId;
+
+    @Schema(description = "出库员")
+    private String operator;
+
+    @Schema(description = "出库时间")
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    private LocalDateTime[] outgoingTime;
+
+    @Schema(description = "退还人")
+    private String returner;
+
+    @Schema(description = "点收人")
+    private String receiver;
+
+    @Schema(description = "退还日期")
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    private LocalDateTime[] returnDate;
+
+    @Schema(description = "标本情况")
+    private String specimenCondition;
+
+    @Schema(description = "创建时间")
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    private LocalDateTime[] createTime;
+
+    @Schema(description = "标本状态(已出库、已回库、出库审批中)", example = "2")
+    private Integer sampleStatus;
+
+}

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

@@ -0,0 +1,91 @@
+package cn.iocoder.yudao.module.museums.controller.admin.specimenoutbound.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.*;
+import java.util.*;
+import org.springframework.format.annotation.DateTimeFormat;
+import java.time.LocalDateTime;
+import com.alibaba.excel.annotation.*;
+
+@Schema(description = "管理后台 - 标本出库回库信息 Response VO")
+@Data
+@ExcelIgnoreUnannotated
+public class SpecimenOutboundRespVO {
+
+    @Schema(description = "主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
+    @ExcelProperty("主键")
+    private Integer id;
+
+    @Schema(description = "关联到总表中的标本ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+    @ExcelProperty("关联到总表中的标本ID")
+    private String infoId;
+
+    @Schema(description = "中文名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "张三")
+    @ExcelProperty("中文名称")
+    private String chineseName;
+
+    @Schema(description = "申请出库的标本编号", requiredMode = Schema.RequiredMode.REQUIRED)
+    @ExcelProperty("申请出库的标本编号")
+    private String specimenNumber;
+
+    @Schema(description = "申请人或申请单位", requiredMode = Schema.RequiredMode.REQUIRED, example = "张三")
+    @ExcelProperty("申请人或申请单位")
+    private String applicantName;
+
+    @Schema(description = "申请日期")
+    @ExcelProperty("申请日期")
+    private LocalDateTime applicationDate;
+
+    @Schema(description = "申请出库的用途", requiredMode = Schema.RequiredMode.REQUIRED)
+    @ExcelProperty("申请出库的用途")
+    private String applicationUsage;
+
+    @Schema(description = "附件上传")
+    @ExcelProperty("附件上传")
+    private String attachments;
+
+    @Schema(description = "审批状态", example = "2")
+    @ExcelProperty("审批状态")
+    private Integer status;
+
+    @Schema(description = "备注信息")
+    @ExcelProperty("备注信息")
+    private String remarks;
+
+    @Schema(description = "流程实例的编号", example = "19175")
+    @ExcelProperty("流程实例的编号")
+    private String processInstanceId;
+
+    @Schema(description = "出库员", requiredMode = Schema.RequiredMode.REQUIRED)
+    @ExcelProperty("出库员")
+    private String operator;
+
+    @Schema(description = "出库时间")
+    @ExcelProperty("出库时间")
+    private LocalDateTime outgoingTime;
+
+    @Schema(description = "退还人", requiredMode = Schema.RequiredMode.REQUIRED)
+    @ExcelProperty("退还人")
+    private String returner;
+
+    @Schema(description = "点收人", requiredMode = Schema.RequiredMode.REQUIRED)
+    @ExcelProperty("点收人")
+    private String receiver;
+
+    @Schema(description = "退还日期", requiredMode = Schema.RequiredMode.REQUIRED)
+    @ExcelProperty("退还日期")
+    private LocalDateTime returnDate;
+
+    @Schema(description = "标本情况")
+    @ExcelProperty("标本情况")
+    private String specimenCondition;
+
+    @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
+    @ExcelProperty("创建时间")
+    private LocalDateTime createTime;
+
+    @Schema(description = "标本状态(已出库、已回库、出库审批中)", example = "2")
+    @ExcelProperty("标本状态(已出库、已回库、出库审批中)")
+    private Integer sampleStatus;
+
+}

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

@@ -0,0 +1,77 @@
+package cn.iocoder.yudao.module.museums.controller.admin.specimenoutbound.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.*;
+import java.util.*;
+import javax.validation.constraints.*;
+import org.springframework.format.annotation.DateTimeFormat;
+import java.time.LocalDateTime;
+
+@Schema(description = "管理后台 - 标本出库回库信息新增/修改 Request VO")
+@Data
+public class SpecimenOutboundSaveReqVO {
+
+    @Schema(description = "主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
+    private Integer id;
+
+    @Schema(description = "关联到总表中的标本ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+    @NotEmpty(message = "关联到总表中的标本ID不能为空")
+    private String infoId;
+
+    @Schema(description = "中文名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "张三")
+    @NotEmpty(message = "中文名称不能为空")
+    private String chineseName;
+
+    @Schema(description = "申请出库的标本编号", requiredMode = Schema.RequiredMode.REQUIRED)
+    @NotEmpty(message = "申请出库的标本编号不能为空")
+    private String specimenNumber;
+
+    @Schema(description = "申请人或申请单位", requiredMode = Schema.RequiredMode.REQUIRED, example = "张三")
+    @NotEmpty(message = "申请人或申请单位不能为空")
+    private String applicantName;
+
+    @Schema(description = "申请日期")
+    private LocalDateTime applicationDate;
+
+    @Schema(description = "申请出库的用途", requiredMode = Schema.RequiredMode.REQUIRED)
+    @NotEmpty(message = "申请出库的用途不能为空")
+    private String applicationUsage;
+
+    @Schema(description = "附件上传")
+    private String attachments;
+
+    @Schema(description = "审批状态", example = "2")
+    private Integer status;
+
+    @Schema(description = "备注信息")
+    private String remarks;
+
+    @Schema(description = "流程实例的编号", example = "19175")
+    private String processInstanceId;
+
+    @Schema(description = "出库员", requiredMode = Schema.RequiredMode.REQUIRED)
+    @NotEmpty(message = "出库员不能为空")
+    private String operator;
+
+    @Schema(description = "出库时间")
+    private LocalDateTime outgoingTime;
+
+    @Schema(description = "退还人", requiredMode = Schema.RequiredMode.REQUIRED)
+    @NotEmpty(message = "退还人不能为空")
+    private String returner;
+
+    @Schema(description = "点收人", requiredMode = Schema.RequiredMode.REQUIRED)
+    @NotEmpty(message = "点收人不能为空")
+    private String receiver;
+
+    @Schema(description = "退还日期", requiredMode = Schema.RequiredMode.REQUIRED)
+    @NotNull(message = "退还日期不能为空")
+    private LocalDateTime returnDate;
+
+    @Schema(description = "标本情况")
+    private String specimenCondition;
+
+    @Schema(description = "标本状态(已出库、已回库、出库审批中)", example = "2")
+    private Integer sampleStatus;
+
+}

+ 64 - 0
yudao-module-museums/yudao-module-museums-biz/src/main/java/cn/iocoder/yudao/module/museums/dal/dataobject/museumsdocument/MuseumsDocumentDO.java

@@ -0,0 +1,64 @@
+package cn.iocoder.yudao.module.museums.dal.dataobject.museumsdocument;
+
+import lombok.*;
+import java.util.*;
+import java.time.LocalDateTime;
+import java.time.LocalDateTime;
+import java.time.LocalDateTime;
+import com.baomidou.mybatisplus.annotation.*;
+import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
+
+/**
+ * 博物馆文件管理 DO
+ *
+ * @author 芋道源码
+ */
+@TableName("museums_document")
+@KeySequence("museums_document_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class MuseumsDocumentDO extends BaseDO {
+
+    /**
+     * 主键
+     */
+    @TableId
+    private Integer id;
+    /**
+     * 文件名称
+     */
+    private String fileName;
+    /**
+     * 配置编号
+     */
+    private Integer configId;
+    /**
+     * 路径
+     */
+    private String path;
+    /**
+     * 文件 URL
+     */
+    private String url;
+    /**
+     * 文件大小(字节)
+     */
+    private Integer fileSize;
+    /**
+     * 文件类型
+     */
+    private String fileType;
+    /**
+     * 上传时间
+     */
+    private LocalDateTime uploadDate;
+    /**
+     * 上传者
+     */
+    private String uploadedBy;
+
+}

+ 53 - 0
yudao-module-museums/yudao-module-museums-biz/src/main/java/cn/iocoder/yudao/module/museums/dal/dataobject/photogroup/PhotoGroupDO.java

@@ -0,0 +1,53 @@
+package cn.iocoder.yudao.module.museums.dal.dataobject.photogroup;
+
+import lombok.*;
+import java.util.*;
+import java.time.LocalDateTime;
+import java.time.LocalDateTime;
+import java.time.LocalDateTime;
+import java.time.LocalDateTime;
+import com.baomidou.mybatisplus.annotation.*;
+import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
+
+/**
+ * 博物馆照片组 DO
+ *
+ * @author qpw
+ */
+@TableName("museums_photo_group")
+@KeySequence("museums_photo_group_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class PhotoGroupDO extends BaseDO {
+
+    /**
+     * 主键
+     */
+    @TableId
+    private Integer id;
+    /**
+     * 照片组名称
+     */
+    private String groupName;
+    /**
+     * 照片组时间
+     */
+    private LocalDateTime groupDate;
+    /**
+     * 照片组简介
+     */
+    private String groupDescription;
+    /**
+     * 创建时间
+     */
+    private LocalDateTime createdAt;
+    /**
+     * 照片组上传
+     */
+    private String uploadPhotos;
+
+}

+ 44 - 0
yudao-module-museums/yudao-module-museums-biz/src/main/java/cn/iocoder/yudao/module/museums/dal/dataobject/photos/PhotosDO.java

@@ -0,0 +1,44 @@
+package cn.iocoder.yudao.module.museums.dal.dataobject.photos;
+
+import lombok.*;
+import java.util.*;
+import java.time.LocalDateTime;
+import java.time.LocalDateTime;
+import java.time.LocalDateTime;
+import com.baomidou.mybatisplus.annotation.*;
+import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
+
+/**
+ * 博物馆照片 DO
+ *
+ * @author qpw
+ */
+@TableName("museums_photos")
+@KeySequence("museums_photos_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class PhotosDO extends BaseDO {
+
+    /**
+     * 主键
+     */
+    @TableId
+    private Integer id;
+    /**
+     * 照片组表id
+     */
+    private Integer groupId;
+    /**
+     * 照片存储路径
+     */
+    private String photoUrl;
+    /**
+     * 上传时间
+     */
+    private LocalDateTime createdAt;
+
+}

+ 149 - 0
yudao-module-museums/yudao-module-museums-biz/src/main/java/cn/iocoder/yudao/module/museums/dal/dataobject/specimeninfo/SpecimenInfoDO.java

@@ -0,0 +1,149 @@
+package cn.iocoder.yudao.module.museums.dal.dataobject.specimeninfo;
+
+import lombok.*;
+
+import java.time.LocalDate;
+import java.util.*;
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+import com.baomidou.mybatisplus.annotation.*;
+import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
+
+/**
+ * 标本管理 DO
+ *
+ * @author 普伟
+ */
+@TableName("museums_specimen_info")
+@KeySequence("museums_specimen_info_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class SpecimenInfoDO extends BaseDO {
+
+    /**
+     * 主键
+     */
+    @TableId
+    private Integer id;
+    /**
+     * 标本类型(矿物、岩石矿石、化石、陨石)
+     */
+    private Integer specimenType;
+    /**
+     * 标本编号
+     */
+    private String specimenNumber;
+    /**
+     * 资产号
+     */
+    private String assetNumber;
+    /**
+     * 存放位置
+     */
+    private String storageLocation;
+    /**
+     * 中文名称
+     */
+    private String chineseName;
+    /**
+     * 英文名称
+     */
+    private String englishName;
+    /**
+     * 成分
+     */
+    private String composition;
+    /**
+     * 产地
+     */
+    private String origin;
+    /**
+     * 时代
+     */
+    private String era;
+    /**
+     * 保存地层
+     */
+    private String preservedLayer;
+    /**
+     * 陨石类型
+     */
+    private String meteoriteType;
+    /**
+     * 国际命名
+     */
+    private String internationalName;
+    /**
+     * 发现时间
+     */
+    private LocalDate discoveryTime;
+    /**
+     * 降落时间
+     */
+    private LocalDate fallTime;
+    /**
+     * 保存类型(标本、光片、薄片模型及其他)
+     */
+    private Integer preservationType;
+    /**
+     * 尺寸
+     */
+    private String size;
+    /**
+     * 重量
+     */
+    private BigDecimal weight;
+    /**
+     * 来源(采购、捐赠、采集)
+     */
+    private Integer source;
+    /**
+     * 标本提供者(供应商、捐赠人、采集人)
+     */
+    private String provider;
+    /**
+     * 入藏时间(购买、捐赠、采集时间)
+     */
+    private LocalDate acquisitionTime;
+    /**
+     * 用途
+     */
+    private String purpose;
+    /**
+     * 描述
+     */
+    private String description;
+    /**
+     * 馆藏状态(在馆、借出)
+     */
+    private Integer collectionStatus;
+    /**
+     * 备注
+     */
+    private String notes;
+    /**
+     * 图片名称
+     */
+    private String imageName;
+    /**
+     * 图片路径
+     */
+    private String imagePath;
+    /**
+     * 注销原因
+     */
+    private String deletedReason;
+    /**
+     * 入库操作员
+     */
+    private String operator;
+    /**
+     * 入库时间
+     */
+    private LocalDateTime entryDate;
+
+}

+ 102 - 0
yudao-module-museums/yudao-module-museums-biz/src/main/java/cn/iocoder/yudao/module/museums/dal/dataobject/specimenoutbound/SpecimenOutboundDO.java

@@ -0,0 +1,102 @@
+package cn.iocoder.yudao.module.museums.dal.dataobject.specimenoutbound;
+
+import lombok.*;
+import java.util.*;
+import java.time.LocalDateTime;
+import java.time.LocalDateTime;
+import java.time.LocalDateTime;
+import java.time.LocalDateTime;
+import java.time.LocalDateTime;
+import com.baomidou.mybatisplus.annotation.*;
+import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
+
+/**
+ * 标本出库回库信息 DO
+ *
+ * @author qpw
+ */
+@TableName("museums_specimen_outbound")
+@KeySequence("museums_specimen_outbound_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class SpecimenOutboundDO extends BaseDO {
+
+    /**
+     * 主键
+     */
+    @TableId
+    private Integer id;
+    /**
+     * 关联到总表中的标本ID
+     */
+    private String infoId;
+    /**
+     * 中文名称
+     */
+    private String chineseName;
+    /**
+     * 申请出库的标本编号
+     */
+    private String specimenNumber;
+    /**
+     * 申请人或申请单位
+     */
+    private String applicantName;
+    /**
+     * 申请日期
+     */
+    private LocalDateTime applicationDate;
+    /**
+     * 申请出库的用途
+     */
+    private String applicationUsage;
+    /**
+     * 附件上传
+     */
+    private String attachments;
+    /**
+     * 审批状态
+     */
+    private Integer status;
+    /**
+     * 备注信息
+     */
+    private String remarks;
+    /**
+     * 流程实例的编号
+     */
+    private String processInstanceId;
+    /**
+     * 出库员
+     */
+    private String operator;
+    /**
+     * 出库时间
+     */
+    private LocalDateTime outgoingTime;
+    /**
+     * 退还人
+     */
+    private String returner;
+    /**
+     * 点收人
+     */
+    private String receiver;
+    /**
+     * 退还日期
+     */
+    private LocalDateTime returnDate;
+    /**
+     * 标本情况
+     */
+    private String specimenCondition;
+    /**
+     * 标本状态(已出库、已回库、出库审批中)
+     */
+    private Integer sampleStatus;
+
+}

+ 34 - 0
yudao-module-museums/yudao-module-museums-biz/src/main/java/cn/iocoder/yudao/module/museums/dal/mysql/museumsdocument/MuseumsDocumentMapper.java

@@ -0,0 +1,34 @@
+package cn.iocoder.yudao.module.museums.dal.mysql.museumsdocument;
+
+import java.util.*;
+
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
+import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
+import cn.iocoder.yudao.module.museums.dal.dataobject.museumsdocument.MuseumsDocumentDO;
+import org.apache.ibatis.annotations.Mapper;
+import cn.iocoder.yudao.module.museums.controller.admin.museumsdocument.vo.*;
+
+/**
+ * 博物馆文件管理 Mapper
+ *
+ * @author 芋道源码
+ */
+@Mapper
+public interface MuseumsDocumentMapper extends BaseMapperX<MuseumsDocumentDO> {
+
+    default PageResult<MuseumsDocumentDO> selectPage(MuseumsDocumentPageReqVO reqVO) {
+        return selectPage(reqVO, new LambdaQueryWrapperX<MuseumsDocumentDO>()
+                .likeIfPresent(MuseumsDocumentDO::getFileName, reqVO.getFileName())
+                .eqIfPresent(MuseumsDocumentDO::getConfigId, reqVO.getConfigId())
+                .eqIfPresent(MuseumsDocumentDO::getPath, reqVO.getPath())
+                .eqIfPresent(MuseumsDocumentDO::getUrl, reqVO.getUrl())
+                .eqIfPresent(MuseumsDocumentDO::getFileSize, reqVO.getFileSize())
+                .eqIfPresent(MuseumsDocumentDO::getFileType, reqVO.getFileType())
+                .betweenIfPresent(MuseumsDocumentDO::getUploadDate, reqVO.getUploadDate())
+                .eqIfPresent(MuseumsDocumentDO::getUploadedBy, reqVO.getUploadedBy())
+                .betweenIfPresent(MuseumsDocumentDO::getCreateTime, reqVO.getCreateTime())
+                .orderByDesc(MuseumsDocumentDO::getId));
+    }
+
+}

+ 31 - 0
yudao-module-museums/yudao-module-museums-biz/src/main/java/cn/iocoder/yudao/module/museums/dal/mysql/photogroup/PhotoGroupMapper.java

@@ -0,0 +1,31 @@
+package cn.iocoder.yudao.module.museums.dal.mysql.photogroup;
+
+import java.util.*;
+
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
+import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
+import cn.iocoder.yudao.module.museums.dal.dataobject.photogroup.PhotoGroupDO;
+import org.apache.ibatis.annotations.Mapper;
+import cn.iocoder.yudao.module.museums.controller.admin.photogroup.vo.*;
+
+/**
+ * 博物馆照片组 Mapper
+ *
+ * @author qpw
+ */
+@Mapper
+public interface PhotoGroupMapper extends BaseMapperX<PhotoGroupDO> {
+
+    default PageResult<PhotoGroupDO> selectPage(PhotoGroupPageReqVO reqVO) {
+        return selectPage(reqVO, new LambdaQueryWrapperX<PhotoGroupDO>()
+                .likeIfPresent(PhotoGroupDO::getGroupName, reqVO.getGroupName())
+                .betweenIfPresent(PhotoGroupDO::getGroupDate, reqVO.getGroupDate())
+                .eqIfPresent(PhotoGroupDO::getGroupDescription, reqVO.getGroupDescription())
+                .eqIfPresent(PhotoGroupDO::getCreatedAt, reqVO.getCreatedAt())
+                .betweenIfPresent(PhotoGroupDO::getCreateTime, reqVO.getCreateTime())
+                .eqIfPresent(PhotoGroupDO::getUploadPhotos, reqVO.getUploadPhotos())
+                .orderByDesc(PhotoGroupDO::getId));
+    }
+
+}

+ 29 - 0
yudao-module-museums/yudao-module-museums-biz/src/main/java/cn/iocoder/yudao/module/museums/dal/mysql/photos/PhotosMapper.java

@@ -0,0 +1,29 @@
+package cn.iocoder.yudao.module.museums.dal.mysql.photos;
+
+import java.util.*;
+
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
+import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
+import cn.iocoder.yudao.module.museums.dal.dataobject.photos.PhotosDO;
+import org.apache.ibatis.annotations.Mapper;
+import cn.iocoder.yudao.module.museums.controller.admin.photos.vo.*;
+
+/**
+ * 博物馆照片 Mapper
+ *
+ * @author qpw
+ */
+@Mapper
+public interface PhotosMapper extends BaseMapperX<PhotosDO> {
+
+    default PageResult<PhotosDO> selectPage(PhotosPageReqVO reqVO) {
+        return selectPage(reqVO, new LambdaQueryWrapperX<PhotosDO>()
+                .eqIfPresent(PhotosDO::getGroupId, reqVO.getGroupId())
+                .eqIfPresent(PhotosDO::getPhotoUrl, reqVO.getPhotoUrl())
+                .eqIfPresent(PhotosDO::getCreatedAt, reqVO.getCreatedAt())
+                .betweenIfPresent(PhotosDO::getCreateTime, reqVO.getCreateTime())
+                .orderByDesc(PhotosDO::getId));
+    }
+
+}

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

@@ -0,0 +1,55 @@
+package cn.iocoder.yudao.module.museums.dal.mysql.specimeninfo;
+
+import java.util.*;
+
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
+import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
+import cn.iocoder.yudao.module.museums.dal.dataobject.specimeninfo.SpecimenInfoDO;
+import org.apache.ibatis.annotations.Mapper;
+import cn.iocoder.yudao.module.museums.controller.admin.specimeninfo.vo.*;
+
+/**
+ * 标本管理 Mapper
+ *
+ * @author 普伟
+ */
+@Mapper
+public interface SpecimenInfoMapper extends BaseMapperX<SpecimenInfoDO> {
+
+    default PageResult<SpecimenInfoDO> selectPage(SpecimenInfoPageReqVO reqVO) {
+        return selectPage(reqVO, new LambdaQueryWrapperX<SpecimenInfoDO>()
+                .eqIfPresent(SpecimenInfoDO::getSpecimenType, reqVO.getSpecimenType())
+                .eqIfPresent(SpecimenInfoDO::getSpecimenNumber, reqVO.getSpecimenNumber())
+                .eqIfPresent(SpecimenInfoDO::getAssetNumber, reqVO.getAssetNumber())
+                .eqIfPresent(SpecimenInfoDO::getStorageLocation, reqVO.getStorageLocation())
+                .likeIfPresent(SpecimenInfoDO::getChineseName, reqVO.getChineseName())
+                .likeIfPresent(SpecimenInfoDO::getEnglishName, reqVO.getEnglishName())
+                .eqIfPresent(SpecimenInfoDO::getComposition, reqVO.getComposition())
+                .eqIfPresent(SpecimenInfoDO::getOrigin, reqVO.getOrigin())
+                .eqIfPresent(SpecimenInfoDO::getEra, reqVO.getEra())
+                .eqIfPresent(SpecimenInfoDO::getPreservedLayer, reqVO.getPreservedLayer())
+                .eqIfPresent(SpecimenInfoDO::getMeteoriteType, reqVO.getMeteoriteType())
+                .likeIfPresent(SpecimenInfoDO::getInternationalName, reqVO.getInternationalName())
+                .betweenIfPresent(SpecimenInfoDO::getDiscoveryTime, reqVO.getDiscoveryTime())
+                .betweenIfPresent(SpecimenInfoDO::getFallTime, reqVO.getFallTime())
+                .eqIfPresent(SpecimenInfoDO::getPreservationType, reqVO.getPreservationType())
+                .eqIfPresent(SpecimenInfoDO::getSize, reqVO.getSize())
+                .eqIfPresent(SpecimenInfoDO::getWeight, reqVO.getWeight())
+                .eqIfPresent(SpecimenInfoDO::getSource, reqVO.getSource())
+                .eqIfPresent(SpecimenInfoDO::getProvider, reqVO.getProvider())
+                .betweenIfPresent(SpecimenInfoDO::getAcquisitionTime, reqVO.getAcquisitionTime())
+                .eqIfPresent(SpecimenInfoDO::getPurpose, reqVO.getPurpose())
+                .eqIfPresent(SpecimenInfoDO::getDescription, reqVO.getDescription())
+                .eqIfPresent(SpecimenInfoDO::getCollectionStatus, reqVO.getCollectionStatus())
+                .eqIfPresent(SpecimenInfoDO::getNotes, reqVO.getNotes())
+                .likeIfPresent(SpecimenInfoDO::getImageName, reqVO.getImageName())
+                .eqIfPresent(SpecimenInfoDO::getImagePath, reqVO.getImagePath())
+                .betweenIfPresent(SpecimenInfoDO::getCreateTime, reqVO.getCreateTime())
+                .eqIfPresent(SpecimenInfoDO::getDeletedReason, reqVO.getDeletedReason())
+                .eqIfPresent(SpecimenInfoDO::getOperator, reqVO.getOperator())
+                .betweenIfPresent(SpecimenInfoDO::getEntryDate, reqVO.getEntryDate())
+                .orderByDesc(SpecimenInfoDO::getId));
+    }
+
+}

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

@@ -0,0 +1,43 @@
+package cn.iocoder.yudao.module.museums.dal.mysql.specimenoutbound;
+
+import java.util.*;
+
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
+import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
+import cn.iocoder.yudao.module.museums.dal.dataobject.specimenoutbound.SpecimenOutboundDO;
+import org.apache.ibatis.annotations.Mapper;
+import cn.iocoder.yudao.module.museums.controller.admin.specimenoutbound.vo.*;
+
+/**
+ * 标本出库回库信息 Mapper
+ *
+ * @author qpw
+ */
+@Mapper
+public interface SpecimenOutboundMapper extends BaseMapperX<SpecimenOutboundDO> {
+
+    default PageResult<SpecimenOutboundDO> selectPage(SpecimenOutboundPageReqVO reqVO) {
+        return selectPage(reqVO, new LambdaQueryWrapperX<SpecimenOutboundDO>()
+                .eqIfPresent(SpecimenOutboundDO::getInfoId, reqVO.getInfoId())
+                .likeIfPresent(SpecimenOutboundDO::getChineseName, reqVO.getChineseName())
+                .eqIfPresent(SpecimenOutboundDO::getSpecimenNumber, reqVO.getSpecimenNumber())
+                .likeIfPresent(SpecimenOutboundDO::getApplicantName, reqVO.getApplicantName())
+                .betweenIfPresent(SpecimenOutboundDO::getApplicationDate, reqVO.getApplicationDate())
+                .eqIfPresent(SpecimenOutboundDO::getApplicationUsage, reqVO.getApplicationUsage())
+                .eqIfPresent(SpecimenOutboundDO::getAttachments, reqVO.getAttachments())
+                .eqIfPresent(SpecimenOutboundDO::getStatus, reqVO.getStatus())
+                .eqIfPresent(SpecimenOutboundDO::getRemarks, reqVO.getRemarks())
+                .eqIfPresent(SpecimenOutboundDO::getProcessInstanceId, reqVO.getProcessInstanceId())
+                .eqIfPresent(SpecimenOutboundDO::getOperator, reqVO.getOperator())
+                .betweenIfPresent(SpecimenOutboundDO::getOutgoingTime, reqVO.getOutgoingTime())
+                .eqIfPresent(SpecimenOutboundDO::getReturner, reqVO.getReturner())
+                .eqIfPresent(SpecimenOutboundDO::getReceiver, reqVO.getReceiver())
+                .betweenIfPresent(SpecimenOutboundDO::getReturnDate, reqVO.getReturnDate())
+                .eqIfPresent(SpecimenOutboundDO::getSpecimenCondition, reqVO.getSpecimenCondition())
+                .betweenIfPresent(SpecimenOutboundDO::getCreateTime, reqVO.getCreateTime())
+                .eqIfPresent(SpecimenOutboundDO::getSampleStatus, reqVO.getSampleStatus())
+                .orderByDesc(SpecimenOutboundDO::getId));
+    }
+
+}

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

@@ -0,0 +1,55 @@
+package cn.iocoder.yudao.module.museums.service.museumsdocument;
+
+import java.util.*;
+import javax.validation.*;
+import cn.iocoder.yudao.module.museums.controller.admin.museumsdocument.vo.*;
+import cn.iocoder.yudao.module.museums.dal.dataobject.museumsdocument.MuseumsDocumentDO;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+
+/**
+ * 博物馆文件管理 Service 接口
+ *
+ * @author 芋道源码
+ */
+public interface MuseumsDocumentService {
+
+    /**
+     * 创建博物馆文件管理
+     *
+     * @param createReqVO 创建信息
+     * @return 编号
+     */
+    Integer createDocument(@Valid MuseumsDocumentSaveReqVO createReqVO);
+
+    /**
+     * 更新博物馆文件管理
+     *
+     * @param updateReqVO 更新信息
+     */
+    void updateDocument(@Valid MuseumsDocumentSaveReqVO updateReqVO);
+
+    /**
+     * 删除博物馆文件管理
+     *
+     * @param id 编号
+     */
+    void deleteDocument(Integer id);
+
+    /**
+     * 获得博物馆文件管理
+     *
+     * @param id 编号
+     * @return 博物馆文件管理
+     */
+    MuseumsDocumentDO getDocument(Integer id);
+
+    /**
+     * 获得博物馆文件管理分页
+     *
+     * @param pageReqVO 分页查询
+     * @return 博物馆文件管理分页
+     */
+    PageResult<MuseumsDocumentDO> getDocumentPage(MuseumsDocumentPageReqVO pageReqVO);
+
+}

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

@@ -0,0 +1,74 @@
+package cn.iocoder.yudao.module.museums.service.museumsdocument;
+
+import org.springframework.stereotype.Service;
+import javax.annotation.Resource;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.*;
+import cn.iocoder.yudao.module.museums.controller.admin.museumsdocument.vo.*;
+import cn.iocoder.yudao.module.museums.dal.dataobject.museumsdocument.MuseumsDocumentDO;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+
+import cn.iocoder.yudao.module.museums.dal.mysql.museumsdocument.MuseumsDocumentMapper;
+
+import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.iocoder.yudao.module.museums.enums.ErrorCodeConstants.*;
+
+/**
+ * 博物馆文件管理 Service 实现类
+ *
+ * @author 芋道源码
+ */
+@Service
+@Validated
+public class MuseumsDocumentServiceImpl implements MuseumsDocumentService {
+
+    @Resource
+    private MuseumsDocumentMapper documentMapper;
+
+    @Override
+    public Integer createDocument(MuseumsDocumentSaveReqVO createReqVO) {
+        // 插入
+        MuseumsDocumentDO document = BeanUtils.toBean(createReqVO, MuseumsDocumentDO.class);
+        documentMapper.insert(document);
+        // 返回
+        return document.getId();
+    }
+
+    @Override
+    public void updateDocument(MuseumsDocumentSaveReqVO updateReqVO) {
+        // 校验存在
+        validateDocumentExists(updateReqVO.getId());
+        // 更新
+        MuseumsDocumentDO updateObj = BeanUtils.toBean(updateReqVO, MuseumsDocumentDO.class);
+        documentMapper.updateById(updateObj);
+    }
+
+    @Override
+    public void deleteDocument(Integer id) {
+        // 校验存在
+        validateDocumentExists(id);
+        // 删除
+        documentMapper.deleteById(id);
+    }
+
+    private void validateDocumentExists(Integer id) {
+        if (documentMapper.selectById(id) == null) {
+            throw exception(DOCUMENT_NOT_EXISTS);
+        }
+    }
+
+    @Override
+    public MuseumsDocumentDO getDocument(Integer id) {
+        return documentMapper.selectById(id);
+    }
+
+    @Override
+    public PageResult<MuseumsDocumentDO> getDocumentPage(MuseumsDocumentPageReqVO pageReqVO) {
+        return documentMapper.selectPage(pageReqVO);
+    }
+
+}

+ 55 - 0
yudao-module-museums/yudao-module-museums-biz/src/main/java/cn/iocoder/yudao/module/museums/service/photogroup/PhotoGroupService.java

@@ -0,0 +1,55 @@
+package cn.iocoder.yudao.module.museums.service.photogroup;
+
+import java.util.*;
+import javax.validation.*;
+import cn.iocoder.yudao.module.museums.controller.admin.photogroup.vo.*;
+import cn.iocoder.yudao.module.museums.dal.dataobject.photogroup.PhotoGroupDO;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+
+/**
+ * 博物馆照片组 Service 接口
+ *
+ * @author qpw
+ */
+public interface PhotoGroupService {
+
+    /**
+     * 创建博物馆照片组
+     *
+     * @param createReqVO 创建信息
+     * @return 编号
+     */
+    Integer createPhotoGroup(@Valid PhotoGroupSaveReqVO createReqVO);
+
+    /**
+     * 更新博物馆照片组
+     *
+     * @param updateReqVO 更新信息
+     */
+    void updatePhotoGroup(@Valid PhotoGroupSaveReqVO updateReqVO);
+
+    /**
+     * 删除博物馆照片组
+     *
+     * @param id 编号
+     */
+    void deletePhotoGroup(Integer id);
+
+    /**
+     * 获得博物馆照片组
+     *
+     * @param id 编号
+     * @return 博物馆照片组
+     */
+    PhotoGroupDO getPhotoGroup(Integer id);
+
+    /**
+     * 获得博物馆照片组分页
+     *
+     * @param pageReqVO 分页查询
+     * @return 博物馆照片组分页
+     */
+    PageResult<PhotoGroupDO> getPhotoGroupPage(PhotoGroupPageReqVO pageReqVO);
+
+}

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

@@ -0,0 +1,74 @@
+package cn.iocoder.yudao.module.museums.service.photogroup;
+
+import org.springframework.stereotype.Service;
+import javax.annotation.Resource;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.*;
+import cn.iocoder.yudao.module.museums.controller.admin.photogroup.vo.*;
+import cn.iocoder.yudao.module.museums.dal.dataobject.photogroup.PhotoGroupDO;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+
+import cn.iocoder.yudao.module.museums.dal.mysql.photogroup.PhotoGroupMapper;
+
+import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.iocoder.yudao.module.museums.enums.ErrorCodeConstants.*;
+
+/**
+ * 博物馆照片组 Service 实现类
+ *
+ * @author qpw
+ */
+@Service
+@Validated
+public class PhotoGroupServiceImpl implements PhotoGroupService {
+
+    @Resource
+    private PhotoGroupMapper photoGroupMapper;
+
+    @Override
+    public Integer createPhotoGroup(PhotoGroupSaveReqVO createReqVO) {
+        // 插入
+        PhotoGroupDO photoGroup = BeanUtils.toBean(createReqVO, PhotoGroupDO.class);
+        photoGroupMapper.insert(photoGroup);
+        // 返回
+        return photoGroup.getId();
+    }
+
+    @Override
+    public void updatePhotoGroup(PhotoGroupSaveReqVO updateReqVO) {
+        // 校验存在
+        validatePhotoGroupExists(updateReqVO.getId());
+        // 更新
+        PhotoGroupDO updateObj = BeanUtils.toBean(updateReqVO, PhotoGroupDO.class);
+        photoGroupMapper.updateById(updateObj);
+    }
+
+    @Override
+    public void deletePhotoGroup(Integer id) {
+        // 校验存在
+        validatePhotoGroupExists(id);
+        // 删除
+        photoGroupMapper.deleteById(id);
+    }
+
+    private void validatePhotoGroupExists(Integer id) {
+        if (photoGroupMapper.selectById(id) == null) {
+            throw exception(PHOTO_GROUP_NOT_EXISTS);
+        }
+    }
+
+    @Override
+    public PhotoGroupDO getPhotoGroup(Integer id) {
+        return photoGroupMapper.selectById(id);
+    }
+
+    @Override
+    public PageResult<PhotoGroupDO> getPhotoGroupPage(PhotoGroupPageReqVO pageReqVO) {
+        return photoGroupMapper.selectPage(pageReqVO);
+    }
+
+}

+ 55 - 0
yudao-module-museums/yudao-module-museums-biz/src/main/java/cn/iocoder/yudao/module/museums/service/photos/PhotosService.java

@@ -0,0 +1,55 @@
+package cn.iocoder.yudao.module.museums.service.photos;
+
+import java.util.*;
+import javax.validation.*;
+import cn.iocoder.yudao.module.museums.controller.admin.photos.vo.*;
+import cn.iocoder.yudao.module.museums.dal.dataobject.photos.PhotosDO;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+
+/**
+ * 博物馆照片 Service 接口
+ *
+ * @author qpw
+ */
+public interface PhotosService {
+
+    /**
+     * 创建博物馆照片
+     *
+     * @param createReqVO 创建信息
+     * @return 编号
+     */
+    Integer createPhotos(@Valid PhotosSaveReqVO createReqVO);
+
+    /**
+     * 更新博物馆照片
+     *
+     * @param updateReqVO 更新信息
+     */
+    void updatePhotos(@Valid PhotosSaveReqVO updateReqVO);
+
+    /**
+     * 删除博物馆照片
+     *
+     * @param id 编号
+     */
+    void deletePhotos(Integer id);
+
+    /**
+     * 获得博物馆照片
+     *
+     * @param id 编号
+     * @return 博物馆照片
+     */
+    PhotosDO getPhotos(Integer id);
+
+    /**
+     * 获得博物馆照片分页
+     *
+     * @param pageReqVO 分页查询
+     * @return 博物馆照片分页
+     */
+    PageResult<PhotosDO> getPhotosPage(PhotosPageReqVO pageReqVO);
+
+}

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

@@ -0,0 +1,74 @@
+package cn.iocoder.yudao.module.museums.service.photos;
+
+import org.springframework.stereotype.Service;
+import javax.annotation.Resource;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.*;
+import cn.iocoder.yudao.module.museums.controller.admin.photos.vo.*;
+import cn.iocoder.yudao.module.museums.dal.dataobject.photos.PhotosDO;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+
+import cn.iocoder.yudao.module.museums.dal.mysql.photos.PhotosMapper;
+
+import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.iocoder.yudao.module.museums.enums.ErrorCodeConstants.*;
+
+/**
+ * 博物馆照片 Service 实现类
+ *
+ * @author qpw
+ */
+@Service
+@Validated
+public class PhotosServiceImpl implements PhotosService {
+
+    @Resource
+    private PhotosMapper photosMapper;
+
+    @Override
+    public Integer createPhotos(PhotosSaveReqVO createReqVO) {
+        // 插入
+        PhotosDO photos = BeanUtils.toBean(createReqVO, PhotosDO.class);
+        photosMapper.insert(photos);
+        // 返回
+        return photos.getId();
+    }
+
+    @Override
+    public void updatePhotos(PhotosSaveReqVO updateReqVO) {
+        // 校验存在
+        validatePhotosExists(updateReqVO.getId());
+        // 更新
+        PhotosDO updateObj = BeanUtils.toBean(updateReqVO, PhotosDO.class);
+        photosMapper.updateById(updateObj);
+    }
+
+    @Override
+    public void deletePhotos(Integer id) {
+        // 校验存在
+        validatePhotosExists(id);
+        // 删除
+        photosMapper.deleteById(id);
+    }
+
+    private void validatePhotosExists(Integer id) {
+        if (photosMapper.selectById(id) == null) {
+            throw exception(PHOTOS_NOT_EXISTS);
+        }
+    }
+
+    @Override
+    public PhotosDO getPhotos(Integer id) {
+        return photosMapper.selectById(id);
+    }
+
+    @Override
+    public PageResult<PhotosDO> getPhotosPage(PhotosPageReqVO pageReqVO) {
+        return photosMapper.selectPage(pageReqVO);
+    }
+
+}

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

@@ -0,0 +1,55 @@
+package cn.iocoder.yudao.module.museums.service.specimeninfo;
+
+import java.util.*;
+import javax.validation.*;
+import cn.iocoder.yudao.module.museums.controller.admin.specimeninfo.vo.*;
+import cn.iocoder.yudao.module.museums.dal.dataobject.specimeninfo.SpecimenInfoDO;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+
+/**
+ * 标本管理 Service 接口
+ *
+ * @author 普伟
+ */
+public interface SpecimenInfoService {
+
+    /**
+     * 创建标本管理
+     *
+     * @param createReqVO 创建信息
+     * @return 编号
+     */
+    Integer createSpecimenInfo(@Valid SpecimenInfoSaveReqVO createReqVO);
+
+    /**
+     * 更新标本管理
+     *
+     * @param updateReqVO 更新信息
+     */
+    void updateSpecimenInfo(@Valid SpecimenInfoSaveReqVO updateReqVO);
+
+    /**
+     * 删除标本管理
+     *
+     * @param id 编号
+     */
+    void deleteSpecimenInfo(Integer id);
+
+    /**
+     * 获得标本管理
+     *
+     * @param id 编号
+     * @return 标本管理
+     */
+    SpecimenInfoDO getSpecimenInfo(Integer id);
+
+    /**
+     * 获得标本管理分页
+     *
+     * @param pageReqVO 分页查询
+     * @return 标本管理分页
+     */
+    PageResult<SpecimenInfoDO> getSpecimenInfoPage(SpecimenInfoPageReqVO pageReqVO);
+
+}

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

@@ -0,0 +1,73 @@
+package cn.iocoder.yudao.module.museums.service.specimeninfo;
+
+import org.springframework.stereotype.Service;
+import javax.annotation.Resource;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.*;
+import cn.iocoder.yudao.module.museums.controller.admin.specimeninfo.vo.*;
+import cn.iocoder.yudao.module.museums.dal.dataobject.specimeninfo.SpecimenInfoDO;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+
+import cn.iocoder.yudao.module.museums.dal.mysql.specimeninfo.SpecimenInfoMapper;
+
+import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.iocoder.yudao.module.museums.enums.ErrorCodeConstants.*;
+/**
+ * 标本管理 Service 实现类
+ *
+ * @author 普伟
+ */
+@Service
+@Validated
+public class SpecimenInfoServiceImpl implements SpecimenInfoService {
+
+    @Resource
+    private SpecimenInfoMapper specimenInfoMapper;
+
+    @Override
+    public Integer createSpecimenInfo(SpecimenInfoSaveReqVO createReqVO) {
+        // 插入
+        SpecimenInfoDO specimenInfo = BeanUtils.toBean(createReqVO, SpecimenInfoDO.class);
+        specimenInfoMapper.insert(specimenInfo);
+        // 返回
+        return specimenInfo.getId();
+    }
+
+    @Override
+    public void updateSpecimenInfo(SpecimenInfoSaveReqVO updateReqVO) {
+        // 校验存在
+        validateSpecimenInfoExists(updateReqVO.getId());
+        // 更新
+        SpecimenInfoDO updateObj = BeanUtils.toBean(updateReqVO, SpecimenInfoDO.class);
+        specimenInfoMapper.updateById(updateObj);
+    }
+
+    @Override
+    public void deleteSpecimenInfo(Integer id) {
+        // 校验存在
+        validateSpecimenInfoExists(id);
+        // 删除
+        specimenInfoMapper.deleteById(id);
+    }
+
+    private void validateSpecimenInfoExists(Integer id) {
+        if (specimenInfoMapper.selectById(id) == null) {
+            throw exception(SPECIMEN_INFO_NOT_EXISTS);
+        }
+    }
+
+    @Override
+    public SpecimenInfoDO getSpecimenInfo(Integer id) {
+        return specimenInfoMapper.selectById(id);
+    }
+
+    @Override
+    public PageResult<SpecimenInfoDO> getSpecimenInfoPage(SpecimenInfoPageReqVO pageReqVO) {
+        return specimenInfoMapper.selectPage(pageReqVO);
+    }
+
+}

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

@@ -0,0 +1,55 @@
+package cn.iocoder.yudao.module.museums.service.specimenoutbound;
+
+import java.util.*;
+import javax.validation.*;
+import cn.iocoder.yudao.module.museums.controller.admin.specimenoutbound.vo.*;
+import cn.iocoder.yudao.module.museums.dal.dataobject.specimenoutbound.SpecimenOutboundDO;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+
+/**
+ * 标本出库回库信息 Service 接口
+ *
+ * @author qpw
+ */
+public interface SpecimenOutboundService {
+
+    /**
+     * 创建标本出库回库信息
+     *
+     * @param createReqVO 创建信息
+     * @return 编号
+     */
+    Integer createSpecimenOutbound(@Valid SpecimenOutboundSaveReqVO createReqVO);
+
+    /**
+     * 更新标本出库回库信息
+     *
+     * @param updateReqVO 更新信息
+     */
+    void updateSpecimenOutbound(@Valid SpecimenOutboundSaveReqVO updateReqVO);
+
+    /**
+     * 删除标本出库回库信息
+     *
+     * @param id 编号
+     */
+    void deleteSpecimenOutbound(Integer id);
+
+    /**
+     * 获得标本出库回库信息
+     *
+     * @param id 编号
+     * @return 标本出库回库信息
+     */
+    SpecimenOutboundDO getSpecimenOutbound(Integer id);
+
+    /**
+     * 获得标本出库回库信息分页
+     *
+     * @param pageReqVO 分页查询
+     * @return 标本出库回库信息分页
+     */
+    PageResult<SpecimenOutboundDO> getSpecimenOutboundPage(SpecimenOutboundPageReqVO pageReqVO);
+
+}

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

@@ -0,0 +1,74 @@
+package cn.iocoder.yudao.module.museums.service.specimenoutbound;
+
+import org.springframework.stereotype.Service;
+import javax.annotation.Resource;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.*;
+import cn.iocoder.yudao.module.museums.controller.admin.specimenoutbound.vo.*;
+import cn.iocoder.yudao.module.museums.dal.dataobject.specimenoutbound.SpecimenOutboundDO;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+
+import cn.iocoder.yudao.module.museums.dal.mysql.specimenoutbound.SpecimenOutboundMapper;
+
+import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.iocoder.yudao.module.museums.enums.ErrorCodeConstants.*;
+
+/**
+ * 标本出库回库信息 Service 实现类
+ *
+ * @author qpw
+ */
+@Service
+@Validated
+public class SpecimenOutboundServiceImpl implements SpecimenOutboundService {
+
+    @Resource
+    private SpecimenOutboundMapper specimenOutboundMapper;
+
+    @Override
+    public Integer createSpecimenOutbound(SpecimenOutboundSaveReqVO createReqVO) {
+        // 插入
+        SpecimenOutboundDO specimenOutbound = BeanUtils.toBean(createReqVO, SpecimenOutboundDO.class);
+        specimenOutboundMapper.insert(specimenOutbound);
+        // 返回
+        return specimenOutbound.getId();
+    }
+
+    @Override
+    public void updateSpecimenOutbound(SpecimenOutboundSaveReqVO updateReqVO) {
+        // 校验存在
+        validateSpecimenOutboundExists(updateReqVO.getId());
+        // 更新
+        SpecimenOutboundDO updateObj = BeanUtils.toBean(updateReqVO, SpecimenOutboundDO.class);
+        specimenOutboundMapper.updateById(updateObj);
+    }
+
+    @Override
+    public void deleteSpecimenOutbound(Integer id) {
+        // 校验存在
+        validateSpecimenOutboundExists(id);
+        // 删除
+        specimenOutboundMapper.deleteById(id);
+    }
+
+    private void validateSpecimenOutboundExists(Integer id) {
+        if (specimenOutboundMapper.selectById(id) == null) {
+            throw exception(SPECIMEN_OUTBOUND_NOT_EXISTS);
+        }
+    }
+
+    @Override
+    public SpecimenOutboundDO getSpecimenOutbound(Integer id) {
+        return specimenOutboundMapper.selectById(id);
+    }
+
+    @Override
+    public PageResult<SpecimenOutboundDO> getSpecimenOutboundPage(SpecimenOutboundPageReqVO pageReqVO) {
+        return specimenOutboundMapper.selectPage(pageReqVO);
+    }
+
+}

+ 12 - 0
yudao-module-museums/yudao-module-museums-biz/src/main/resources/mapper/museumsdocument/MuseumsDocumentMapper.xml

@@ -0,0 +1,12 @@
+<?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.museums.dal.mysql.museumsdocument.MuseumsDocumentMapper">
+
+    <!--
+        一般情况下,尽可能使用 Mapper 进行 CRUD 增删改查即可。
+        无法满足的场景,例如说多表关联查询,才使用 XML 编写 SQL。
+        代码生成器暂时只生成 Mapper XML 文件本身,更多推荐 MybatisX 快速开发插件来生成查询。
+        文档可见:https://www.iocoder.cn/MyBatis/x-plugins/
+     -->
+
+</mapper>

+ 12 - 0
yudao-module-museums/yudao-module-museums-biz/src/main/resources/mapper/photogroup/PhotoGroupMapper.xml

@@ -0,0 +1,12 @@
+<?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.museums.dal.mysql.photogroup.PhotoGroupMapper">
+
+    <!--
+        一般情况下,尽可能使用 Mapper 进行 CRUD 增删改查即可。
+        无法满足的场景,例如说多表关联查询,才使用 XML 编写 SQL。
+        代码生成器暂时只生成 Mapper XML 文件本身,更多推荐 MybatisX 快速开发插件来生成查询。
+        文档可见:https://www.iocoder.cn/MyBatis/x-plugins/
+     -->
+
+</mapper>

+ 12 - 0
yudao-module-museums/yudao-module-museums-biz/src/main/resources/mapper/photos/PhotosMapper.xml

@@ -0,0 +1,12 @@
+<?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.museums.dal.mysql.photos.PhotosMapper">
+
+    <!--
+        一般情况下,尽可能使用 Mapper 进行 CRUD 增删改查即可。
+        无法满足的场景,例如说多表关联查询,才使用 XML 编写 SQL。
+        代码生成器暂时只生成 Mapper XML 文件本身,更多推荐 MybatisX 快速开发插件来生成查询。
+        文档可见:https://www.iocoder.cn/MyBatis/x-plugins/
+     -->
+
+</mapper>

+ 12 - 0
yudao-module-museums/yudao-module-museums-biz/src/main/resources/mapper/specimeninfo/SpecimenInfoMapper.xml

@@ -0,0 +1,12 @@
+<?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.museums.dal.mysql.specimeninfo.SpecimenInfoMapper">
+
+    <!--
+        一般情况下,尽可能使用 Mapper 进行 CRUD 增删改查即可。
+        无法满足的场景,例如说多表关联查询,才使用 XML 编写 SQL。
+        代码生成器暂时只生成 Mapper XML 文件本身,更多推荐 MybatisX 快速开发插件来生成查询。
+        文档可见:https://www.iocoder.cn/MyBatis/x-plugins/
+     -->
+
+</mapper>

+ 12 - 0
yudao-module-museums/yudao-module-museums-biz/src/main/resources/mapper/specimenoutbound/SpecimenOutboundMapper.xml

@@ -0,0 +1,12 @@
+<?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.museums.dal.mysql.specimenoutbound.SpecimenOutboundMapper">
+
+    <!--
+        一般情况下,尽可能使用 Mapper 进行 CRUD 增删改查即可。
+        无法满足的场景,例如说多表关联查询,才使用 XML 编写 SQL。
+        代码生成器暂时只生成 Mapper XML 文件本身,更多推荐 MybatisX 快速开发插件来生成查询。
+        文档可见:https://www.iocoder.cn/MyBatis/x-plugins/
+     -->
+
+</mapper>

+ 162 - 0
yudao-module-museums/yudao-module-museums-biz/src/test/java/cn/iocoder/yudao/module/museums/service/museumsdocument/MuseumsDocumentServiceImplTest.java

@@ -0,0 +1,162 @@
+package cn.iocoder.yudao.module.museums.service.museumsdocument;
+
+import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.test.mock.mockito.MockBean;
+
+import javax.annotation.Resource;
+
+import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
+
+import cn.iocoder.yudao.module.museums.controller.admin.museumsdocument.vo.*;
+import cn.iocoder.yudao.module.museums.dal.dataobject.museumsdocument.MuseumsDocumentDO;
+import cn.iocoder.yudao.module.museums.dal.mysql.museumsdocument.MuseumsDocumentMapper;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+
+import javax.annotation.Resource;
+import org.springframework.context.annotation.Import;
+import java.util.*;
+import java.time.LocalDateTime;
+
+import static cn.hutool.core.util.RandomUtil.*;
+import static cn.iocoder.yudao.module.museums.enums.ErrorCodeConstants.*;
+import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.*;
+import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*;
+import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.*;
+import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.*;
+import static cn.iocoder.yudao.framework.common.util.date.DateUtils.*;
+import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.Mockito.*;
+
+/**
+ * {@link MuseumsDocumentServiceImpl} 的单元测试类
+ *
+ * @author 芋道源码
+ */
+@Import(MuseumsDocumentServiceImpl.class)
+public class MuseumsDocumentServiceImplTest extends BaseDbUnitTest {
+
+    @Resource
+    private MuseumsDocumentServiceImpl documentService;
+
+    @Resource
+    private MuseumsDocumentMapper documentMapper;
+
+    @Test
+    public void testCreateDocument_success() {
+        // 准备参数
+        MuseumsDocumentSaveReqVO createReqVO = randomPojo(MuseumsDocumentSaveReqVO.class).setId(null);
+
+        // 调用
+        Integer documentId = documentService.createDocument(createReqVO);
+        // 断言
+        assertNotNull(documentId);
+        // 校验记录的属性是否正确
+        MuseumsDocumentDO document = documentMapper.selectById(documentId);
+        assertPojoEquals(createReqVO, document, "id");
+    }
+
+    @Test
+    public void testUpdateDocument_success() {
+        // mock 数据
+        MuseumsDocumentDO dbDocument = randomPojo(MuseumsDocumentDO.class);
+        documentMapper.insert(dbDocument);// @Sql: 先插入出一条存在的数据
+        // 准备参数
+        MuseumsDocumentSaveReqVO updateReqVO = randomPojo(MuseumsDocumentSaveReqVO.class, o -> {
+            o.setId(dbDocument.getId()); // 设置更新的 ID
+        });
+
+        // 调用
+        documentService.updateDocument(updateReqVO);
+        // 校验是否更新正确
+        MuseumsDocumentDO document = documentMapper.selectById(updateReqVO.getId()); // 获取最新的
+        assertPojoEquals(updateReqVO, document);
+    }
+
+    @Test
+    public void testUpdateDocument_notExists() {
+        // 准备参数
+        MuseumsDocumentSaveReqVO updateReqVO = randomPojo(MuseumsDocumentSaveReqVO.class);
+
+        // 调用, 并断言异常
+        assertServiceException(() -> documentService.updateDocument(updateReqVO), DOCUMENT_NOT_EXISTS);
+    }
+
+    @Test
+    public void testDeleteDocument_success() {
+        // mock 数据
+        MuseumsDocumentDO dbDocument = randomPojo(MuseumsDocumentDO.class);
+        documentMapper.insert(dbDocument);// @Sql: 先插入出一条存在的数据
+        // 准备参数
+        Integer id = dbDocument.getId();
+
+        // 调用
+        documentService.deleteDocument(id);
+       // 校验数据不存在了
+       assertNull(documentMapper.selectById(id));
+    }
+
+    @Test
+    public void testDeleteDocument_notExists() {
+        // 准备参数
+        Integer id = randomIntegerId();
+
+        // 调用, 并断言异常
+        assertServiceException(() -> documentService.deleteDocument(id), DOCUMENT_NOT_EXISTS);
+    }
+
+    @Test
+    @Disabled  // TODO 请修改 null 为需要的值,然后删除 @Disabled 注解
+    public void testGetDocumentPage() {
+       // mock 数据
+       MuseumsDocumentDO dbDocument = randomPojo(MuseumsDocumentDO.class, o -> { // 等会查询到
+           o.setFileName(null);
+           o.setConfigId(null);
+           o.setPath(null);
+           o.setUrl(null);
+           o.setFileSize(null);
+           o.setFileType(null);
+           o.setUploadDate(null);
+           o.setUploadedBy(null);
+           o.setCreateTime(null);
+       });
+       documentMapper.insert(dbDocument);
+       // 测试 fileName 不匹配
+       documentMapper.insert(cloneIgnoreId(dbDocument, o -> o.setFileName(null)));
+       // 测试 configId 不匹配
+       documentMapper.insert(cloneIgnoreId(dbDocument, o -> o.setConfigId(null)));
+       // 测试 path 不匹配
+       documentMapper.insert(cloneIgnoreId(dbDocument, o -> o.setPath(null)));
+       // 测试 url 不匹配
+       documentMapper.insert(cloneIgnoreId(dbDocument, o -> o.setUrl(null)));
+       // 测试 fileSize 不匹配
+       documentMapper.insert(cloneIgnoreId(dbDocument, o -> o.setFileSize(null)));
+       // 测试 fileType 不匹配
+       documentMapper.insert(cloneIgnoreId(dbDocument, o -> o.setFileType(null)));
+       // 测试 uploadDate 不匹配
+       documentMapper.insert(cloneIgnoreId(dbDocument, o -> o.setUploadDate(null)));
+       // 测试 uploadedBy 不匹配
+       documentMapper.insert(cloneIgnoreId(dbDocument, o -> o.setUploadedBy(null)));
+       // 测试 createTime 不匹配
+       documentMapper.insert(cloneIgnoreId(dbDocument, o -> o.setCreateTime(null)));
+       // 准备参数
+       MuseumsDocumentPageReqVO reqVO = new MuseumsDocumentPageReqVO();
+       reqVO.setFileName(null);
+       reqVO.setConfigId(null);
+       reqVO.setPath(null);
+       reqVO.setUrl(null);
+       reqVO.setFileSize(null);
+       reqVO.setFileType(null);
+       reqVO.setUploadDate(buildBetweenTime(2023, 2, 1, 2023, 2, 28));
+       reqVO.setUploadedBy(null);
+       reqVO.setCreateTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28));
+
+       // 调用
+       PageResult<MuseumsDocumentDO> pageResult = documentService.getDocumentPage(reqVO);
+       // 断言
+       assertEquals(1, pageResult.getTotal());
+       assertEquals(1, pageResult.getList().size());
+       assertPojoEquals(dbDocument, pageResult.getList().get(0));
+    }
+
+}

+ 150 - 0
yudao-module-museums/yudao-module-museums-biz/src/test/java/cn/iocoder/yudao/module/museums/service/photogroup/PhotoGroupServiceImplTest.java

@@ -0,0 +1,150 @@
+package cn.iocoder.yudao.module.museums.service.photogroup;
+
+import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.test.mock.mockito.MockBean;
+
+import javax.annotation.Resource;
+
+import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
+
+import cn.iocoder.yudao.module.museums.controller.admin.photogroup.vo.*;
+import cn.iocoder.yudao.module.museums.dal.dataobject.photogroup.PhotoGroupDO;
+import cn.iocoder.yudao.module.museums.dal.mysql.photogroup.PhotoGroupMapper;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+
+import javax.annotation.Resource;
+import org.springframework.context.annotation.Import;
+import java.util.*;
+import java.time.LocalDateTime;
+
+import static cn.hutool.core.util.RandomUtil.*;
+import static cn.iocoder.yudao.module.museums.enums.ErrorCodeConstants.*;
+import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.*;
+import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*;
+import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.*;
+import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.*;
+import static cn.iocoder.yudao.framework.common.util.date.DateUtils.*;
+import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.Mockito.*;
+
+/**
+ * {@link PhotoGroupServiceImpl} 的单元测试类
+ *
+ * @author qpw
+ */
+@Import(PhotoGroupServiceImpl.class)
+public class PhotoGroupServiceImplTest extends BaseDbUnitTest {
+
+    @Resource
+    private PhotoGroupServiceImpl photoGroupService;
+
+    @Resource
+    private PhotoGroupMapper photoGroupMapper;
+
+    @Test
+    public void testCreatePhotoGroup_success() {
+        // 准备参数
+        PhotoGroupSaveReqVO createReqVO = randomPojo(PhotoGroupSaveReqVO.class).setId(null);
+
+        // 调用
+        Integer photoGroupId = photoGroupService.createPhotoGroup(createReqVO);
+        // 断言
+        assertNotNull(photoGroupId);
+        // 校验记录的属性是否正确
+        PhotoGroupDO photoGroup = photoGroupMapper.selectById(photoGroupId);
+        assertPojoEquals(createReqVO, photoGroup, "id");
+    }
+
+    @Test
+    public void testUpdatePhotoGroup_success() {
+        // mock 数据
+        PhotoGroupDO dbPhotoGroup = randomPojo(PhotoGroupDO.class);
+        photoGroupMapper.insert(dbPhotoGroup);// @Sql: 先插入出一条存在的数据
+        // 准备参数
+        PhotoGroupSaveReqVO updateReqVO = randomPojo(PhotoGroupSaveReqVO.class, o -> {
+            o.setId(dbPhotoGroup.getId()); // 设置更新的 ID
+        });
+
+        // 调用
+        photoGroupService.updatePhotoGroup(updateReqVO);
+        // 校验是否更新正确
+        PhotoGroupDO photoGroup = photoGroupMapper.selectById(updateReqVO.getId()); // 获取最新的
+        assertPojoEquals(updateReqVO, photoGroup);
+    }
+
+    @Test
+    public void testUpdatePhotoGroup_notExists() {
+        // 准备参数
+        PhotoGroupSaveReqVO updateReqVO = randomPojo(PhotoGroupSaveReqVO.class);
+
+        // 调用, 并断言异常
+        assertServiceException(() -> photoGroupService.updatePhotoGroup(updateReqVO), PHOTO_GROUP_NOT_EXISTS);
+    }
+
+    @Test
+    public void testDeletePhotoGroup_success() {
+        // mock 数据
+        PhotoGroupDO dbPhotoGroup = randomPojo(PhotoGroupDO.class);
+        photoGroupMapper.insert(dbPhotoGroup);// @Sql: 先插入出一条存在的数据
+        // 准备参数
+        Integer id = dbPhotoGroup.getId();
+
+        // 调用
+        photoGroupService.deletePhotoGroup(id);
+       // 校验数据不存在了
+       assertNull(photoGroupMapper.selectById(id));
+    }
+
+    @Test
+    public void testDeletePhotoGroup_notExists() {
+        // 准备参数
+        Integer id = randomIntegerId();
+
+        // 调用, 并断言异常
+        assertServiceException(() -> photoGroupService.deletePhotoGroup(id), PHOTO_GROUP_NOT_EXISTS);
+    }
+
+    @Test
+    @Disabled  // TODO 请修改 null 为需要的值,然后删除 @Disabled 注解
+    public void testGetPhotoGroupPage() {
+       // mock 数据
+       PhotoGroupDO dbPhotoGroup = randomPojo(PhotoGroupDO.class, o -> { // 等会查询到
+           o.setGroupName(null);
+           o.setGroupDate(null);
+           o.setGroupDescription(null);
+           o.setCreatedAt(null);
+           o.setCreateTime(null);
+           o.setUploadPhotos(null);
+       });
+       photoGroupMapper.insert(dbPhotoGroup);
+       // 测试 groupName 不匹配
+       photoGroupMapper.insert(cloneIgnoreId(dbPhotoGroup, o -> o.setGroupName(null)));
+       // 测试 groupDate 不匹配
+       photoGroupMapper.insert(cloneIgnoreId(dbPhotoGroup, o -> o.setGroupDate(null)));
+       // 测试 groupDescription 不匹配
+       photoGroupMapper.insert(cloneIgnoreId(dbPhotoGroup, o -> o.setGroupDescription(null)));
+       // 测试 createdAt 不匹配
+       photoGroupMapper.insert(cloneIgnoreId(dbPhotoGroup, o -> o.setCreatedAt(null)));
+       // 测试 createTime 不匹配
+       photoGroupMapper.insert(cloneIgnoreId(dbPhotoGroup, o -> o.setCreateTime(null)));
+       // 测试 uploadPhotos 不匹配
+       photoGroupMapper.insert(cloneIgnoreId(dbPhotoGroup, o -> o.setUploadPhotos(null)));
+       // 准备参数
+       PhotoGroupPageReqVO reqVO = new PhotoGroupPageReqVO();
+       reqVO.setGroupName(null);
+       reqVO.setGroupDate(buildBetweenTime(2023, 2, 1, 2023, 2, 28));
+       reqVO.setGroupDescription(null);
+       reqVO.setCreatedAt(null);
+       reqVO.setCreateTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28));
+       reqVO.setUploadPhotos(null);
+
+       // 调用
+       PageResult<PhotoGroupDO> pageResult = photoGroupService.getPhotoGroupPage(reqVO);
+       // 断言
+       assertEquals(1, pageResult.getTotal());
+       assertEquals(1, pageResult.getList().size());
+       assertPojoEquals(dbPhotoGroup, pageResult.getList().get(0));
+    }
+
+}

+ 142 - 0
yudao-module-museums/yudao-module-museums-biz/src/test/java/cn/iocoder/yudao/module/museums/service/photos/PhotosServiceImplTest.java

@@ -0,0 +1,142 @@
+package cn.iocoder.yudao.module.museums.service.photos;
+
+import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.test.mock.mockito.MockBean;
+
+import javax.annotation.Resource;
+
+import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
+
+import cn.iocoder.yudao.module.museums.controller.admin.photos.vo.*;
+import cn.iocoder.yudao.module.museums.dal.dataobject.photos.PhotosDO;
+import cn.iocoder.yudao.module.museums.dal.mysql.photos.PhotosMapper;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+
+import javax.annotation.Resource;
+import org.springframework.context.annotation.Import;
+import java.util.*;
+import java.time.LocalDateTime;
+
+import static cn.hutool.core.util.RandomUtil.*;
+import static cn.iocoder.yudao.module.museums.enums.ErrorCodeConstants.*;
+import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.*;
+import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*;
+import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.*;
+import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.*;
+import static cn.iocoder.yudao.framework.common.util.date.DateUtils.*;
+import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.Mockito.*;
+
+/**
+ * {@link PhotosServiceImpl} 的单元测试类
+ *
+ * @author qpw
+ */
+@Import(PhotosServiceImpl.class)
+public class PhotosServiceImplTest extends BaseDbUnitTest {
+
+    @Resource
+    private PhotosServiceImpl photosService;
+
+    @Resource
+    private PhotosMapper photosMapper;
+
+    @Test
+    public void testCreatePhotos_success() {
+        // 准备参数
+        PhotosSaveReqVO createReqVO = randomPojo(PhotosSaveReqVO.class).setId(null);
+
+        // 调用
+        Integer photosId = photosService.createPhotos(createReqVO);
+        // 断言
+        assertNotNull(photosId);
+        // 校验记录的属性是否正确
+        PhotosDO photos = photosMapper.selectById(photosId);
+        assertPojoEquals(createReqVO, photos, "id");
+    }
+
+    @Test
+    public void testUpdatePhotos_success() {
+        // mock 数据
+        PhotosDO dbPhotos = randomPojo(PhotosDO.class);
+        photosMapper.insert(dbPhotos);// @Sql: 先插入出一条存在的数据
+        // 准备参数
+        PhotosSaveReqVO updateReqVO = randomPojo(PhotosSaveReqVO.class, o -> {
+            o.setId(dbPhotos.getId()); // 设置更新的 ID
+        });
+
+        // 调用
+        photosService.updatePhotos(updateReqVO);
+        // 校验是否更新正确
+        PhotosDO photos = photosMapper.selectById(updateReqVO.getId()); // 获取最新的
+        assertPojoEquals(updateReqVO, photos);
+    }
+
+    @Test
+    public void testUpdatePhotos_notExists() {
+        // 准备参数
+        PhotosSaveReqVO updateReqVO = randomPojo(PhotosSaveReqVO.class);
+
+        // 调用, 并断言异常
+        assertServiceException(() -> photosService.updatePhotos(updateReqVO), PHOTOS_NOT_EXISTS);
+    }
+
+    @Test
+    public void testDeletePhotos_success() {
+        // mock 数据
+        PhotosDO dbPhotos = randomPojo(PhotosDO.class);
+        photosMapper.insert(dbPhotos);// @Sql: 先插入出一条存在的数据
+        // 准备参数
+        Integer id = dbPhotos.getId();
+
+        // 调用
+        photosService.deletePhotos(id);
+       // 校验数据不存在了
+       assertNull(photosMapper.selectById(id));
+    }
+
+    @Test
+    public void testDeletePhotos_notExists() {
+        // 准备参数
+        Integer id = randomIntegerId();
+
+        // 调用, 并断言异常
+        assertServiceException(() -> photosService.deletePhotos(id), PHOTOS_NOT_EXISTS);
+    }
+
+    @Test
+    @Disabled  // TODO 请修改 null 为需要的值,然后删除 @Disabled 注解
+    public void testGetPhotosPage() {
+       // mock 数据
+       PhotosDO dbPhotos = randomPojo(PhotosDO.class, o -> { // 等会查询到
+           o.setGroupId(null);
+           o.setPhotoUrl(null);
+           o.setCreatedAt(null);
+           o.setCreateTime(null);
+       });
+       photosMapper.insert(dbPhotos);
+       // 测试 groupId 不匹配
+       photosMapper.insert(cloneIgnoreId(dbPhotos, o -> o.setGroupId(null)));
+       // 测试 photoUrl 不匹配
+       photosMapper.insert(cloneIgnoreId(dbPhotos, o -> o.setPhotoUrl(null)));
+       // 测试 createdAt 不匹配
+       photosMapper.insert(cloneIgnoreId(dbPhotos, o -> o.setCreatedAt(null)));
+       // 测试 createTime 不匹配
+       photosMapper.insert(cloneIgnoreId(dbPhotos, o -> o.setCreateTime(null)));
+       // 准备参数
+       PhotosPageReqVO reqVO = new PhotosPageReqVO();
+       reqVO.setGroupId(null);
+       reqVO.setPhotoUrl(null);
+       reqVO.setCreatedAt(null);
+       reqVO.setCreateTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28));
+
+       // 调用
+       PageResult<PhotosDO> pageResult = photosService.getPhotosPage(reqVO);
+       // 断言
+       assertEquals(1, pageResult.getTotal());
+       assertEquals(1, pageResult.getList().size());
+       assertPojoEquals(dbPhotos, pageResult.getList().get(0));
+    }
+
+}

+ 234 - 0
yudao-module-museums/yudao-module-museums-biz/src/test/java/cn/iocoder/yudao/module/museums/service/specimeninfo/SpecimenInfoServiceImplTest.java

@@ -0,0 +1,234 @@
+//package cn.iocoder.yudao.module.museums.service.specimeninfo;
+//
+//import org.junit.jupiter.api.Disabled;
+//import org.junit.jupiter.api.Test;
+//
+//import cn.iocoder.yudao.module.museums.controller.admin.specimeninfo.vo.*;
+//import cn.iocoder.yudao.module.museums.dal.dataobject.specimeninfo.SpecimenInfoDO;
+//import cn.iocoder.yudao.module.museums.dal.mysql.specimeninfo.SpecimenInfoMapper;
+//import cn.iocoder.yudao.framework.common.pojo.PageResult;
+//
+//import javax.annotation.Resource;
+//import org.springframework.context.annotation.Import;
+//
+//import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.*;
+//import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.*;
+//import static cn.iocoder.yudao.framework.common.util.date.DateUtils.*;
+//import static org.junit.jupiter.api.Assertions.*;
+//
+///**
+// * {@link SpecimenInfoServiceImpl} 的单元测试类
+// *
+// * @author 普伟
+// */
+//@Import(SpecimenInfoServiceImpl.class)
+//public class SpecimenInfoServiceImplTest extends BaseDbUnitTest {
+//
+//    @Resource
+//    private SpecimenInfoServiceImpl specimenInfoService;
+//
+//    @Resource
+//    private SpecimenInfoMapper specimenInfoMapper;
+//
+//    @Test
+//    public void testCreateSpecimenInfo_success() {
+//        // 准备参数
+//        SpecimenInfoSaveReqVO createReqVO = randomPojo(SpecimenInfoSaveReqVO.class).setId(null);
+//
+//        // 调用
+//        Integer specimenInfoId = specimenInfoService.createSpecimenInfo(createReqVO);
+//        // 断言
+//        assertNotNull(specimenInfoId);
+//        // 校验记录的属性是否正确
+//        SpecimenInfoDO specimenInfo = specimenInfoMapper.selectById(specimenInfoId);
+//        assertPojoEquals(createReqVO, specimenInfo, "id");
+//    }
+//
+//    @Test
+//    public void testUpdateSpecimenInfo_success() {
+//        // mock 数据
+//        SpecimenInfoDO dbSpecimenInfo = randomPojo(SpecimenInfoDO.class);
+//        specimenInfoMapper.insert(dbSpecimenInfo);// @Sql: 先插入出一条存在的数据
+//        // 准备参数
+//        SpecimenInfoSaveReqVO updateReqVO = randomPojo(SpecimenInfoSaveReqVO.class, o -> {
+//            o.setId(dbSpecimenInfo.getId()); // 设置更新的 ID
+//        });
+//
+//        // 调用
+//        specimenInfoService.updateSpecimenInfo(updateReqVO);
+//        // 校验是否更新正确
+//        SpecimenInfoDO specimenInfo = specimenInfoMapper.selectById(updateReqVO.getId()); // 获取最新的
+//        assertPojoEquals(updateReqVO, specimenInfo);
+//    }
+//
+//    @Test
+//    public void testUpdateSpecimenInfo_notExists() {
+//        // 准备参数
+//        SpecimenInfoSaveReqVO updateReqVO = randomPojo(SpecimenInfoSaveReqVO.class);
+//
+//        // 调用, 并断言异常
+//        assertServiceException(() -> specimenInfoService.updateSpecimenInfo(updateReqVO), SPECIMEN_INFO_NOT_EXISTS);
+//    }
+//
+//    @Test
+//    public void testDeleteSpecimenInfo_success() {
+//        // mock 数据
+//        SpecimenInfoDO dbSpecimenInfo = randomPojo(SpecimenInfoDO.class);
+//        specimenInfoMapper.insert(dbSpecimenInfo);// @Sql: 先插入出一条存在的数据
+//        // 准备参数
+//        Integer id = dbSpecimenInfo.getId();
+//
+//        // 调用
+//        specimenInfoService.deleteSpecimenInfo(id);
+//       // 校验数据不存在了
+//       assertNull(specimenInfoMapper.selectById(id));
+//    }
+//
+//    @Test
+//    public void testDeleteSpecimenInfo_notExists() {
+//        // 准备参数
+//        Integer id = randomIntegerId();
+//
+//        // 调用, 并断言异常
+//        assertServiceException(() -> specimenInfoService.deleteSpecimenInfo(id), SPECIMEN_INFO_NOT_EXISTS);
+//    }
+//
+//    @Test
+//    @Disabled  // TODO 请修改 null 为需要的值,然后删除 @Disabled 注解
+//    public void testGetSpecimenInfoPage() {
+//       // mock 数据
+//       SpecimenInfoDO dbSpecimenInfo = randomPojo(SpecimenInfoDO.class, o -> { // 等会查询到
+//           o.setSpecimenType(null);
+//           o.setSpecimenNumber(null);
+//           o.setAssetNumber(null);
+//           o.setStorageLocation(null);
+//           o.setChineseName(null);
+//           o.setEnglishName(null);
+//           o.setComposition(null);
+//           o.setOrigin(null);
+//           o.setEra(null);
+//           o.setPreservedLayer(null);
+//           o.setMeteoriteType(null);
+//           o.setInternationalName(null);
+//           o.setDiscoveryTime(null);
+//           o.setFallTime(null);
+//           o.setPreservationType(null);
+//           o.setSize(null);
+//           o.setWeight(null);
+//           o.setSource(null);
+//           o.setProvider(null);
+//           o.setAcquisitionTime(null);
+//           o.setPurpose(null);
+//           o.setDescription(null);
+//           o.setCollectionStatus(null);
+//           o.setNotes(null);
+//           o.setImageName(null);
+//           o.setImagePath(null);
+//           o.setCreateTime(null);
+//           o.setDeletedReason(null);
+//           o.setOperator(null);
+//           o.setEntryDate(null);
+//       });
+//       specimenInfoMapper.insert(dbSpecimenInfo);
+//       // 测试 specimenType 不匹配
+//       specimenInfoMapper.insert(cloneIgnoreId(dbSpecimenInfo, o -> o.setSpecimenType(null)));
+//       // 测试 specimenNumber 不匹配
+//       specimenInfoMapper.insert(cloneIgnoreId(dbSpecimenInfo, o -> o.setSpecimenNumber(null)));
+//       // 测试 assetNumber 不匹配
+//       specimenInfoMapper.insert(cloneIgnoreId(dbSpecimenInfo, o -> o.setAssetNumber(null)));
+//       // 测试 storageLocation 不匹配
+//       specimenInfoMapper.insert(cloneIgnoreId(dbSpecimenInfo, o -> o.setStorageLocation(null)));
+//       // 测试 chineseName 不匹配
+//       specimenInfoMapper.insert(cloneIgnoreId(dbSpecimenInfo, o -> o.setChineseName(null)));
+//       // 测试 englishName 不匹配
+//       specimenInfoMapper.insert(cloneIgnoreId(dbSpecimenInfo, o -> o.setEnglishName(null)));
+//       // 测试 composition 不匹配
+//       specimenInfoMapper.insert(cloneIgnoreId(dbSpecimenInfo, o -> o.setComposition(null)));
+//       // 测试 origin 不匹配
+//       specimenInfoMapper.insert(cloneIgnoreId(dbSpecimenInfo, o -> o.setOrigin(null)));
+//       // 测试 era 不匹配
+//       specimenInfoMapper.insert(cloneIgnoreId(dbSpecimenInfo, o -> o.setEra(null)));
+//       // 测试 preservedLayer 不匹配
+//       specimenInfoMapper.insert(cloneIgnoreId(dbSpecimenInfo, o -> o.setPreservedLayer(null)));
+//       // 测试 meteoriteType 不匹配
+//       specimenInfoMapper.insert(cloneIgnoreId(dbSpecimenInfo, o -> o.setMeteoriteType(null)));
+//       // 测试 internationalName 不匹配
+//       specimenInfoMapper.insert(cloneIgnoreId(dbSpecimenInfo, o -> o.setInternationalName(null)));
+//       // 测试 discoveryTime 不匹配
+//       specimenInfoMapper.insert(cloneIgnoreId(dbSpecimenInfo, o -> o.setDiscoveryTime(null)));
+//       // 测试 fallTime 不匹配
+//       specimenInfoMapper.insert(cloneIgnoreId(dbSpecimenInfo, o -> o.setFallTime(null)));
+//       // 测试 preservationType 不匹配
+//       specimenInfoMapper.insert(cloneIgnoreId(dbSpecimenInfo, o -> o.setPreservationType(null)));
+//       // 测试 size 不匹配
+//       specimenInfoMapper.insert(cloneIgnoreId(dbSpecimenInfo, o -> o.setSize(null)));
+//       // 测试 weight 不匹配
+//       specimenInfoMapper.insert(cloneIgnoreId(dbSpecimenInfo, o -> o.setWeight(null)));
+//       // 测试 source 不匹配
+//       specimenInfoMapper.insert(cloneIgnoreId(dbSpecimenInfo, o -> o.setSource(null)));
+//       // 测试 provider 不匹配
+//       specimenInfoMapper.insert(cloneIgnoreId(dbSpecimenInfo, o -> o.setProvider(null)));
+//       // 测试 acquisitionTime 不匹配
+//       specimenInfoMapper.insert(cloneIgnoreId(dbSpecimenInfo, o -> o.setAcquisitionTime(null)));
+//       // 测试 purpose 不匹配
+//       specimenInfoMapper.insert(cloneIgnoreId(dbSpecimenInfo, o -> o.setPurpose(null)));
+//       // 测试 description 不匹配
+//       specimenInfoMapper.insert(cloneIgnoreId(dbSpecimenInfo, o -> o.setDescription(null)));
+//       // 测试 collectionStatus 不匹配
+//       specimenInfoMapper.insert(cloneIgnoreId(dbSpecimenInfo, o -> o.setCollectionStatus(null)));
+//       // 测试 notes 不匹配
+//       specimenInfoMapper.insert(cloneIgnoreId(dbSpecimenInfo, o -> o.setNotes(null)));
+//       // 测试 imageName 不匹配
+//       specimenInfoMapper.insert(cloneIgnoreId(dbSpecimenInfo, o -> o.setImageName(null)));
+//       // 测试 imagePath 不匹配
+//       specimenInfoMapper.insert(cloneIgnoreId(dbSpecimenInfo, o -> o.setImagePath(null)));
+//       // 测试 createTime 不匹配
+//       specimenInfoMapper.insert(cloneIgnoreId(dbSpecimenInfo, o -> o.setCreateTime(null)));
+//       // 测试 deletedReason 不匹配
+//       specimenInfoMapper.insert(cloneIgnoreId(dbSpecimenInfo, o -> o.setDeletedReason(null)));
+//       // 测试 operator 不匹配
+//       specimenInfoMapper.insert(cloneIgnoreId(dbSpecimenInfo, o -> o.setOperator(null)));
+//       // 测试 entryDate 不匹配
+//       specimenInfoMapper.insert(cloneIgnoreId(dbSpecimenInfo, o -> o.setEntryDate(null)));
+//       // 准备参数
+//       SpecimenInfoPageReqVO reqVO = new SpecimenInfoPageReqVO();
+//       reqVO.setSpecimenType(null);
+//       reqVO.setSpecimenNumber(null);
+//       reqVO.setAssetNumber(null);
+//       reqVO.setStorageLocation(null);
+//       reqVO.setChineseName(null);
+//       reqVO.setEnglishName(null);
+//       reqVO.setComposition(null);
+//       reqVO.setOrigin(null);
+//       reqVO.setEra(null);
+//       reqVO.setPreservedLayer(null);
+//       reqVO.setMeteoriteType(null);
+//       reqVO.setInternationalName(null);
+//       reqVO.setDiscoveryTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28));
+//       reqVO.setFallTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28));
+//       reqVO.setPreservationType(null);
+//       reqVO.setSize(null);
+//       reqVO.setWeight(null);
+//       reqVO.setSource(null);
+//       reqVO.setProvider(null);
+//       reqVO.setAcquisitionTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28));
+//       reqVO.setPurpose(null);
+//       reqVO.setDescription(null);
+//       reqVO.setCollectionStatus(null);
+//       reqVO.setNotes(null);
+//       reqVO.setImageName(null);
+//       reqVO.setImagePath(null);
+//       reqVO.setCreateTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28));
+//       reqVO.setDeletedReason(null);
+//       reqVO.setOperator(null);
+//       reqVO.setEntryDate(buildBetweenTime(2023, 2, 1, 2023, 2, 28));
+//
+//       // 调用
+//       PageResult<SpecimenInfoDO> pageResult = specimenInfoService.getSpecimenInfoPage(reqVO);
+//       // 断言
+//       assertEquals(1, pageResult.getTotal());
+//       assertEquals(1, pageResult.getList().size());
+//       assertPojoEquals(dbSpecimenInfo, pageResult.getList().get(0));
+//    }
+//
+//}

+ 198 - 0
yudao-module-museums/yudao-module-museums-biz/src/test/java/cn/iocoder/yudao/module/museums/service/specimenoutbound/SpecimenOutboundServiceImplTest.java

@@ -0,0 +1,198 @@
+//package cn.iocoder.yudao.module.museums.service.specimenoutbound;
+//
+//import org.junit.jupiter.api.Disabled;
+//import org.junit.jupiter.api.Test;
+//import org.springframework.boot.test.mock.mockito.MockBean;
+//
+//import javax.annotation.Resource;
+//
+//import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
+//
+//import cn.iocoder.yudao.module.museums.controller.admin.specimenoutbound.vo.*;
+//import cn.iocoder.yudao.module.museums.dal.dataobject.specimenoutbound.SpecimenOutboundDO;
+//import cn.iocoder.yudao.module.museums.dal.mysql.specimenoutbound.SpecimenOutboundMapper;
+//import cn.iocoder.yudao.framework.common.pojo.PageResult;
+//
+//import javax.annotation.Resource;
+//import org.springframework.context.annotation.Import;
+//import java.util.*;
+//import java.time.LocalDateTime;
+//
+//import static cn.hutool.core.util.RandomUtil.*;
+//import static cn.iocoder.yudao.module.museums.enums.ErrorCodeConstants.*;
+//import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.*;
+//import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*;
+//import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.*;
+//import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.*;
+//import static cn.iocoder.yudao.framework.common.util.date.DateUtils.*;
+//import static org.junit.jupiter.api.Assertions.*;
+//import static org.mockito.Mockito.*;
+//
+///**
+// * {@link SpecimenOutboundServiceImpl} 的单元测试类
+// *
+// * @author qpw
+// */
+//@Import(SpecimenOutboundServiceImpl.class)
+//public class SpecimenOutboundServiceImplTest extends BaseDbUnitTest {
+//
+//    @Resource
+//    private SpecimenOutboundServiceImpl specimenOutboundService;
+//
+//    @Resource
+//    private SpecimenOutboundMapper specimenOutboundMapper;
+//
+//    @Test
+//    public void testCreateSpecimenOutbound_success() {
+//        // 准备参数
+//        SpecimenOutboundSaveReqVO createReqVO = randomPojo(SpecimenOutboundSaveReqVO.class).setId(null);
+//
+//        // 调用
+//        Integer specimenOutboundId = specimenOutboundService.createSpecimenOutbound(createReqVO);
+//        // 断言
+//        assertNotNull(specimenOutboundId);
+//        // 校验记录的属性是否正确
+//        SpecimenOutboundDO specimenOutbound = specimenOutboundMapper.selectById(specimenOutboundId);
+//        assertPojoEquals(createReqVO, specimenOutbound, "id");
+//    }
+//
+//    @Test
+//    public void testUpdateSpecimenOutbound_success() {
+//        // mock 数据
+//        SpecimenOutboundDO dbSpecimenOutbound = randomPojo(SpecimenOutboundDO.class);
+//        specimenOutboundMapper.insert(dbSpecimenOutbound);// @Sql: 先插入出一条存在的数据
+//        // 准备参数
+//        SpecimenOutboundSaveReqVO updateReqVO = randomPojo(SpecimenOutboundSaveReqVO.class, o -> {
+//            o.setId(dbSpecimenOutbound.getId()); // 设置更新的 ID
+//        });
+//
+//        // 调用
+//        specimenOutboundService.updateSpecimenOutbound(updateReqVO);
+//        // 校验是否更新正确
+//        SpecimenOutboundDO specimenOutbound = specimenOutboundMapper.selectById(updateReqVO.getId()); // 获取最新的
+//        assertPojoEquals(updateReqVO, specimenOutbound);
+//    }
+//
+//    @Test
+//    public void testUpdateSpecimenOutbound_notExists() {
+//        // 准备参数
+//        SpecimenOutboundSaveReqVO updateReqVO = randomPojo(SpecimenOutboundSaveReqVO.class);
+//
+//        // 调用, 并断言异常
+//        assertServiceException(() -> specimenOutboundService.updateSpecimenOutbound(updateReqVO), SPECIMEN_OUTBOUND_NOT_EXISTS);
+//    }
+//
+//    @Test
+//    public void testDeleteSpecimenOutbound_success() {
+//        // mock 数据
+//        SpecimenOutboundDO dbSpecimenOutbound = randomPojo(SpecimenOutboundDO.class);
+//        specimenOutboundMapper.insert(dbSpecimenOutbound);// @Sql: 先插入出一条存在的数据
+//        // 准备参数
+//        Integer id = dbSpecimenOutbound.getId();
+//
+//        // 调用
+//        specimenOutboundService.deleteSpecimenOutbound(id);
+//       // 校验数据不存在了
+//       assertNull(specimenOutboundMapper.selectById(id));
+//    }
+//
+//    @Test
+//    public void testDeleteSpecimenOutbound_notExists() {
+//        // 准备参数
+//        Integer id = randomIntegerId();
+//
+//        // 调用, 并断言异常
+//        assertServiceException(() -> specimenOutboundService.deleteSpecimenOutbound(id), SPECIMEN_OUTBOUND_NOT_EXISTS);
+//    }
+//
+//    @Test
+//    @Disabled  // TODO 请修改 null 为需要的值,然后删除 @Disabled 注解
+//    public void testGetSpecimenOutboundPage() {
+//       // mock 数据
+//       SpecimenOutboundDO dbSpecimenOutbound = randomPojo(SpecimenOutboundDO.class, o -> { // 等会查询到
+//           o.setInfoId(null);
+//           o.setChineseName(null);
+//           o.setSpecimenNumber(null);
+//           o.setApplicantName(null);
+//           o.setApplicationDate(null);
+//           o.setApplicationUsage(null);
+//           o.setAttachments(null);
+//           o.setStatus(null);
+//           o.setRemarks(null);
+//           o.setProcessInstanceId(null);
+//           o.setOperator(null);
+//           o.setOutgoingTime(null);
+//           o.setReturner(null);
+//           o.setReceiver(null);
+//           o.setReturnDate(null);
+//           o.setSpecimenCondition(null);
+//           o.setCreateTime(null);
+//           o.setSampleStatus(null);
+//       });
+//       specimenOutboundMapper.insert(dbSpecimenOutbound);
+//       // 测试 infoId 不匹配
+//       specimenOutboundMapper.insert(cloneIgnoreId(dbSpecimenOutbound, o -> o.setInfoId(null)));
+//       // 测试 chineseName 不匹配
+//       specimenOutboundMapper.insert(cloneIgnoreId(dbSpecimenOutbound, o -> o.setChineseName(null)));
+//       // 测试 specimenNumber 不匹配
+//       specimenOutboundMapper.insert(cloneIgnoreId(dbSpecimenOutbound, o -> o.setSpecimenNumber(null)));
+//       // 测试 applicantName 不匹配
+//       specimenOutboundMapper.insert(cloneIgnoreId(dbSpecimenOutbound, o -> o.setApplicantName(null)));
+//       // 测试 applicationDate 不匹配
+//       specimenOutboundMapper.insert(cloneIgnoreId(dbSpecimenOutbound, o -> o.setApplicationDate(null)));
+//       // 测试 applicationUsage 不匹配
+//       specimenOutboundMapper.insert(cloneIgnoreId(dbSpecimenOutbound, o -> o.setApplicationUsage(null)));
+//       // 测试 attachments 不匹配
+//       specimenOutboundMapper.insert(cloneIgnoreId(dbSpecimenOutbound, o -> o.setAttachments(null)));
+//       // 测试 status 不匹配
+//       specimenOutboundMapper.insert(cloneIgnoreId(dbSpecimenOutbound, o -> o.setStatus(null)));
+//       // 测试 remarks 不匹配
+//       specimenOutboundMapper.insert(cloneIgnoreId(dbSpecimenOutbound, o -> o.setRemarks(null)));
+//       // 测试 processInstanceId 不匹配
+//       specimenOutboundMapper.insert(cloneIgnoreId(dbSpecimenOutbound, o -> o.setProcessInstanceId(null)));
+//       // 测试 operator 不匹配
+//       specimenOutboundMapper.insert(cloneIgnoreId(dbSpecimenOutbound, o -> o.setOperator(null)));
+//       // 测试 outgoingTime 不匹配
+//       specimenOutboundMapper.insert(cloneIgnoreId(dbSpecimenOutbound, o -> o.setOutgoingTime(null)));
+//       // 测试 returner 不匹配
+//       specimenOutboundMapper.insert(cloneIgnoreId(dbSpecimenOutbound, o -> o.setReturner(null)));
+//       // 测试 receiver 不匹配
+//       specimenOutboundMapper.insert(cloneIgnoreId(dbSpecimenOutbound, o -> o.setReceiver(null)));
+//       // 测试 returnDate 不匹配
+//       specimenOutboundMapper.insert(cloneIgnoreId(dbSpecimenOutbound, o -> o.setReturnDate(null)));
+//       // 测试 specimenCondition 不匹配
+//       specimenOutboundMapper.insert(cloneIgnoreId(dbSpecimenOutbound, o -> o.setSpecimenCondition(null)));
+//       // 测试 createTime 不匹配
+//       specimenOutboundMapper.insert(cloneIgnoreId(dbSpecimenOutbound, o -> o.setCreateTime(null)));
+//       // 测试 sampleStatus 不匹配
+//       specimenOutboundMapper.insert(cloneIgnoreId(dbSpecimenOutbound, o -> o.setSampleStatus(null)));
+//       // 准备参数
+//       SpecimenOutboundPageReqVO reqVO = new SpecimenOutboundPageReqVO();
+//       reqVO.setInfoId(null);
+//       reqVO.setChineseName(null);
+//       reqVO.setSpecimenNumber(null);
+//       reqVO.setApplicantName(null);
+//       reqVO.setApplicationDate(buildBetweenTime(2023, 2, 1, 2023, 2, 28));
+//       reqVO.setApplicationUsage(null);
+//       reqVO.setAttachments(null);
+//       reqVO.setStatus(null);
+//       reqVO.setRemarks(null);
+//       reqVO.setProcessInstanceId(null);
+//       reqVO.setOperator(null);
+//       reqVO.setOutgoingTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28));
+//       reqVO.setReturner(null);
+//       reqVO.setReceiver(null);
+//       reqVO.setReturnDate(buildBetweenTime(2023, 2, 1, 2023, 2, 28));
+//       reqVO.setSpecimenCondition(null);
+//       reqVO.setCreateTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28));
+//       reqVO.setSampleStatus(null);
+//
+//       // 调用
+//       PageResult<SpecimenOutboundDO> pageResult = specimenOutboundService.getSpecimenOutboundPage(reqVO);
+//       // 断言
+//       assertEquals(1, pageResult.getTotal());
+//       assertEquals(1, pageResult.getList().size());
+//       assertPojoEquals(dbSpecimenOutbound, pageResult.getList().get(0));
+//    }
+//
+//}

+ 1 - 0
yudao-module-museums/yudao-module-museums-biz/src/test/resources/clean.sql

@@ -0,0 +1 @@
+DELETE FROM "museums_specimen_outbound";

+ 27 - 0
yudao-module-museums/yudao-module-museums-biz/src/test/resources/create_tables.sql

@@ -0,0 +1,27 @@
+CREATE TABLE IF NOT EXISTS "museums_specimen_outbound" (
+                                                           "id" int NOT NULL GENERATED BY DEFAULT AS IDENTITY,
+                                                           "info_id" varchar NOT NULL,
+                                                           "chinese_name" varchar NOT NULL,
+                                                           "specimen_number" varchar NOT NULL,
+                                                           "applicant_name" varchar NOT NULL,
+                                                           "application_date" varchar,
+                                                           "application_usage" varchar NOT NULL,
+                                                           "attachments" varchar,
+                                                           "status" int,
+                                                           "remarks" varchar,
+                                                           "process_instance_id" varchar,
+                                                           "operator" varchar NOT NULL,
+                                                           "outgoing_time" varchar,
+                                                           "returner" varchar NOT NULL,
+                                                           "receiver" varchar NOT NULL,
+                                                           "return_date" varchar NOT NULL,
+                                                           "specimen_condition" varchar,
+                                                           "creator" varchar DEFAULT '',
+                                                           "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
+                                                           "updater" varchar DEFAULT '',
+                                                           "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+                                                           "deleted" bit NOT NULL DEFAULT FALSE,
+                                                           "tenant_id" bigint NOT NULL DEFAULT 0,
+                                                           "sample_status" int,
+                                                           PRIMARY KEY ("id")
+    ) COMMENT '标本出库回库信息表';

+ 12 - 0
yudao-server/pom.xml

@@ -32,6 +32,13 @@
             <version>${revision}</version>
         </dependency>
 
+        <!--                 地质博物馆相关模块。-->
+        <dependency>
+            <groupId>cn.iocoder.boot</groupId>
+            <artifactId>yudao-module-museums-biz</artifactId>
+            <version>${revision}</version>
+        </dependency>
+
         <!-- 会员中心。默认注释,保证编译速度 -->
 <!--        <dependency>-->
 <!--            <groupId>cn.iocoder.boot</groupId>-->
@@ -108,6 +115,9 @@
 <!--            <version>${revision}</version>-->
 <!--        </dependency>-->
 
+
+
+
         <!-- spring boot 配置所需依赖 -->
         <dependency>
             <groupId>org.springframework.boot</groupId>
@@ -121,6 +131,8 @@
             <artifactId>yudao-spring-boot-starter-protection</artifactId>
         </dependency>
 
+
+
     </dependencies>
 
     <build>

+ 9 - 9
yudao-server/src/main/resources/application-local.yaml

@@ -46,7 +46,7 @@ spring:
       primary: master
       datasource:
         master:
-          url: jdbc:mysql://127.0.0.1:3306/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true # MySQL Connector/J 8.X 连接的示例
+          url: jdbc:mysql://172.16.59.50:3306/museums?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true # MySQL Connector/J 8.X 连接的示例
           #          url: jdbc:mysql://127.0.0.1:3306/ruoyi-vue-pro?useSSL=true&allowPublicKeyRetrieval=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai # MySQL Connector/J 5.X 连接的示例
           #          url: jdbc:postgresql://127.0.0.1:5432/ruoyi-vue-pro # PostgreSQL 连接的示例
           #          url: jdbc:oracle:thin:@127.0.0.1:1521:xe # Oracle 连接的示例
@@ -54,8 +54,8 @@ spring:
           #          url: jdbc:dm://127.0.0.1:5236?schema=RUOYI_VUE_PRO # DM 连接的示例
           #          url: jdbc:kingbase8://127.0.0.1:54321/test  # 人大金仓 KingbaseES 连接的示例
           #          url: jdbc:postgresql://127.0.0.1:5432/postgres # OpenGauss 连接的示例
-          username: root
-          password: 123456
+          username: museums
+          password: Sx5mt8yn2epMbSrB
           #          username: sa # SQL Server 连接的示例
           #          password: Yudao@2024 # SQL Server 连接的示例
           #          username: SYSDBA # DM 连接的示例
@@ -64,16 +64,16 @@ spring:
           #          password: Yudao@2024 # OpenGauss 连接的示例
         slave: # 模拟从库,可根据自己需要修改
           lazy: true # 开启懒加载,保证启动速度
-          url: jdbc:mysql://127.0.0.1:3306/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true
-          username: root
-          password: 123456
+          url: jdbc:mysql://172.16.59.50:3306/museums?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true
+          username: museums
+          password: Sx5mt8yn2epMbSrB
 
   # Redis 配置。Redisson 默认的配置足够使用,一般不需要进行调优
   redis:
-    host: 127.0.0.1 # 地址
+    host: 172.16.59.50 # 地址
     port: 6379 # 端口
-    database: 0 # 数据库索引
-#    password: dev # 密码,建议生产环境开启
+    database: 1 # 数据库索引
+    password: 123456 # 密码,建议生产环境开启
 
 --- #################### 定时任务相关配置 ####################