Przeglądaj źródła

进销存管理-代码提交

huangguoce 14 godzin temu
rodzic
commit
af560faa68
100 zmienionych plików z 13363 dodań i 0 usunięć
  1. 175 0
      jeeplus-modules/jeeplus-psi-management/pom.xml
  2. 25 0
      jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/JeeplusPsiManagementApplication.java
  3. 250 0
      jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/collect/controller/PsiCollectController.java
  4. 63 0
      jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/collect/domain/PsiCollectBasic.java
  5. 46 0
      jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/collect/domain/PsiCollectBasicsReturn.java
  6. 46 0
      jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/collect/domain/PsiCollectBasicsReturnHi.java
  7. 119 0
      jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/collect/domain/PsiCollectDetailed.java
  8. 168 0
      jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/collect/domain/PsiCollectDetailedRecord.java
  9. 41 0
      jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/collect/mapper/PsiCollectBasicMapper.java
  10. 29 0
      jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/collect/mapper/PsiCollectBasicsReturnHiMapper.java
  11. 9 0
      jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/collect/mapper/PsiCollectBasicsReturnMapper.java
  12. 66 0
      jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/collect/mapper/PsiCollectDetailedMapper.java
  13. 16 0
      jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/collect/mapper/PsiCollectDetailedRecordMapper.java
  14. 72 0
      jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/collect/mapper/xml/PsiCollectBasicMapper.xml
  15. 44 0
      jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/collect/mapper/xml/PsiCollectBasicsReturnHiMapper.xml
  16. 139 0
      jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/collect/mapper/xml/PsiCollectDetailedMapper.xml
  17. 1056 0
      jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/collect/service/PsiCollectService.java
  18. 167 0
      jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/collect/service/dto/PsiCollectDto.java
  19. 52 0
      jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/collect/service/dto/PsiCollectExportDto.java
  20. 28 0
      jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/collect/service/dto/PsiWareHouseSummaryDto.java
  21. 83 0
      jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/contract/controller/PsiContractController.java
  22. 72 0
      jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/contract/domain/PsiContract.java
  23. 33 0
      jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/contract/domain/PsiContractUser.java
  24. 21 0
      jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/contract/mapper/PsiContractMapper.java
  25. 17 0
      jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/contract/mapper/PsiContractUserMapper.java
  26. 33 0
      jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/contract/mapper/xml/PsiContractMapper.xml
  27. 10 0
      jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/contract/mapper/xml/PsiContractUserMapper.xml
  28. 239 0
      jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/contract/service/PsiContractService.java
  29. 86 0
      jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/contract/service/dto/PsiContractInfoDto.java
  30. 72 0
      jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/foodPurchase/controller/PsiFoodPurchaseController.java
  31. 40 0
      jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/foodPurchase/domain/PsiFoodPurchaseBasic.java
  32. 39 0
      jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/foodPurchase/domain/PsiFoodPurchaseDetail.java
  33. 28 0
      jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/foodPurchase/mapper/PsiFoodPurchaseBasicMapper.java
  34. 16 0
      jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/foodPurchase/mapper/PsiFoodPurchaseDetailMapper.java
  35. 58 0
      jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/foodPurchase/mapper/xml/PsiFoodPurchaseBasicMapper.xml
  36. 45 0
      jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/foodPurchase/mapper/xml/PsiFoodPurchaseDetailMapper.xml
  37. 303 0
      jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/foodPurchase/service/PsiFoodPurchaseService.java
  38. 53 0
      jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/foodPurchase/service/dto/PsiFoodPurchaseDto.java
  39. 88 0
      jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/loss/controller/PsiLossController.java
  40. 39 0
      jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/loss/domain/PsiLossBasic.java
  41. 54 0
      jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/loss/domain/PsiLossDetailed.java
  42. 25 0
      jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/loss/mapper/PsiLossBasicMapper.java
  43. 16 0
      jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/loss/mapper/PsiLossDetailedMapper.java
  44. 54 0
      jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/loss/mapper/xml/PsiLossBasicMapper.xml
  45. 58 0
      jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/loss/mapper/xml/PsiLossDetailedMapper.xml
  46. 405 0
      jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/loss/service/PsiLossService.java
  47. 57 0
      jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/loss/service/dto/PsiLossDto.java
  48. 38 0
      jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/loss/service/dto/PsiLossExportDto.java
  49. 153 0
      jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/materialType/controller/PsiMaterialTypeController.java
  50. 86 0
      jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/materialType/domain/PsiMaterialTypeInfo.java
  51. 70 0
      jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/materialType/mapper/PsiMaterialTypeMapper.java
  52. 106 0
      jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/materialType/mapper/xml/PsiMaterialTypeMapper.xml
  53. 178 0
      jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/materialType/service/PsiMaterialTypeForTreeDataService.java
  54. 303 0
      jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/materialType/service/PsiMaterialTypeService.java
  55. 21 0
      jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/materialType/service/dto/PsiMaterialTypeDto.java
  56. 177 0
      jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/oss/controller/PsiOssController.java
  57. 802 0
      jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/oss/controller/PsiOssFileController.java
  58. 71 0
      jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/oss/domain/PsiWorkAttachment.java
  59. 84 0
      jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/oss/mapper/PsiOssServiceMapper.java
  60. 199 0
      jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/oss/mapper/xml/PsiOssServiceMapper.xml
  61. 478 0
      jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/oss/service/PsiOSSClientService.java
  62. 954 0
      jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/oss/service/PsiOssService.java
  63. 67 0
      jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/oss/service/dto/AttachmentDTO.java
  64. 12 0
      jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/oss/service/dto/DownToOssDTO.java
  65. 11 0
      jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/oss/service/dto/FileDetailDTO.java
  66. 12 0
      jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/oss/service/dto/FileUrlDto.java
  67. 6 0
      jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/oss/service/dto/OssServiceDto.java
  68. 20 0
      jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/oss/service/dto/WorkAttachmentDto.java
  69. 53 0
      jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/oss/utils/FileUtil.java
  70. 354 0
      jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/psiWareHouse/controller/PsiWareHouseController.java
  71. 85 0
      jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/psiWareHouse/domain/PsiWareHouseBasic.java
  72. 173 0
      jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/psiWareHouse/domain/PsiWareHouseDetailed.java
  73. 35 0
      jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/psiWareHouse/domain/PsiWareHouseSummary.java
  74. 59 0
      jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/psiWareHouse/domain/PsiWarehouseUpHi.java
  75. 119 0
      jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/psiWareHouse/mapper/PsiWareHouseBasicMapper.java
  76. 62 0
      jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/psiWareHouse/mapper/PsiWareHouseDetailedMapper.java
  77. 47 0
      jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/psiWareHouse/mapper/PsiWareHouseSummaryMapper.java
  78. 27 0
      jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/psiWareHouse/mapper/PsiWarehouseUpHiMapper.java
  79. 468 0
      jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/psiWareHouse/mapper/xml/PsiWareHouseBasicMapper.xml
  80. 105 0
      jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/psiWareHouse/mapper/xml/PsiWareHouseDetailedMapper.xml
  81. 82 0
      jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/psiWareHouse/mapper/xml/PsiWareHouseSummaryMapper.xml
  82. 67 0
      jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/psiWareHouse/mapper/xml/PsiWarehouseUpHiMapper.xml
  83. 1283 0
      jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/psiWareHouse/service/PsiWareHouseBasicService.java
  84. 359 0
      jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/psiWareHouse/service/dto/PsiWareHouseDto.java
  85. 57 0
      jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/psiWareHouse/service/dto/PsiWareHouseExportDto.java
  86. 38 0
      jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/psiWareHouse/service/dto/PsiWareSummaryExportDto.java
  87. 94 0
      jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/purchase/controller/PsiMaterialController.java
  88. 74 0
      jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/purchase/domain/PsiMaterialBasic.java
  89. 124 0
      jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/purchase/domain/PsiMaterialDetailed.java
  90. 43 0
      jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/purchase/mapper/PsiMaterialBasicMapper.java
  91. 24 0
      jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/purchase/mapper/PsiMaterialDetailedMapper.java
  92. 71 0
      jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/purchase/mapper/xml/PsiMaterialBasicMapper.xml
  93. 44 0
      jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/purchase/mapper/xml/PsiMaterialDetailedMapper.xml
  94. 577 0
      jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/purchase/service/PsiMaterialService.java
  95. 36 0
      jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/purchase/service/dto/PsiMaterialExportDto.java
  96. 152 0
      jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/purchase/service/dto/PsiMaterialInfoDto.java
  97. 61 0
      jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/serialNumTpl/controller/PsiSerialnumTplController.java
  98. 64 0
      jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/serialNumTpl/domain/PsiSysSerialnumTpl.java
  99. 23 0
      jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/serialNumTpl/mapper/PsiSerialnumTplMapper.java
  100. 0 0
      jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/serialNumTpl/mapper/xml/PsiSerialnumTplMapper.xml

+ 175 - 0
jeeplus-modules/jeeplus-psi-management/pom.xml

@@ -0,0 +1,175 @@
+<?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>jeeplus-modules</artifactId>
+        <groupId>org.jeeplus</groupId>
+        <version>9.0</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>jeeplus-psi-management</artifactId>
+
+    <name>jeeplus-psi-management</name>
+    <description>psi-management project for Spring Boot</description>
+
+    <properties>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
+        <java.version>1.8</java.version>
+    </properties>
+
+    <dependencies>
+
+        <dependency>
+            <groupId>org.jeeplus</groupId>
+            <artifactId>jeeplus-common-mybatis-plus</artifactId>
+            <version>${project.parent.version}</version>
+        </dependency>
+        <!-- SpringCloud Alibaba Nacos -->
+        <dependency>
+            <groupId>com.alibaba.cloud</groupId>
+            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
+        </dependency>
+
+        <!-- SpringCloud Alibaba Nacos Config -->
+        <dependency>
+            <groupId>com.alibaba.cloud</groupId>
+            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
+        </dependency>
+
+        <!-- SpringCloud Alibaba Sentinel -->
+        <dependency>
+            <groupId>com.alibaba.cloud</groupId>
+            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.google.zxing</groupId>
+            <artifactId>core</artifactId>
+            <version>${zxing.core}</version>
+        </dependency>
+        <dependency>
+            <groupId>com.google.zxing</groupId>
+            <artifactId>javase</artifactId>
+            <version>${zxing.core}</version>
+        </dependency>
+
+        <!--添加actuator依赖-->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-actuator</artifactId>
+        </dependency>
+        <!--spring boot admin依赖-->
+        <dependency>
+            <groupId>de.codecentric</groupId>
+            <artifactId>spring-boot-admin-starter-client</artifactId>
+        </dependency>
+
+        <!-- 获取系统信息 -->
+        <dependency>
+            <groupId>com.github.oshi</groupId>
+            <artifactId>oshi-core</artifactId>
+            <version>${oshi.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>net.java.dev.jna</groupId>
+            <artifactId>jna-platform</artifactId>
+            <version>${jna.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>net.java.dev.jna</groupId>
+            <artifactId>jna</artifactId>
+            <version>${jna.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-web</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-websocket</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-mail</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.jeeplus</groupId>
+            <artifactId>jeeplus-common-core</artifactId>
+            <version>${project.parent.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.jeeplus</groupId>
+            <artifactId>jeeplus-common-security</artifactId>
+            <version>${project.parent.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.jeeplus</groupId>
+            <artifactId>jeeplus-system-api</artifactId>
+            <version>${project.parent.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.jeeplus</groupId>
+            <artifactId>jeeplus-common-log</artifactId>
+            <version>${project.parent.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.jeeplus</groupId>
+            <artifactId>jeeplus-common-swagger</artifactId>
+            <version>${project.parent.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>com.alibaba.cloud</groupId>
+            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>cn.hutool</groupId>
+            <artifactId>hutool-all</artifactId>
+            <version>${hutool.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.jeeplus</groupId>
+            <artifactId>jeeplus-public-modules</artifactId>
+            <version>${project.parent.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>com.aliyun.oss</groupId>
+            <artifactId>aliyun-sdk-oss</artifactId>
+            <version>${aliyun-sdk-oss.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-test</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.json</groupId>
+            <artifactId>json</artifactId>
+            <version>20210307</version> <!-- 使用最新稳定版本 -->
+        </dependency>
+
+    </dependencies>
+
+    <build>
+        <finalName>jeeplus-psi-management</finalName>
+        <plugins>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+                <version>2.1.2.RELEASE</version>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>repackage</goal>
+                        </goals>
+                    </execution>
+                </executions>
+                <configuration>
+
+                </configuration>
+            </plugin>
+
+        </plugins>
+    </build>
+</project>

+ 25 - 0
jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/JeeplusPsiManagementApplication.java

@@ -0,0 +1,25 @@
+package com.jeeplus.psimanage;
+
+import com.jeeplus.core.annotation.JeeplusCloudApplication;
+import org.springframework.boot.SpringApplication;
+import org.springframework.cache.annotation.EnableCaching;
+
+/**
+ * 进销存模块
+ */
+@EnableCaching
+@JeeplusCloudApplication
+public class JeeplusPsiManagementApplication {
+    public static void main(String[] args) {
+        SpringApplication.run ( JeeplusPsiManagementApplication.class, args );
+        System.out.println ( " O(∩_∩)O~ 进销存模块启动成功 ^_^゙  \n" +
+                "    _                         _                                       _                      \n" +
+                "   (_)                       | |                                     | |                     \n" +
+                "    _    ___    ___   _ __   | |  _   _   ___     ___   _   _   ___  | |_    ___   _ __ ___  \n" +
+                "   | |  / _ \\  / _ \\ | '_ \\  | | | | | | / __|   / __| | | | | / __| | __|  / _ \\ | '_ ` _ \\ \n" +
+                "   | | |  __/ |  __/ | |_) | | | | |_| | \\__ \\   \\__ \\ | |_| | \\__ \\ | |_  |  __/ | | | | | |\n" +
+                "   | |  \\___|  \\___| | .__/  |_|  \\__,_| |___/   |___/  \\__, | |___/  \\__|  \\___| |_| |_| |_|\n" +
+                "  _/ |               | |                                 __/ |                               \n" +
+                " |__/                |_|                                |___/                                " );
+    }
+}

+ 250 - 0
jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/collect/controller/PsiCollectController.java

@@ -0,0 +1,250 @@
+package com.jeeplus.psimanage.collect.controller;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.jeeplus.common.excel.EasyExcelUtils;
+import com.jeeplus.common.excel.ExcelOptions;
+import com.jeeplus.common.excel.annotation.ExportMode;
+import com.jeeplus.common.utils.ResponseUtil;
+import com.jeeplus.logging.annotation.ApiLog;
+import com.jeeplus.logging.constant.enums.LogTypeEnum;
+import com.jeeplus.psimanage.collect.domain.PsiCollectBasicsReturnHi;
+import com.jeeplus.psimanage.collect.mapper.PsiCollectDetailedRecordMapper;
+import com.jeeplus.psimanage.collect.service.PsiCollectService;
+import com.jeeplus.psimanage.collect.service.dto.PsiCollectDto;
+import com.jeeplus.psimanage.collect.service.dto.PsiCollectExportDto;
+import com.jeeplus.psimanage.collect.service.dto.PsiWareHouseSummaryDto;
+import com.jeeplus.utils.StringUtils;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletResponse;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+/**
+ * @author: 王强
+ * @create: 2023-01-03 16:18
+ **/
+@RestController
+@Api(tags ="物资管理-领用申请")
+@RequestMapping(value = "/psi/collect")
+public class PsiCollectController {
+
+    @Resource
+    private PsiCollectService psiCollectService;
+
+    @Resource
+    private PsiCollectDetailedRecordMapper psiCollectDetailedRecordMapper;
+
+
+
+    /**
+     * 根据id修改状态status
+     */
+    @ApiOperation(value = "根据id修改状态status")
+    @PostMapping(value = "updateStatusById")
+    public void updateStatusById(@RequestBody PsiCollectDto dto) {
+        psiCollectService.updateStatusById(dto);
+    }
+
+    /**
+     * 删除
+     * @param id
+     * @return
+     */
+    @ApiOperation(value = "删除")
+    @GetMapping("/remove")
+    public ResponseEntity<String> remove(@RequestParam String id){
+        String s = psiCollectService.remove(id);
+        return ResponseEntity.ok(s);
+    }
+
+    /**
+     * 新增/修改
+     * @param dto
+     * @return
+     */
+    @ApiOperation(value = "新增、修改")
+    @PostMapping("/save")
+    public ResponseEntity<String> save(@RequestBody PsiCollectDto dto) throws Exception{
+        String s = psiCollectService.save(dto);
+        return ResponseUtil.newInstance().add("businessTable", "psi_management_collect_basics").add("businessId", s).ok ("操作成功");
+    }
+
+    /**
+     * 查询
+     * @param id
+     * @return
+     */
+    @ApiOperation(value = "查询")
+    @GetMapping("/findById")
+    public ResponseEntity<PsiCollectDto> findById(@RequestParam String id) throws Exception{
+        PsiCollectDto dto = psiCollectService.findById(id);
+        return ResponseEntity.ok(dto);
+    }
+
+    /**
+     * 列表查询
+     * @param dto
+     * @return
+     */
+    @ApiOperation(value = "列表查询")
+    @GetMapping("/list")
+    public ResponseEntity<IPage<PsiCollectDto>> list(Page<PsiCollectDto> page, PsiCollectDto dto) throws Exception{
+        IPage<PsiCollectDto> iPage = psiCollectService.list(page, dto);
+        return ResponseEntity.ok(iPage);
+    }
+
+    @ApiLog(value = "导出领用数据", type = LogTypeEnum.EXPORT)
+    @ApiOperation(value = "导出领用数据")
+    @GetMapping("/exportFile")
+    public void exportFile(Page<PsiCollectDto> page, PsiCollectDto dto, ExcelOptions options, HttpServletResponse response) throws Exception{
+        String fileName = options.getFilename();
+        String sheetName = options.getSheetName();
+        List<PsiCollectExportDto> result;
+        if (ExportMode.current.equals(options.getMode())) {
+            result = psiCollectService.exportRecordList(page, dto);
+        } else if (ExportMode.selected.equals(options.getMode())) {
+            result = psiCollectService.exportRecordList(page, dto).stream().filter(item ->
+                    options.getSelectIds().contains(item.getId())
+            ).collect(Collectors.toList());
+        } else {
+            page.setSize(-1);
+            page.setCurrent(0);
+            result = psiCollectService.exportRecordList(page, dto);
+        }
+        EasyExcelUtils.newInstance().exportExcel(result, sheetName, PsiCollectExportDto.class, fileName, null, response);
+    }
+
+    /**
+     * 商品入库信息列表查询
+     * @param dto
+     * @return
+     */
+    @ApiOperation(value = "商品入库信息列表查询")
+    @GetMapping("/wareHouseList")
+    public ResponseEntity<IPage<PsiWareHouseSummaryDto>> wareHouseList(Page<PsiWareHouseSummaryDto> page, PsiWareHouseSummaryDto dto) throws Exception{
+        IPage<PsiWareHouseSummaryDto> iPage = psiCollectService.wareHouseList(page, dto);
+        return ResponseEntity.ok(iPage);
+    }
+
+    /**
+     * 创建领用退回流程表数据
+     * @param dto
+     * @return
+     */
+    @ApiOperation(value = "创建领用退回流程表数据")
+    @PostMapping("/createReturnData")
+    public ResponseEntity<Map<String,String>> createReturnData(@RequestBody PsiCollectDto dto) throws Exception{
+        String returnId = psiCollectService.createReturnData(dto.getId());
+        Map<String,String> res = new HashMap<String,String>();
+        res.put("returnId", returnId);
+        return ResponseEntity.ok(res);
+    }
+
+    /**
+     * 领用-退回  发起
+     * @param dto
+     * @return
+     */
+    @ApiOperation(value = "领用-退回  发起")
+    @PostMapping("/saveReturn")
+    public ResponseEntity saveReturn(@RequestBody PsiCollectDto dto) throws Exception{
+        String businessId = psiCollectService.saveReturn(dto);
+        if (StringUtils.isNotBlank(businessId)) {
+            return ResponseUtil.newInstance().add("businessTable", "psi_management_collect_basics_return").add("businessId", businessId).ok ("操作成功");
+        } else {
+            return ResponseEntity.badRequest().body("操作失败");
+        }
+    }
+
+    /**
+     * 领用-退回  同意
+     * @param dto
+     * @return
+     */
+    @ApiOperation(value = "领用-退回  同意")
+    @PostMapping("/saveReturnAgree")
+    public ResponseEntity saveReturnAgree(@RequestBody PsiCollectDto dto) throws Exception{
+        String s = psiCollectService.saveReturnAgree(dto);
+        return ResponseUtil.newInstance().add("businessTable", "psi_management_collect_basics_return").add("businessId", s).ok ("操作成功");
+    }
+
+    /**
+     * 领用-退回流程修改状态
+     * @param dto
+     * @return
+     */
+    @ApiOperation(value = "领用-退回流程修改状态")
+    @PostMapping("/updateStatusByIdReturn")
+    public ResponseEntity updateStatusByIdReturn(@RequestBody PsiCollectDto dto) throws Exception{
+        psiCollectService.updateStatusByIdReturn(dto.getId(), dto.getStatus());
+        return ResponseEntity.ok("修改完成");
+    }
+
+    /**
+     * 查询
+     * @param returnId
+     * @return
+     */
+    @ApiOperation(value = "查询")
+    @GetMapping("/findByReturnId")
+    public ResponseEntity<PsiCollectDto> findByReturnId(@RequestParam String returnId) throws Exception{
+        PsiCollectDto dto = psiCollectService.findByReturnId(returnId);
+        return ResponseEntity.ok(dto);
+    }
+
+    /**
+     * 取消领用退回
+     * @param dto
+     * @return
+     */
+    @ApiOperation(value = "取消领用退回")
+    @PostMapping("/returnRequest")
+    public ResponseEntity returnRequest(@RequestBody PsiCollectDto dto) throws Exception{
+        psiCollectService.returnRequest(dto.getId());
+        return ResponseEntity.ok("操作完成");
+    }
+
+    /**
+     * 根据领用表id查询其全部历史修改数据
+     * @return
+     */
+    @ApiOperation(value = "根据领用表id查询其全部历史修改数据")
+    @GetMapping("/findHiById")
+    public ResponseEntity findHiById(@RequestParam String collectId) {
+        List<PsiCollectBasicsReturnHi> hiById = psiCollectService.findHiById(collectId);
+        return ResponseEntity.ok(hiById);
+    }
+
+    /**
+     * 根据历史表id查询历史表数据
+     * @param id
+     * @return
+     */
+    @ApiOperation(value = "根据历史表id查询历史表数据")
+    @GetMapping("/findHiByHiId")
+    public ResponseEntity findHiByHiId(@RequestParam String id) {
+        PsiCollectDto hi = psiCollectService.findHiByHiId(id);
+        return ResponseEntity.ok(hi);
+    }
+
+    /**
+     * 根据领用表id查询最近的一个修改历史
+     * @param collectId
+     * @return
+     */
+    @ApiOperation(value = "根据领用表id查询最近的一个修改历史")
+    @GetMapping("/findLastHiByid")
+    public ResponseEntity findLastHiByid(@RequestParam String collectId) {
+        PsiCollectDto hi = psiCollectService.findLastHiByid(collectId);
+        return ResponseEntity.ok(hi);
+    }
+
+}

+ 63 - 0
jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/collect/domain/PsiCollectBasic.java

@@ -0,0 +1,63 @@
+package com.jeeplus.psimanage.collect.domain;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.jeeplus.core.domain.BaseEntity;
+import lombok.Data;
+
+import java.util.Date;
+import java.util.List;
+
+/**
+ * @author: 王强
+ * @create: 2023-01-03 16:29
+ **/
+@Data
+@TableName("psi_management_collect_basics")
+public class PsiCollectBasic extends BaseEntity {
+
+    //领用编号(字典值)
+    public static final String BIZ_CODE = "151";
+
+    /**
+     * 备注
+     */
+    private String remarks;
+
+    /**
+     * 流程id
+     */
+    private String procInsId;
+
+    /**
+     * 状态
+     */
+    private String status;
+
+    private String processDefinitionId;
+
+    /**
+     * 领用编号
+     */
+    private String collectNo;
+
+    /**
+     * 经办人
+     */
+    private String handledBy;
+
+    /**
+     * 经办人部门
+     */
+    private String handledByOffice;
+
+    /**
+     * 领用时间
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    private Date collectDate;
+
+    @TableField(exist = false)
+    List<PsiCollectDetailed> detailInfos;
+}

+ 46 - 0
jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/collect/domain/PsiCollectBasicsReturn.java

@@ -0,0 +1,46 @@
+package com.jeeplus.psimanage.collect.domain;
+
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.jeeplus.core.domain.BaseEntity;
+import lombok.Data;
+
+/**
+ * 物资管理-领用退回
+ * @TableName material_management_collect_basics_return
+ */
+@Data
+@TableName("psi_management_collect_basics_return")
+public class PsiCollectBasicsReturn extends BaseEntity {
+
+    /**
+     * 申请原因
+     */
+    private String remarks;
+
+    /**
+     * 流程id
+     */
+    private String procInsId;
+
+    /**
+     * 状态
+     */
+    private String status;
+
+    /**
+     *
+     */
+    private String processDefinitionId;
+
+    /**
+     * 领用id
+     */
+    private String basicId;
+
+    /**
+     * 退回申请人
+     */
+    private String requestUser;
+
+    private static final long serialVersionUID = 1L;
+}

+ 46 - 0
jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/collect/domain/PsiCollectBasicsReturnHi.java

@@ -0,0 +1,46 @@
+package com.jeeplus.psimanage.collect.domain;
+
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.jeeplus.core.domain.BaseEntity;
+import lombok.Data;
+
+/**
+ * 物资管理-领用退回-历史
+ * @TableName material_management_collect_basics_return_hi
+ */
+@Data
+@TableName("psi_management_collect_basics_return_hi")
+public class PsiCollectBasicsReturnHi extends BaseEntity {
+
+    /**
+     * 备注
+     */
+    private String remarks;
+
+    /**
+     * 领用id
+     */
+    private String collectId;
+
+    /**
+     * json数据
+     */
+    private String jsonData;
+
+    /**
+     * 退回申请人
+     */
+    private String returnUser;
+
+    /**
+     * 退回数据的物品名称
+     */
+    private String returnGoods;
+
+    /**
+     * 退回申请人名称
+     */
+    private String returnUserName;
+
+    private static final long serialVersionUID = 1L;
+}

+ 119 - 0
jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/collect/domain/PsiCollectDetailed.java

@@ -0,0 +1,119 @@
+package com.jeeplus.psimanage.collect.domain;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.jeeplus.core.domain.BaseEntity;
+import com.jeeplus.psimanage.oss.service.dto.WorkAttachmentDto;
+import lombok.Data;
+
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 领用明细表
+ * @author: 王强
+ * @create: 2023-01-04 14:53
+ **/
+@Data
+@TableName("psi_management_collect_detailed")
+public class PsiCollectDetailed extends BaseEntity {
+
+    /**
+     * 当前库存
+     */
+    private String currentInventory;
+
+    /**
+     * 领用基础表id
+     */
+    private String basicId;
+
+    /**
+     * 领用人
+     */
+    private String recipientAgent;
+
+    /**
+     * 领用人id
+     */
+    @TableField(exist = false)
+    private String recipientAgentId;
+
+    /**
+     * 领用人部门
+     */
+    @TableField(exist = false)
+    private String recipientOffice;
+
+    /**
+     * 领用类型
+     */
+    private String collectType;
+
+    /**
+     * 领用类型ID
+     */
+    @TableField(exist = false)
+    private String collectTypeId;
+
+    /**
+     * 物品名称
+     */
+    private String goodsName;
+
+    /**
+     * 剩余数量
+     */
+    private String surplusNumber;
+
+    /**
+     * 领用数量
+     */
+    private String collectNumber;
+
+    /**
+     * 单位
+     */
+    private String company;
+
+    /**
+     * 备注
+     */
+    private String remarks;
+
+    //附件信息
+    @TableField(exist = false)
+    List<WorkAttachmentDto> fileInfoLost;
+
+    /**
+     * 0未退回 1已退回
+     */
+    private String isReturn;
+
+    /**
+     * 包装规格
+     */
+    @TableField(exist = false)
+    private String spec;
+
+    /**
+     * 生产日期
+     */
+    @TableField(exist = false)
+    @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
+    private Date produceDate;
+
+    /**
+     * 保质期
+     */
+    @TableField(exist = false)
+    private String shelfLife;
+
+    /**
+     * 保质期单位
+     */
+    @TableField(exist = false)
+    private String shelfLifeUnit;
+
+}

+ 168 - 0
jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/collect/domain/PsiCollectDetailedRecord.java

@@ -0,0 +1,168 @@
+package com.jeeplus.psimanage.collect.domain;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.jeeplus.core.domain.BaseEntity;
+import com.jeeplus.psimanage.oss.service.dto.WorkAttachmentDto;
+import com.jeeplus.psimanage.psiWareHouse.service.dto.PsiWareHouseDto;
+import lombok.Data;
+
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 领用明细表
+ * @author: 王强
+ * @create: 2023-01-04 14:53
+ **/
+@Data
+@TableName("psi_management_collect_detailed_record")
+public class PsiCollectDetailedRecord extends BaseEntity {
+
+    /**
+     * 当前库存
+     */
+    private String currentInventory;
+
+    /**
+     * 领用基础表id
+     */
+    private String basicId;
+
+
+
+    /**
+     * 领用详情id
+     */
+    private String detailId;
+
+
+    /**
+     * 预扣除库存数据id
+     */
+    private String inventoryId;
+
+    /**
+     * 领用人
+     */
+    private String recipientAgent;
+
+    /**
+     * 领用人id
+     */
+    @TableField(exist = false)
+    private String recipientAgentId;
+
+    /**
+     * 领用人部门
+     */
+    @TableField(exist = false)
+    private String recipientOffice;
+
+    /**
+     * 领用类型
+     */
+    private String collectType;
+
+    /**
+     * 领用类型ID
+     */
+    @TableField(exist = false)
+    private String collectTypeId;
+
+    /**
+     * 物品名称
+     */
+    private String goodsName;
+
+    /**
+     * 剩余数量
+     */
+    private String surplusNumber;
+
+    /**
+     * 领用数量
+     */
+    private String collectNumber;
+
+    /**
+     * 单位
+     */
+    private String company;
+
+    /**
+     * 备注
+     */
+    private String remarks;
+
+    //附件信息
+    @TableField(exist = false)
+    List<WorkAttachmentDto> fileInfoLost;
+
+    /**
+     * 0未退回 1已退回
+     */
+    private String isReturn;
+
+    /**
+     * 包装规格
+     */
+    @TableField(exist = false)
+    private String spec;
+
+    /**
+     * 生产日期
+     */
+    @TableField(exist = false)
+    @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
+    private Date produceDate;
+
+    /**
+     * 保质期
+     */
+    @TableField(exist = false)
+    private String shelfLife;
+
+    /**
+     * 保质期单位
+     */
+    @TableField(exist = false)
+    private String shelfLifeUnit;
+
+    /**
+     * 此项领用的库存列表,不合并
+     */
+    @TableField(exist = false)
+    private List<PsiWareHouseDto> psiWareHouseDtoList ;
+
+    /**
+     *  退回数量
+     */
+    private String surplusStock;
+
+    /**
+     *  未退回数量
+     */
+    private String notSurplusStock;
+
+
+    /**
+     *  已退回数量
+     */
+    private String returnedNum;
+
+    /**
+     *  告警数量
+     */
+    @TableField(exist = false)
+    private String warnNum;
+
+
+    /**
+     *  告警标记
+     */
+    @TableField(exist = false)
+    private String warnFlag;
+
+}

+ 41 - 0
jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/collect/mapper/PsiCollectBasicMapper.java

@@ -0,0 +1,41 @@
+package com.jeeplus.psimanage.collect.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.core.toolkit.Constants;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.jeeplus.psimanage.collect.domain.PsiCollectBasic;
+import com.jeeplus.psimanage.collect.domain.PsiCollectBasicsReturn;
+import com.jeeplus.psimanage.collect.service.dto.PsiCollectDto;
+import com.jeeplus.psimanage.collect.service.dto.PsiWareHouseSummaryDto;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+/**
+ * @author: 王强
+ * @create: 2023-01-03 16:29
+ **/
+public interface PsiCollectBasicMapper extends BaseMapper<PsiCollectBasic> {
+
+    void updateStatusById(@Param("id") String id, @Param("type") String type);
+
+    List<String> findChildIds(String department);
+
+    IPage<PsiCollectDto> findList(Page<PsiCollectDto> page, @Param(Constants.WRAPPER) QueryWrapper<PsiCollectDto> queryWrapper);
+
+    IPage<PsiWareHouseSummaryDto> findWareHouseList(Page<PsiWareHouseSummaryDto> page, @Param(Constants.WRAPPER) QueryWrapper<PsiWareHouseSummaryDto> queryWrapper);
+
+    String getUserNameByUserId(String handledBy);
+
+    PsiCollectBasicsReturn selectReturnByBasicId(String id);
+
+    /**
+     * 清除退回原因
+     * @param id
+     */
+    void setCauseEmptyById(String id);
+
+    String getOfficeNameByOfficeId(String handledByOffice);
+}

+ 29 - 0
jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/collect/mapper/PsiCollectBasicsReturnHiMapper.java

@@ -0,0 +1,29 @@
+package com.jeeplus.psimanage.collect.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.jeeplus.psimanage.collect.domain.PsiCollectBasicsReturnHi;
+import java.util.List;
+
+public interface PsiCollectBasicsReturnHiMapper extends BaseMapper<PsiCollectBasicsReturnHi> {
+
+    /**
+     * 根据领用id查询全部退回记录
+     * @param collectId
+     * @return
+     */
+    List<PsiCollectBasicsReturnHi> findHiById(String collectId);
+
+    /**
+     * 根据历史数据id查询
+     * @param id
+     * @return
+     */
+    PsiCollectBasicsReturnHi findHiByHiId(String id);
+
+    /**
+     * 根据领用id查询最近的一条退回记录
+     * @param collectId
+     * @return
+     */
+    PsiCollectBasicsReturnHi findLastHiByid(String collectId);
+}

+ 9 - 0
jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/collect/mapper/PsiCollectBasicsReturnMapper.java

@@ -0,0 +1,9 @@
+package com.jeeplus.psimanage.collect.mapper;
+
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.jeeplus.psimanage.collect.domain.PsiCollectBasicsReturn;
+
+public interface PsiCollectBasicsReturnMapper extends BaseMapper<PsiCollectBasicsReturn> {
+
+}

+ 66 - 0
jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/collect/mapper/PsiCollectDetailedMapper.java

@@ -0,0 +1,66 @@
+package com.jeeplus.psimanage.collect.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.jeeplus.psimanage.collect.domain.PsiCollectDetailed;
+import com.jeeplus.psimanage.collect.domain.PsiCollectDetailedRecord;
+import com.jeeplus.psimanage.oss.service.dto.WorkAttachmentDto;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+/**
+ * @author: 王强
+ * @create: 2023-01-04 15:32
+ **/
+public interface PsiCollectDetailedMapper extends BaseMapper<PsiCollectDetailed> {
+    //根据基础表id查出详情数据
+    List<PsiCollectDetailed> getByBasicId(String id);
+
+    //根据基础表id查出详情数据
+    List<PsiCollectDetailedRecord> getRecordsByBasicId( @Param("id")String id, @Param("isReturn") String isReturn);
+
+    //查出附件信息
+    List<WorkAttachmentDto> getByAttachmentId(String id);
+
+    List<String> getIdByBasicId(String id);
+
+    /**
+     * 根据领用详情id修改 退回标记(is_return)
+     * @param id 领用详情id
+     * @param isReturn 退回标记 0未退回 1已退回
+     */
+    void updateReturnFlagById(@Param("id")String id, @Param("isReturn")String isReturn);
+
+    /**
+     * 根据领用详情id修改审核表的退回标记(is_return)
+     */
+    void updateAuditReturnFlagById(PsiCollectDetailedRecord psiCollectDetailedRecord);
+
+    /**
+     * 根据退回表id修改 退回状态
+     * @param id 退回表id
+     * @param status 退回状态
+     */
+    void updateStatusByIdReturn(@Param("id")String id, @Param("status")String status);
+
+    /**
+     * 根据退回表id修改 退回状态和 退回申请人
+     * @param id 退回表id
+     * @param status 退回状态
+     * @param userId 退回申请人id
+     * @param cause 退回原因
+     */
+    void updateByIdReturn(@Param("id")String id, @Param("status")String status, @Param("userId")String userId, @Param("cause")String cause);
+
+    /**
+     * 将此领用id下全部del_flag=0的领用详情修改为->未退回
+     * @param id 领用id
+     */
+    void updateNoReturnByBasicId(String id);
+
+    /**
+     * 领用审核记录表的退回撤销
+     * @param id 领用id
+     */
+    void updateAutditNoReturnByBasicId(String id);
+}

+ 16 - 0
jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/collect/mapper/PsiCollectDetailedRecordMapper.java

@@ -0,0 +1,16 @@
+package com.jeeplus.psimanage.collect.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.jeeplus.psimanage.collect.domain.PsiCollectDetailed;
+import com.jeeplus.psimanage.collect.domain.PsiCollectDetailedRecord;
+import com.jeeplus.psimanage.oss.service.dto.WorkAttachmentDto;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+/**
+ * @author: 王强
+ * @create: 2023-01-04 15:32
+ **/
+public interface PsiCollectDetailedRecordMapper extends BaseMapper<PsiCollectDetailedRecord> {
+}

+ 72 - 0
jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/collect/mapper/xml/PsiCollectBasicMapper.xml

@@ -0,0 +1,72 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.jeeplus.psimanage.collect.mapper.PsiCollectBasicMapper">
+    <update id="updateStatusById">
+		UPDATE psi_management_collect_basics SET status = #{type}
+		WHERE id = #{id}
+	</update>
+    <select id="findWareHouseList"
+            resultType="com.jeeplus.psimanage.collect.service.dto.PsiWareHouseSummaryDto">
+        SELECT
+			a.id,
+			a.create_by_id as createBy,
+			a.create_time,
+			a.trade_name,
+			a.trade_number
+		FROM
+			psi_management_warehouse_basics a
+			${ew.customSqlSegment}
+		ORDER BY a.update_time DESC
+    </select>
+    <select id="findChildIds" resultType="java.lang.String">
+		select id from sys_office where parent_id = #{department}
+	</select>
+	<select id="findList" resultType="com.jeeplus.psimanage.collect.service.dto.PsiCollectDto">
+		SELECT
+        	DISTINCT
+			a.id,
+			a.create_by_id as createBy,
+			a.create_time,
+			a.status,
+			a.proc_ins_id,
+			a.process_definition_id,
+			a.collect_no,
+			a.handled_by,
+			a.handled_by_office,
+			a.collect_date,
+			b.goods_name,
+			b.id as detail_id,
+			so.name as handledByOfficeName,
+			su.name as handledByName,
+			art.ID_ as task_id,
+			returna.status as status_return,
+			returna.proc_ins_id as proc_ins_id_return,
+			returna.process_definition_id as process_definition_id_return,
+			returna.id as return_id,
+			art_r.ID_ as task_id_return
+		FROM
+			psi_management_collect_basics a
+			left join sys_user su on a.handled_by = su.id
+			left join sys_office so on a.handled_by_office = so.id
+			left join psi_management_collect_detailed b on a.id = b.basic_id and b.del_flag = '0'
+			left join act_ru_task art ON a.proc_ins_id = art.PROC_INST_ID_
+			left join psi_management_collect_basics_return returna on returna.basic_id = a.id and returna.del_flag = '0'
+			left join act_ru_task art_r ON returna.proc_ins_id = art_r.PROC_INST_ID_
+			${ew.customSqlSegment}
+		ORDER BY a.update_time DESC
+	</select>
+	<select id="getUserNameByUserId" resultType="java.lang.String">
+		select name from sys_user where id = #{id}
+	</select>
+	<select id="selectReturnByBasicId" resultType="com.jeeplus.psimanage.collect.domain.PsiCollectBasicsReturn">
+		select *
+		from psi_management_collect_basics_return
+		where basic_id = #{id}
+	</select>
+	<select id="getOfficeNameByOfficeId" resultType="java.lang.String">
+		select name from sys_office where id = #{handledByOffice}
+	</select>
+	<update id="setCauseEmptyById">
+		update psi_management_collect_basics_return set remarks = null where id = #{id}
+	</update>
+</mapper>

+ 44 - 0
jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/collect/mapper/xml/PsiCollectBasicsReturnHiMapper.xml

@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.jeeplus.psimanage.collect.mapper.PsiCollectBasicsReturnHiMapper">
+
+    <sql id="HI_Column_List">
+        hi.id,
+        hi.create_by_id,
+        hi.create_time,
+        hi.update_by_id,
+        hi.update_time,
+        hi.del_flag,
+        hi.remarks,
+        hi.collect_id,
+        hi.json_data,
+        hi.return_user,
+        hi.return_goods
+    </sql>
+
+    <select id="findHiById" resultType="com.jeeplus.psimanage.collect.domain.PsiCollectBasicsReturnHi">
+        select
+        <include refid="HI_Column_List"></include>,
+        su.name as returnUserName
+        from psi_management_collect_basics_return_hi hi
+        left join sys_user su on su.id = hi.return_user
+        where hi.del_flag = '0' and hi.collect_id = #{collectId}
+        order by hi.create_time desc
+    </select>
+
+    <select id="findHiByHiId" resultType="com.jeeplus.psimanage.collect.domain.PsiCollectBasicsReturnHi">
+        select
+        <include refid="HI_Column_List"></include>
+        from psi_management_collect_basics_return_hi hi
+        where hi.del_flag = '0' and hi.id = #{id}
+    </select>
+
+    <select id="findLastHiByid" resultType="com.jeeplus.psimanage.collect.domain.PsiCollectBasicsReturnHi">
+        select
+        <include refid="HI_Column_List"></include>
+        from psi_management_collect_basics_return_hi hi
+        where hi.del_flag = '0' and hi.collect_id = #{collectId}
+        order by hi.create_time desc
+        limit 1
+    </select>
+</mapper>

+ 139 - 0
jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/collect/mapper/xml/PsiCollectDetailedMapper.xml

@@ -0,0 +1,139 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.jeeplus.psimanage.collect.mapper.PsiCollectDetailedMapper">
+    <select id="getByBasicId" resultType="com.jeeplus.psimanage.collect.domain.PsiCollectDetailed">
+        SELECT a.id,
+               a.create_by_id,
+               a.create_time,
+               a.update_by_id,
+               a.update_time,
+               a.del_flag,
+               a.remarks,
+               a.basic_id,
+               a.recipient_agent,
+        a.collect_type,
+        a.goods_name,
+        a.collect_number,
+        a.company,
+        a.current_inventory,
+               c.spec,
+        su.name AS recipientAgent, su.id AS recipientAgentId, so.name AS recipientOffice,
+        d.id AS collectTypeId, d.name AS collectType,
+               IFNULL(
+                       SUM(trade_number) - (b.collect_number / c.spec),
+                       SUM(trade_number)
+               ) AS surplusNumber,
+                a.is_return
+             FROM psi_management_collect_detailed a
+             LEFT JOIN sys_user su
+             ON a.recipient_agent = su.id
+             LEFT JOIN sys_office so
+             ON su.office_id = so.id
+
+             LEFT JOIN (
+                SELECT
+                    sum( collect_number ) AS collect_number,
+                    goods_name,
+                STATUS
+                FROM
+                    psi_management_collect_detailed e
+                    LEFT JOIN psi_management_collect_basics f ON e.basic_id = f.id
+                    AND f.del_flag = 0
+                WHERE
+                    f.`status` = 5
+                    AND e.del_flag = 0
+                GROUP BY
+                    e.goods_name
+                ) b ON a.goods_name = b.goods_name
+
+             LEFT JOIN psi_management_warehouse_detailed c on a.goods_name = c.trade_name and a.collect_type = c.ware_house_type
+             LEFT JOIN psi_management_warehouse_basics bas ON c.basic_id = bas.id
+
+             LEFT JOIN psi_management_type d ON a.collect_type = d.id
+             WHERE a.basic_id = #{id} AND a.del_flag = '0' and c.del_flag = '0' AND ( bas.`status` = '0' OR bas.`status` = '5')
+             group by a.goods_name;
+    </select>
+    <select id="getRecordsByBasicId" resultType="com.jeeplus.psimanage.collect.domain.PsiCollectDetailedRecord">
+        select
+            a.id,
+            su.name AS recipientAgent,
+            su.id AS recipientAgentId,
+            so.name AS recipientOffice,
+            d.id AS collectTypeId,
+            d.name AS collectType,
+            a.goods_name,
+            pmwd.current_inventory as surplusNumber,
+            a.collect_number,
+            a.company,
+            a.current_inventory,
+            pmwd.produce_date,
+            pmwd.spec,
+            a.detail_id,
+            a.inventory_id,
+            pmcd.is_return,
+            a.surplus_stock,
+            a.not_surplus_stock,
+            a.returned_num,
+            pmwd.warn_num,
+            pmwd.warn_flag
+        from psi_management_collect_detailed_record a
+            LEFT JOIN sys_user su  ON a.recipient_agent = su.id
+            LEFT JOIN sys_office so ON su.office_id = so.id
+            LEFT JOIN psi_management_type d ON a.collect_type = d.id
+            LEFT JOIN psi_management_collect_detailed pmcd ON a.detail_id = pmcd.id
+            LEFT JOIN psi_management_warehouse_detailed pmwd ON a.inventory_id = pmwd.id
+
+        where a.del_flag = '0' and
+        a.basic_id = #{id}
+    </select>
+
+    <select id="getByAttachmentId" resultType="com.jeeplus.psimanage.oss.service.dto.WorkAttachmentDto">
+        SELECT
+			id,
+			url,
+			attachment_name AS `name`,
+			create_by_id AS `by`,
+			create_time
+		FROM
+			work_attachment
+		WHERE
+			del_flag = 0
+			AND attachment_id = #{id}
+    </select>
+    <select id="getIdByBasicId" resultType="java.lang.String">
+        select a.id from psi_management_collect_detailed a where a.basic_id = #{id} and a.del_flag = 0
+    </select>
+
+    <update id="updateReturnFlagById">
+        update psi_management_collect_detailed set is_return = #{isReturn} where id = #{id}
+    </update>
+
+    <update id="updateAuditReturnFlagById">
+        update psi_management_collect_detailed_record
+        set is_return = #{isReturn},
+            surplus_stock = #{surplusStock},
+            not_surplus_stock = #{notSurplusStock},
+            returned_num = #{returnedNum}
+        where id = #{id}
+    </update>
+
+    <update id="updateStatusByIdReturn">
+        update psi_management_collect_basics_return set status = #{status} where id = #{id}
+    </update>
+
+    <update id="updateByIdReturn">
+        update psi_management_collect_basics_return set status = #{status},request_user = #{userId},remarks = #{cause} where id = #{id}
+    </update>
+
+    <update id="updateNoReturnByBasicId">
+        update psi_management_collect_detailed set is_return = '0' where basic_id = #{id}
+    </update>
+
+
+    <update id="updateAutditNoReturnByBasicId">
+        update psi_management_collect_detailed_record
+        set is_return = '0',
+            returned_num = '0'
+        where basic_id = #{id}
+    </update>
+</mapper>

Plik diff jest za duży
+ 1056 - 0
jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/collect/service/PsiCollectService.java


+ 167 - 0
jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/collect/service/dto/PsiCollectDto.java

@@ -0,0 +1,167 @@
+package com.jeeplus.psimanage.collect.service.dto;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.jeeplus.psimanage.collect.domain.PsiCollectDetailed;
+import com.jeeplus.psimanage.collect.domain.PsiCollectDetailedRecord;
+import com.jeeplus.psimanage.oss.domain.PsiWorkAttachment;
+import com.jeeplus.psimanage.oss.service.dto.WorkAttachmentDto;
+import lombok.Data;
+
+import java.util.Date;
+import java.util.List;
+
+/**
+ * @author: 王强
+ * @create: 2023-01-04 14:58
+ **/
+@Data
+public class PsiCollectDto {
+
+    /**
+     * 管理员修改标记
+     */
+    private String sign;
+
+    /**
+     * 备注
+     */
+    private String remarks;
+
+    private String createBy;
+
+    //领用编号(字典值)
+    public static final String BIZ_CODE = "151";
+
+    /**
+     * 基础表主键值
+     */
+    private String id;
+
+    /**
+     * 领用物品名称
+     */
+    private String goodsName;
+
+    /**
+     * 流程id
+     */
+    private String procInsId;
+
+    /**
+     * 状态
+     */
+    private String status;
+
+    private String processDefinitionId;
+
+    /**
+     * 领用编号
+     */
+    private String collectNo;
+
+    /**
+     * 领用时间
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    private Date collectDate;
+
+    /**
+     * 领用时间
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    private String[] collectDates;
+
+    /**
+     * 经办人
+     */
+    private String handledBy;
+
+    /**
+     * 经办人id
+     */
+    private String handledById;
+
+    /**
+     * 经办人名称
+     */
+    private String handledByName;
+
+    /**
+     * 经办人部门
+     */
+    private String handledByOffice;
+
+    /**
+     *经办人部门名称
+     */
+    private String handledByOfficeName;
+
+    /**
+     * 领用  附件
+     */
+    private List<WorkAttachmentDto> files;
+
+    /**
+     * 领用-退回  附件
+     */
+    private List<WorkAttachmentDto> returnFiles;
+
+    //附件信息
+    List<PsiWorkAttachment> fileInfoLost;
+
+    //新增信息
+    List<PsiCollectDetailed> detailInfos;
+
+    /**
+     * 领用申请  taskId
+     */
+    private String taskId;
+
+    /**
+     * 数据审核人  领用申请
+     */
+    private List<String> auditUserIds;
+
+    /**
+     * 领用-退回流程状态
+     */
+    private String statusReturn;
+
+    /**
+     * 流程id
+     */
+    private String procInsIdReturn;
+
+    private String processDefinitionIdReturn;
+
+    /**
+     * 退回id
+     */
+    private String returnId;
+
+    /**
+     * 退回申请原因
+     */
+    private String returnCause;
+
+    /**
+     * 领用-退回申请  taskId
+     */
+    private String taskIdReturn;
+
+    /**
+     * 数据审核人  领用-退回申请
+     */
+    private List<String> auditUserIdsReturn;
+
+    /**
+     * 领用详情id
+     */
+    private String detailId;
+
+    /**
+     * 数据审核人  领用-退回申请
+     */
+    private List<PsiCollectDetailedRecord> recordList;
+
+}

+ 52 - 0
jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/collect/service/dto/PsiCollectExportDto.java

@@ -0,0 +1,52 @@
+package com.jeeplus.psimanage.collect.service.dto;
+
+import com.alibaba.excel.annotation.ExcelIgnore;
+import com.alibaba.excel.annotation.ExcelProperty;
+import lombok.Data;
+
+@Data
+public class PsiCollectExportDto {
+
+    @ExcelIgnore
+    private String id;
+
+    @ExcelIgnore
+    private String handledByName;
+
+    @ExcelIgnore
+    private String handledByOfficeName;
+
+    @ExcelIgnore
+    private String status;
+
+    @ExcelIgnore
+    private String statusReturn;
+
+    @ExcelProperty("领用编号")
+    private String collectNo;
+
+    @ExcelProperty("领用人")
+    private String recipientAgent;
+
+    @ExcelProperty("领用人部门")
+    private String recipientOffice;
+
+    @ExcelProperty("领用类型")
+    private String collectType;
+
+    @ExcelProperty("物品名称")
+    private String goodsName;
+
+    @ExcelProperty("分配生产日期")
+    private String produceDate;
+
+    @ExcelProperty("领用数量")
+    private String collectNumber;
+
+    //@ExcelProperty("库存数量")
+    @ExcelIgnore
+    private String surplusNumber;
+
+    @ExcelProperty("领用时间")
+    private String collectDate;
+}

+ 28 - 0
jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/collect/service/dto/PsiWareHouseSummaryDto.java

@@ -0,0 +1,28 @@
+package com.jeeplus.psimanage.collect.service.dto;
+
+import lombok.Data;
+
+/**
+ * 入库汇总表
+ * @author: 王强
+ * @create: 2023-01-03 16:22
+ **/
+@Data
+public class PsiWareHouseSummaryDto {
+
+    /**
+     * 商品名称
+     */
+    private String tradeName;
+
+    /**
+     * 商品数量
+     */
+    private String tradeNumber;
+
+    /**
+     * 入库类型
+     */
+    private String wareHouseType;
+
+}

+ 83 - 0
jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/contract/controller/PsiContractController.java

@@ -0,0 +1,83 @@
+package com.jeeplus.psimanage.contract.controller;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.jeeplus.common.utils.ResponseUtil;
+import com.jeeplus.psimanage.contract.service.PsiContractService;
+import com.jeeplus.psimanage.contract.service.dto.PsiContractInfoDto;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+
+/**
+ * @author: 王强
+ * @create: 2023-01-13 13:55
+ **/
+@RestController
+@Api(tags ="物资管理-合同")
+@RequestMapping(value = "/psi/contract")
+public class PsiContractController {
+
+    @Resource
+    private PsiContractService psiContractService;
+
+    /**
+     * 新增/修改
+     * @param dto
+     * @return
+     */
+    @ApiOperation(value = "新增、修改")
+    @PostMapping("/save")
+    public ResponseEntity<String> save(@RequestBody PsiContractInfoDto dto) throws Exception{
+        String s = psiContractService.save(dto);
+        return ResponseUtil.newInstance().add("businessTable", "psi_management_contract").add("businessId", s).ok ("操作成功");
+    }
+
+    /**
+     * 列表查询
+     * @param dto
+     * @return
+     */
+    @ApiOperation(value = "列表查询")
+    @GetMapping("/list")
+    public ResponseEntity<IPage<PsiContractInfoDto>> list(Page<PsiContractInfoDto> page, PsiContractInfoDto dto) throws Exception{
+        IPage<PsiContractInfoDto> iPage = psiContractService.list(page, dto);
+        return ResponseEntity.ok(iPage);
+    }
+
+    /**
+     * 查询
+     * @param id
+     * @return
+     */
+    @ApiOperation(value = "查询")
+    @GetMapping("/findById")
+    public ResponseEntity<PsiContractInfoDto> findById(@RequestParam String id) throws Exception{
+        PsiContractInfoDto dto = psiContractService.findById(id);
+        return ResponseEntity.ok(dto);
+    }
+
+    /**
+     * 根据id修改状态status
+     */
+    @ApiOperation(value = "根据id修改状态status")
+    @PostMapping(value = "updateStatusById")
+    public void updateStatusById(@RequestBody PsiContractInfoDto dto) {
+        psiContractService.updateStatusById(dto);
+    }
+
+    /**
+     * 删除
+     * @param id
+     * @return
+     */
+    @ApiOperation(value = "删除")
+    @GetMapping("/remove")
+    public ResponseEntity<String> remove(@RequestParam String id){
+        String s = psiContractService.remove(id);
+        return ResponseEntity.ok(s);
+    }
+}

+ 72 - 0
jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/contract/domain/PsiContract.java

@@ -0,0 +1,72 @@
+package com.jeeplus.psimanage.contract.domain;
+
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.jeeplus.core.domain.BaseEntity;
+import lombok.Data;
+
+import java.util.Date;
+
+/**
+ * 物资管理-合同表
+ * @author: 王强
+ * @create: 2023-01-13 13:56
+ **/
+@Data
+@TableName("psi_management_contract")
+public class PsiContract extends BaseEntity {
+
+    //入库编号(字典值)
+    public static final String BIZ_CODE = "153";
+
+    //备注1
+    private String remarks1;
+    //备注2
+    private String remarks2;
+
+    private String procInsId;
+
+    /**
+     * 状态
+     */
+    private String status;
+
+    private String processDefinitionId;
+
+    //客户名称
+    private String name;
+
+    //是否有统一社会信用代码
+    private String isUscCode;
+
+    //统一社会信用代码
+    private String uscCode;
+
+    //注册地址
+    private String companyAddress;
+
+    //详细地址
+    private String address;
+
+    //公司电话
+    private String mobile;
+
+    //合同名称
+    private String contractName;
+
+    //合同编号
+    private String contractNo;
+
+    //签订日期
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    private Date signingDate;
+
+    //合同生效日期
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    private Date effectiveDate;
+
+    //合同终止日期
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    private Date endTime;
+
+}

+ 33 - 0
jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/contract/domain/PsiContractUser.java

@@ -0,0 +1,33 @@
+package com.jeeplus.psimanage.contract.domain;
+
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.jeeplus.core.domain.BaseEntity;
+import lombok.Data;
+
+/**
+ * 物资管理-合同-客户联系人表
+ * @author: 王强
+ * @create: 2023-01-13 13:57
+ **/
+@Data
+@TableName("psi_management_contract_user")
+public class PsiContractUser extends BaseEntity {
+
+    //备注
+    private String remarks;
+
+    //姓名
+    private String name;
+
+    //职位
+    private String position;
+
+    //联系方式1
+    private String contactFirst;
+
+    //联系方式2
+    private String contactSecond;
+
+    //物资管理-合同表id
+    private String contractId;
+}

+ 21 - 0
jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/contract/mapper/PsiContractMapper.java

@@ -0,0 +1,21 @@
+package com.jeeplus.psimanage.contract.mapper;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.core.toolkit.Constants;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.jeeplus.psimanage.contract.domain.PsiContract;
+import com.jeeplus.psimanage.contract.service.dto.PsiContractInfoDto;
+import org.apache.ibatis.annotations.Param;
+
+/**
+ * @author: 王强
+ * @create: 2023-01-13 14:29
+ **/
+public interface PsiContractMapper extends BaseMapper<PsiContract> {
+
+    void updateStatusById(@Param("id") String id, @Param("type") String type);
+
+    IPage<PsiContractInfoDto> findList(Page<PsiContractInfoDto> page, @Param(Constants.WRAPPER) QueryWrapper<PsiContractInfoDto> queryWrapper);
+}

+ 17 - 0
jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/contract/mapper/PsiContractUserMapper.java

@@ -0,0 +1,17 @@
+package com.jeeplus.psimanage.contract.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.jeeplus.psimanage.contract.domain.PsiContractUser;
+
+import java.util.List;
+
+/**
+ * @author: 王强
+ * @create: 2023-01-13 14:31
+ **/
+public interface PsiContractUserMapper extends BaseMapper<PsiContractUser> {
+    //根据合同id查出所有的用户id
+    List<String> getByContractId(String id);
+
+    List<PsiContractUser> getByContId(String id);
+}

+ 33 - 0
jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/contract/mapper/xml/PsiContractMapper.xml

@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.jeeplus.psimanage.contract.mapper.PsiContractMapper">
+	<update id="updateStatusById">
+		UPDATE material_management_contract SET status = #{type}
+		WHERE id = #{id}
+	</update>
+	<select id="findList"
+            resultType="com.jeeplus.psimanage.contract.service.dto.PsiContractInfoDto">
+        SELECT
+        	DISTINCT
+			a.id,
+			a.create_by,
+			a.create_date,
+			a.proc_ins_id,
+			a.status,
+			a.process_definition_id,
+			a.usc_code,
+			a.address,
+			a.company_address,
+			a.mobile,
+			a.contract_name,
+			a.signing_date,
+			a.effective_date,
+			a.end_time,
+			a.name,
+			a.contract_no
+		FROM
+			psi_management_contract a
+			${ew.customSqlSegment}
+		ORDER BY a.update_date DESC
+    </select>
+</mapper>

+ 10 - 0
jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/contract/mapper/xml/PsiContractUserMapper.xml

@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.jeeplus.psimanage.contract.mapper.PsiContractUserMapper">
+    <select id="getByContractId" resultType="java.lang.String">
+        select id from material_management_contract_user where contract_id = #{id} and del_flag = 0
+    </select>
+    <select id="getByContId" resultType="com.jeeplus.psimanage.contract.domain.PsiContractUser">
+        SELECT * FROM psi_management_contract_user where contract_id = #{id} and del_flag = 0 order by create_date desc
+    </select>
+</mapper>

+ 239 - 0
jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/contract/service/PsiContractService.java

@@ -0,0 +1,239 @@
+package com.jeeplus.psimanage.contract.service;
+
+import cn.hutool.extra.spring.SpringUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.jeeplus.common.TokenProvider;
+import com.jeeplus.core.query.QueryWrapperGenerator;
+import com.jeeplus.psimanage.contract.domain.PsiContract;
+import com.jeeplus.psimanage.contract.domain.PsiContractUser;
+import com.jeeplus.psimanage.contract.mapper.PsiContractMapper;
+import com.jeeplus.psimanage.contract.mapper.PsiContractUserMapper;
+import com.jeeplus.psimanage.contract.service.dto.PsiContractInfoDto;
+import com.jeeplus.psimanage.purchase.mapper.PsiMaterialDetailedMapper;
+import com.jeeplus.psimanage.oss.domain.PsiWorkAttachment;
+import com.jeeplus.psimanage.oss.mapper.PsiOssServiceMapper;
+import com.jeeplus.psimanage.oss.service.PsiOssService;
+import com.jeeplus.psimanage.oss.service.dto.WorkAttachmentDto;
+import com.jeeplus.psimanage.serialNumTpl.service.PsiSerialnumTplService;
+import com.jeeplus.sys.feign.IUserApi;
+import com.jeeplus.sys.service.dto.UserDTO;
+//import com.jeeplus.sys.utils.UserUtils;
+import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
+import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
+import com.jeeplus.utils.StringUtils;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+
+import org.springframework.beans.BeanUtils;
+
+import javax.annotation.Resource;
+import java.util.Date;
+import java.util.List;
+import java.util.UUID;
+
+/**
+ * @author: 王强
+ * @create: 2023-01-13 14:11
+ **/
+@Service
+@Transactional
+public class PsiContractService {
+
+    @Resource
+    private PsiContractMapper psiContractMapper;
+
+    @Resource
+    private PsiContractUserMapper psiContractUserMapper;
+
+    @Resource
+    private PsiMaterialDetailedMapper psiDetailedMapper;
+
+    @Resource
+    private PsiOssServiceMapper psiOssServiceMapper;
+
+    @Resource
+    private PsiOssService psiOssService;
+
+    @Resource
+    private PsiSerialnumTplService psiSerialnumTplService;
+
+//    @Resource
+//    private ContractInfoService infoService;
+
+    public String remove(String id) {
+        // 删除基础信息表
+        psiContractMapper.deleteById(id);
+        // 删除详情列表 及对应附件信息
+        List<PsiContractUser> detailedList = psiContractUserMapper.getByContId(id);
+        if (null != detailedList){
+            detailedList.forEach(de->{
+                psiDetailedMapper.deleteById(de.getId());
+            });
+        }
+        // 删除附件信息
+        LambdaQueryWrapper<PsiWorkAttachment> wrapper = new LambdaQueryWrapper<>();
+        wrapper.eq(PsiWorkAttachment::getAttachmentId, id);
+        psiOssServiceMapper.delete(wrapper);
+        return "操作成功";
+    }
+
+    public void updateStatusById(PsiContractInfoDto dto) {
+        psiContractMapper.updateStatusById(dto.getId(), dto.getStatus());
+    }
+
+    public PsiContractInfoDto findById(String id) {
+        PsiContractInfoDto dto = new PsiContractInfoDto();
+        // 查询基础信息表
+        PsiContract info = psiContractMapper.selectById(id);
+        if (ObjectUtils.isNotEmpty(info)) {
+            BeanUtils.copyProperties(info, dto);
+            //将采购详情数据查出
+            List<PsiContractUser> detailedList = psiContractUserMapper.getByContId(id);
+            dto.setCwProjectClientContactDTOList(detailedList);
+            //附件信息
+            List<WorkAttachmentDto> files = psiDetailedMapper.getByAttachmentId(info.getId());
+            if (CollectionUtils.isNotEmpty(files)) {
+                for (WorkAttachmentDto i : files) {
+                    i.setCreateBy(SpringUtil.getBean ( IUserApi.class ).getById(i.getBy()));
+//                    i.setCreateBy(UserUtils.get(i.getBy()));
+                }
+            }
+            dto.setFiles(files);
+        }
+        return dto;
+    }
+
+    /**
+     * 列表查询
+     */
+    public IPage<PsiContractInfoDto> list(Page<PsiContractInfoDto> page , PsiContractInfoDto dto) throws Exception{
+        QueryWrapper<PsiContractInfoDto> queryWrapper = QueryWrapperGenerator.buildQueryCondition(dto, PsiContractInfoDto.class);
+
+        queryWrapper.eq("a.del_flag", "0");
+
+        if (StringUtils.isNotEmpty(dto.getName())) {
+            queryWrapper.like("a.name", dto.getName());
+        }
+        if (StringUtils.isNotEmpty(dto.getContractName())) {
+            queryWrapper.like("a.contract_name", dto.getContractName());
+        }
+        if (StringUtils.isNotEmpty(dto.getStatus())) {
+            queryWrapper.like("a.status", dto.getStatus());
+        }
+        String[] effectiveDates = dto.getEffectiveDates();
+        if (effectiveDates != null) {
+
+            queryWrapper.between("a.effective_date", effectiveDates[0], effectiveDates[1]);
+        }
+
+        return psiContractMapper.findList(page, queryWrapper);
+    }
+
+    public String save(PsiContractInfoDto dto) throws Exception{
+        // 获取当前登录人信息
+        UserDTO userDTO = SpringUtil.getBean ( IUserApi.class ).getByToken(TokenProvider.getCurrentToken ( ));
+//        UserDTO userDTO = UserUtils.getCurrentUserDTO();
+        if (StringUtils.isNotEmpty(dto.getId()) && !dto.getId().equals("false")) {
+            return update(dto, userDTO);
+        } else {
+            return add(dto, userDTO);
+        }
+    }
+
+    public String update(PsiContractInfoDto dto, UserDTO userDTO) {
+        // 修改基础信息
+        PsiContract info = new PsiContract();
+        BeanUtils.copyProperties(dto, info);
+        info.setUpdateById(userDTO.getId());
+        info.setUpdateTime(new Date());
+        psiContractMapper.updateById(info);
+        //当一开始保存的联系人数据在修改的时候被删除时
+        List<String> idList = psiContractUserMapper.getByContractId(info.getId());
+        for (PsiContractUser detailInfo : dto.getCwProjectClientContactDTOList()) {
+            //删除多余的领用详情
+            //根据基础表id获取所有的详情表id
+            if (null != idList) {
+                if (idList.contains(detailInfo.getId())){
+                    idList.remove(detailInfo.getId());
+                }
+            }
+        }
+        if (null != idList & idList.size()>0) {
+            idList.forEach(id->{
+                psiContractUserMapper.deleteById(id);
+            });
+        }
+        // 修改客户联系人信息
+        if (CollectionUtils.isNotEmpty(dto.getCwProjectClientContactDTOList())) {
+            for (PsiContractUser user : dto.getCwProjectClientContactDTOList()) {
+                //根据id去客户联系人表中查是否有对应数据  有则修改,无则添加
+                PsiContractUser contractUser = psiContractUserMapper.selectById(user.getId());
+                if (null == contractUser) {
+                    // 生成id
+                    String detailId = UUID.randomUUID().toString().replace("-", "");
+                    user.setId(detailId);
+                    user.setCreateById(userDTO.getId());
+                    user.setCreateTime(new Date());
+                    user.setUpdateById(userDTO.getId());
+                    user.setUpdateTime(new Date());
+                    user.setDelFlag(0);
+                    user.setContractId(info.getId());
+                    psiContractUserMapper.insert(user);
+                } else {
+                    user.setUpdateById(userDTO.getId());
+                    user.setUpdateTime(new Date());
+                    psiContractUserMapper.updateById(user);
+                }
+            }
+        }
+        // 修改附件信息列表
+        if (CollectionUtils.isNotEmpty(dto.getFiles())) {
+            psiOssService.saveOrUpdateFileList(dto.getFiles(),dto.getId(),"procureContract",TokenProvider.getCurrentToken ( ));
+//            infoService.updateFiles(dto.getFiles(), userDTO, dto.getId());
+        }
+        return dto.getId();
+    }
+
+    public String add(PsiContractInfoDto dto, UserDTO userDTO) throws Exception{
+        // 生成id
+        String id = UUID.randomUUID().toString().replace("-", "");
+        // 生成编号
+        String no = psiSerialnumTplService.genSerialNum(userDTO.getCompanyDTO().getId(), dto.BIZ_CODE,TokenProvider.getCurrentToken());
+        // 保存基础信息表信息
+        PsiContract info = new PsiContract();
+        BeanUtils.copyProperties(dto, info);
+        info.setId(id);
+        info.setContractNo(no);
+        info.setCreateById(userDTO.getId());
+        info.setCreateTime(new Date());
+        info.setUpdateById(userDTO.getId());
+        info.setUpdateTime(new Date());
+        info.setDelFlag(0);
+        psiContractMapper.insert(info);
+        //保存客户联系人信息
+        if (CollectionUtils.isNotEmpty(dto.getCwProjectClientContactDTOList())) {
+            for (PsiContractUser user : dto.getCwProjectClientContactDTOList()) {
+                // 生成id
+                String detailId = UUID.randomUUID().toString().replace("-", "");
+                user.setId(detailId);
+                user.setCreateById(userDTO.getId());
+                user.setCreateTime(new Date());
+                user.setUpdateById(userDTO.getId());
+                user.setUpdateTime(new Date());
+                user.setDelFlag(0);
+                user.setContractId(info.getId());
+                psiContractUserMapper.insert(user);
+            }
+        }
+        // 保存附件列表信息
+        if (CollectionUtils.isNotEmpty(dto.getFiles())) {
+            psiOssService.saveOrUpdateFileList(dto.getFiles(),dto.getId(),"procureContract",TokenProvider.getCurrentToken ( ));
+//            infoService.saveFiles(dto.getFiles(), userDTO, id);
+        }
+        return id;
+    }
+}

+ 86 - 0
jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/contract/service/dto/PsiContractInfoDto.java

@@ -0,0 +1,86 @@
+package com.jeeplus.psimanage.contract.service.dto;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.jeeplus.psimanage.contract.domain.PsiContractUser;
+import com.jeeplus.psimanage.oss.service.dto.WorkAttachmentDto;
+import lombok.Data;
+
+import java.util.Date;
+import java.util.List;
+
+/**
+ * @author: 王强
+ * @create: 2023-01-13 14:07
+ **/
+@Data
+public class PsiContractInfoDto {
+
+    //入库编号(字典值)
+    public static final String BIZ_CODE = "153";
+
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    private String[] effectiveDates;
+
+    private String createBy;
+
+    /**
+     * 基础表主键值
+     */
+    private String id;
+
+    //备注1
+    private String remarks1;
+    //备注2
+    private String remarks2;
+
+    private String procInsId;
+
+    /**
+     * 状态
+     */
+    private String status;
+
+    private String processDefinitionId;
+
+    //客户名称
+    private String name;
+
+    //是否有统一社会信用代码
+    private String isUscCode;
+
+    //统一社会信用代码
+    private String uscCode;
+
+    //注册地址
+    private String companyAddress;
+
+    //详细地址
+    private String address;
+
+    //公司电话
+    private String mobile;
+
+    //合同名称
+    private String contractName;
+
+    //合同编号
+    private String contractNo;
+
+    //签订日期
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    private Date signingDate;
+
+    //合同生效日期
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    private Date effectiveDate;
+
+    //合同终止日期
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    private Date endTime;
+
+
+    private List<WorkAttachmentDto> files;
+
+    //客户联系人信息
+    List<PsiContractUser> cwProjectClientContactDTOList;
+}

+ 72 - 0
jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/foodPurchase/controller/PsiFoodPurchaseController.java

@@ -0,0 +1,72 @@
+package com.jeeplus.psimanage.foodPurchase.controller;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.jeeplus.common.utils.ResponseUtil;
+import com.jeeplus.psimanage.foodPurchase.service.PsiFoodPurchaseService;
+import com.jeeplus.psimanage.foodPurchase.service.dto.PsiFoodPurchaseDto;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+import java.math.BigDecimal;
+import java.util.HashMap;
+import java.util.Map;
+
+@RestController
+@Api(tags = "进销存-食材采购")
+@RequestMapping("/psi/foodPurchase")
+public class PsiFoodPurchaseController {
+
+    @Resource
+    private PsiFoodPurchaseService psiFoodPurchaseService;
+
+    @ApiOperation(value = "根据id修改状态")
+    @PostMapping("/updateStatusById")
+    public void updateStatusById(@RequestBody PsiFoodPurchaseDto dto) {
+        psiFoodPurchaseService.updateStatusById(dto);
+    }
+
+    @ApiOperation(value = "删除")
+    @GetMapping("/remove")
+    public ResponseEntity<String> remove(@RequestParam String id) {
+        return ResponseEntity.ok(psiFoodPurchaseService.remove(id));
+    }
+
+    @ApiOperation(value = "新增、修改")
+    @PostMapping("/save")
+    public ResponseEntity<String> save(@RequestBody PsiFoodPurchaseDto dto) throws Exception {
+        String id = psiFoodPurchaseService.save(dto);
+        return ResponseUtil.newInstance()
+                .add("businessTable", "psi_management_food_purchase_basic")
+                .add("businessId", id)
+                .ok("操作成功");
+    }
+
+    @ApiOperation(value = "查询")
+    @GetMapping("/findById")
+    public ResponseEntity<PsiFoodPurchaseDto> findById(@RequestParam String id) throws Exception {
+        return ResponseEntity.ok(psiFoodPurchaseService.findById(id));
+    }
+
+    @ApiOperation(value = "列表查询")
+    @GetMapping("/list")
+    public ResponseEntity<IPage<PsiFoodPurchaseDto>> list(Page<PsiFoodPurchaseDto> page, PsiFoodPurchaseDto dto) throws Exception {
+        return ResponseEntity.ok(psiFoodPurchaseService.list(page, dto));
+    }
+
+    @ApiOperation(value = "采购金额统计")
+    @GetMapping("/statistics")
+    public ResponseEntity<Map<String, BigDecimal>> statistics(PsiFoodPurchaseDto dto) {
+        Map<String, BigDecimal> result = new HashMap<>(1);
+        result.put("totalPrice", psiFoodPurchaseService.statistics(dto));
+        return ResponseEntity.ok(result);
+    }
+}

+ 40 - 0
jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/foodPurchase/domain/PsiFoodPurchaseBasic.java

@@ -0,0 +1,40 @@
+package com.jeeplus.psimanage.foodPurchase.domain;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.jeeplus.core.domain.BaseEntity;
+import lombok.Data;
+
+import java.math.BigDecimal;
+import java.util.Date;
+import java.util.List;
+
+@Data
+@TableName("psi_management_food_purchase_basic")
+public class PsiFoodPurchaseBasic extends BaseEntity {
+
+    public static final String BIZ_CODE = "153";
+
+    private String remarks;
+
+    private String purchaseNo;
+
+    private String handledBy;
+
+    private String handledByOffice;
+
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date purchaseTime;
+
+    private BigDecimal totalPrice;
+
+    private String procInsId;
+
+    private String status;
+
+    private String processDefinitionId;
+
+    @TableField(exist = false)
+    private List<PsiFoodPurchaseDetail> detailInfos;
+}

+ 39 - 0
jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/foodPurchase/domain/PsiFoodPurchaseDetail.java

@@ -0,0 +1,39 @@
+package com.jeeplus.psimanage.foodPurchase.domain;
+
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.jeeplus.core.domain.BaseEntity;
+import lombok.Data;
+
+import java.math.BigDecimal;
+import java.util.Date;
+
+@Data
+@TableName("psi_management_food_purchase_detail")
+public class PsiFoodPurchaseDetail extends BaseEntity {
+
+    private String basicId;
+
+    private String goodsName;
+
+    private String foodType;
+
+    private BigDecimal purchaseNumber;
+
+    private String unit;
+
+    private BigDecimal unitPrice;
+
+    private BigDecimal totalPrice;
+
+    private String storageArea;
+
+    private String shelfLife;
+
+    @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
+    private Date expiryDate;
+
+    private Integer sort;
+
+    private String remarks;
+}

+ 28 - 0
jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/foodPurchase/mapper/PsiFoodPurchaseBasicMapper.java

@@ -0,0 +1,28 @@
+package com.jeeplus.psimanage.foodPurchase.mapper;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.core.toolkit.Constants;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.jeeplus.psimanage.foodPurchase.domain.PsiFoodPurchaseBasic;
+import com.jeeplus.psimanage.foodPurchase.service.dto.PsiFoodPurchaseDto;
+import org.apache.ibatis.annotations.Param;
+
+import java.math.BigDecimal;
+import java.util.List;
+
+public interface PsiFoodPurchaseBasicMapper extends BaseMapper<PsiFoodPurchaseBasic> {
+
+    void updateStatusById(@Param("id") String id, @Param("status") String status);
+
+    List<String> findChildIds(String department);
+
+    IPage<PsiFoodPurchaseDto> findList(Page<PsiFoodPurchaseDto> page, @Param(Constants.WRAPPER) QueryWrapper<PsiFoodPurchaseDto> queryWrapper);
+
+    String getUserNameByUserId(String handledBy);
+
+    String getOfficeNameByOfficeId(String handledByOffice);
+
+    BigDecimal statistics(@Param(Constants.WRAPPER) QueryWrapper<PsiFoodPurchaseDto> queryWrapper);
+}

+ 16 - 0
jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/foodPurchase/mapper/PsiFoodPurchaseDetailMapper.java

@@ -0,0 +1,16 @@
+package com.jeeplus.psimanage.foodPurchase.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.jeeplus.psimanage.foodPurchase.domain.PsiFoodPurchaseDetail;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+public interface PsiFoodPurchaseDetailMapper extends BaseMapper<PsiFoodPurchaseDetail> {
+
+    List<PsiFoodPurchaseDetail> getByBasicId(String basicId);
+
+    List<String> getIdByBasicId(String basicId);
+
+    void deleteByBasicId(@Param("basicId") String basicId);
+}

+ 58 - 0
jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/foodPurchase/mapper/xml/PsiFoodPurchaseBasicMapper.xml

@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.jeeplus.psimanage.foodPurchase.mapper.PsiFoodPurchaseBasicMapper">
+
+    <update id="updateStatusById">
+        UPDATE psi_management_food_purchase_basic
+        SET status = #{status}
+        WHERE id = #{id}
+    </update>
+
+    <select id="findChildIds" resultType="java.lang.String">
+        SELECT id
+        FROM sys_office
+        WHERE parent_id = #{department}
+    </select>
+
+    <select id="findList" resultType="com.jeeplus.psimanage.foodPurchase.service.dto.PsiFoodPurchaseDto">
+        SELECT
+            a.id,
+            a.create_by_id AS createBy,
+            a.create_time,
+            a.purchase_no,
+            a.handled_by,
+            a.handled_by_office,
+            a.purchase_time,
+            a.total_price,
+            a.status,
+            a.proc_ins_id,
+            a.process_definition_id,
+            su.name AS handledByName,
+            so.name AS handledByOfficeName,
+            art.ID_ AS task_id
+        FROM psi_management_food_purchase_basic a
+        LEFT JOIN sys_user su ON a.handled_by = su.id
+        LEFT JOIN sys_office so ON a.handled_by_office = so.id
+        LEFT JOIN act_ru_task art ON a.proc_ins_id = art.PROC_INST_ID_
+        ${ew.customSqlSegment}
+        ORDER BY a.update_time DESC
+    </select>
+
+    <select id="getUserNameByUserId" resultType="java.lang.String">
+        SELECT name
+        FROM sys_user
+        WHERE id = #{handledBy}
+    </select>
+
+    <select id="getOfficeNameByOfficeId" resultType="java.lang.String">
+        SELECT name
+        FROM sys_office
+        WHERE id = #{handledByOffice}
+    </select>
+
+    <select id="statistics" resultType="java.math.BigDecimal">
+        SELECT IFNULL(SUM(a.total_price), 0)
+        FROM psi_management_food_purchase_basic a
+        ${ew.customSqlSegment}
+    </select>
+</mapper>

+ 45 - 0
jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/foodPurchase/mapper/xml/PsiFoodPurchaseDetailMapper.xml

@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.jeeplus.psimanage.foodPurchase.mapper.PsiFoodPurchaseDetailMapper">
+
+    <select id="getByBasicId" resultType="com.jeeplus.psimanage.foodPurchase.domain.PsiFoodPurchaseDetail">
+        SELECT
+            id,
+            create_by_id,
+            create_time,
+            update_by_id,
+            update_time,
+            del_flag,
+            tenant_id,
+            remarks,
+            basic_id,
+            goods_name,
+            food_type,
+            purchase_number,
+            unit,
+            unit_price,
+            total_price,
+            storage_area,
+            shelf_life,
+            expiry_date,
+            sort
+        FROM psi_management_food_purchase_detail
+        WHERE basic_id = #{basicId}
+          AND del_flag = 0
+        ORDER BY sort ASC, create_time ASC
+    </select>
+
+    <select id="getIdByBasicId" resultType="java.lang.String">
+        SELECT id
+        FROM psi_management_food_purchase_detail
+        WHERE basic_id = #{basicId}
+          AND del_flag = 0
+    </select>
+
+    <update id="deleteByBasicId">
+        UPDATE psi_management_food_purchase_detail
+        SET del_flag = 1
+        WHERE basic_id = #{basicId}
+          AND del_flag = 0
+    </update>
+</mapper>

+ 303 - 0
jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/foodPurchase/service/PsiFoodPurchaseService.java

@@ -0,0 +1,303 @@
+package com.jeeplus.psimanage.foodPurchase.service;
+
+import cn.hutool.extra.spring.SpringUtil;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.jeeplus.common.TokenProvider;
+import com.jeeplus.flowable.feign.IFlowableApi;
+import com.jeeplus.psimanage.foodPurchase.domain.PsiFoodPurchaseBasic;
+import com.jeeplus.psimanage.foodPurchase.domain.PsiFoodPurchaseDetail;
+import com.jeeplus.psimanage.foodPurchase.mapper.PsiFoodPurchaseBasicMapper;
+import com.jeeplus.psimanage.foodPurchase.mapper.PsiFoodPurchaseDetailMapper;
+import com.jeeplus.psimanage.foodPurchase.service.dto.PsiFoodPurchaseDto;
+import com.jeeplus.psimanage.serialNumTpl.service.PsiSerialnumTplService;
+import com.jeeplus.sys.feign.IUserApi;
+import com.jeeplus.sys.service.dto.UserDTO;
+import com.jeeplus.utils.StringUtils;
+import org.springframework.beans.BeanUtils;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import javax.annotation.Resource;
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.Objects;
+import java.util.UUID;
+
+@Service
+@Transactional
+public class PsiFoodPurchaseService {
+
+    @Resource
+    private PsiFoodPurchaseBasicMapper basicMapper;
+
+    @Resource
+    private PsiFoodPurchaseDetailMapper detailMapper;
+
+    @Resource
+    private PsiSerialnumTplService psiSerialnumTplService;
+
+    @Resource
+    private IFlowableApi flowTaskService;
+
+    public void updateStatusById(PsiFoodPurchaseDto dto) {
+        basicMapper.updateStatusById(dto.getId(), dto.getStatus());
+    }
+
+    public String remove(String id) {
+        basicMapper.deleteById(id);
+        detailMapper.deleteByBasicId(id);
+        return "操作成功";
+    }
+
+    public String save(PsiFoodPurchaseDto dto) throws Exception {
+        UserDTO userDTO = SpringUtil.getBean(IUserApi.class).getByToken(TokenProvider.getCurrentToken());
+        if (StringUtils.isNotBlank(dto.getId()) && !"false".equals(dto.getId())) {
+            return update(dto, userDTO);
+        }
+        return add(dto, userDTO);
+    }
+
+    public String add(PsiFoodPurchaseDto dto, UserDTO userDTO) throws Exception {
+        validateDetailInfos(dto.getDetailInfos());
+        String id = UUID.randomUUID().toString().replace("-", "");
+
+        PsiFoodPurchaseBasic basic = new PsiFoodPurchaseBasic();
+        BeanUtils.copyProperties(dto, basic);
+        basic.setId(id);
+        basic.setPurchaseNo(buildPurchaseNo(userDTO));
+        basic.setHandledBy(StringUtils.isNotBlank(dto.getHandledById()) ? dto.getHandledById() : userDTO.getId());
+        basic.setHandledByOffice(resolveOfficeId(dto.getHandledByOffice(), userDTO));
+        basic.setPurchaseTime(Objects.nonNull(dto.getPurchaseTime()) ? dto.getPurchaseTime() : new Date());
+        basic.setTotalPrice(calculateBasicTotal(dto.getDetailInfos()));
+        basic.setStatus(StringUtils.isNotBlank(dto.getStatus()) ? dto.getStatus() : "0");
+        basic.setCreateById(userDTO.getId());
+        basic.setCreateTime(new Date());
+        basic.setUpdateById(userDTO.getId());
+        basic.setUpdateTime(new Date());
+        basic.setDelFlag(0);
+        basicMapper.insert(basic);
+
+        saveDetails(dto.getDetailInfos(), id, userDTO);
+        return id;
+    }
+
+    public String update(PsiFoodPurchaseDto dto, UserDTO userDTO) throws Exception {
+        validateDetailInfos(dto.getDetailInfos());
+        PsiFoodPurchaseBasic oldInfo = basicMapper.selectById(dto.getId());
+        if (oldInfo == null) {
+            throw new RuntimeException("食材采购单不存在");
+        }
+
+        PsiFoodPurchaseBasic basic = new PsiFoodPurchaseBasic();
+        BeanUtils.copyProperties(dto, basic);
+        basic.setId(dto.getId());
+        basic.setPurchaseNo(StringUtils.isNotBlank(dto.getPurchaseNo()) ? dto.getPurchaseNo() : oldInfo.getPurchaseNo());
+        basic.setHandledBy(StringUtils.isNotBlank(dto.getHandledById()) ? dto.getHandledById() : oldInfo.getHandledBy());
+        basic.setHandledByOffice(resolveOfficeId(dto.getHandledByOffice(), userDTO, oldInfo.getHandledByOffice()));
+        basic.setPurchaseTime(Objects.nonNull(dto.getPurchaseTime()) ? dto.getPurchaseTime() : oldInfo.getPurchaseTime());
+        basic.setTotalPrice(calculateBasicTotal(dto.getDetailInfos()));
+        basic.setStatus(StringUtils.isNotBlank(dto.getStatus()) ? dto.getStatus() : oldInfo.getStatus());
+        basic.setProcInsId(StringUtils.isNotBlank(dto.getProcInsId()) ? dto.getProcInsId() : oldInfo.getProcInsId());
+        basic.setProcessDefinitionId(StringUtils.isNotBlank(dto.getProcessDefinitionId()) ? dto.getProcessDefinitionId() : oldInfo.getProcessDefinitionId());
+        basic.setUpdateById(userDTO.getId());
+        basic.setUpdateTime(new Date());
+        basicMapper.updateById(basic);
+
+        List<String> dbIds = detailMapper.getIdByBasicId(dto.getId());
+        List<String> liveIds = new ArrayList<>();
+        if (CollectionUtils.isNotEmpty(dto.getDetailInfos())) {
+            int sort = 1;
+            for (PsiFoodPurchaseDetail detail : dto.getDetailInfos()) {
+                normalizeDetail(detail, sort++);
+                detail.setBasicId(dto.getId());
+                if (StringUtils.isNotBlank(detail.getId())) {
+                    liveIds.add(detail.getId());
+                }
+                if (StringUtils.isBlank(detail.getId()) || detailMapper.selectById(detail.getId()) == null) {
+                    detail.setId(UUID.randomUUID().toString().replace("-", ""));
+                    detail.setCreateById(userDTO.getId());
+                    detail.setCreateTime(new Date());
+                    detail.setUpdateById(userDTO.getId());
+                    detail.setUpdateTime(new Date());
+                    detail.setDelFlag(0);
+                    detailMapper.insert(detail);
+                    liveIds.add(detail.getId());
+                } else {
+                    detail.setUpdateById(userDTO.getId());
+                    detail.setUpdateTime(new Date());
+                    detailMapper.updateById(detail);
+                }
+            }
+        }
+        if (CollectionUtils.isNotEmpty(dbIds)) {
+            dbIds.stream()
+                    .filter(dbId -> !liveIds.contains(dbId))
+                    .forEach(detailMapper::deleteById);
+        }
+        return dto.getId();
+    }
+
+    public PsiFoodPurchaseDto findById(String id) {
+        PsiFoodPurchaseDto dto = new PsiFoodPurchaseDto();
+        PsiFoodPurchaseBasic basic = basicMapper.selectById(id);
+        if (basic == null) {
+            return dto;
+        }
+        BeanUtils.copyProperties(basic, dto);
+        dto.setHandledById(basic.getHandledBy());
+        dto.setHandledBy(basicMapper.getUserNameByUserId(basic.getHandledBy()));
+        dto.setHandledByOfficeName(basicMapper.getOfficeNameByOfficeId(basic.getHandledByOffice()));
+        dto.setDetailInfos(detailMapper.getByBasicId(id));
+        return dto;
+    }
+
+    public IPage<PsiFoodPurchaseDto> list(Page<PsiFoodPurchaseDto> page, PsiFoodPurchaseDto dto) {
+        QueryWrapper<PsiFoodPurchaseDto> queryWrapper = buildListWrapper(dto);
+        IPage<PsiFoodPurchaseDto> pageData = basicMapper.findList(page, queryWrapper);
+        pageData.getRecords().forEach(item -> {
+            if ("2".equals(item.getStatus()) && StringUtils.isNotBlank(item.getTaskId())) {
+                item.setAuditUserIds(flowTaskService.getTaskAuditUsers(item.getTaskId()));
+            }
+        });
+        return pageData;
+    }
+
+    public BigDecimal statistics(PsiFoodPurchaseDto dto) {
+        QueryWrapper<PsiFoodPurchaseDto> queryWrapper = buildStatisticsWrapper(dto);
+        BigDecimal total = basicMapper.statistics(queryWrapper);
+        return total == null ? BigDecimal.ZERO.setScale(2, RoundingMode.HALF_UP) : total.setScale(2, RoundingMode.HALF_UP);
+    }
+
+    private QueryWrapper<PsiFoodPurchaseDto> buildListWrapper(PsiFoodPurchaseDto dto) {
+        QueryWrapper<PsiFoodPurchaseDto> queryWrapper = new QueryWrapper<>();
+        queryWrapper.eq("a.del_flag", 0);
+        if (StringUtils.isNotBlank(dto.getPurchaseNo())) {
+            queryWrapper.like("a.purchase_no", dto.getPurchaseNo());
+        }
+        if (StringUtils.isNotBlank(dto.getHandledBy())) {
+            queryWrapper.eq("a.handled_by", dto.getHandledBy());
+        }
+        if (StringUtils.isNotBlank(dto.getHandledByOffice())) {
+            List<String> childIds = basicMapper.findChildIds(dto.getHandledByOffice());
+            if (CollectionUtils.isNotEmpty(childIds)) {
+                childIds.add(dto.getHandledByOffice());
+                queryWrapper.in("a.handled_by_office", childIds);
+            } else {
+                queryWrapper.eq("a.handled_by_office", dto.getHandledByOffice());
+            }
+        }
+        if (StringUtils.isNotBlank(dto.getStatus())) {
+            queryWrapper.eq("a.status", dto.getStatus());
+        }
+        if (dto.getPurchaseTimes() != null && dto.getPurchaseTimes().length == 2
+                && StringUtils.isNotBlank(dto.getPurchaseTimes()[0]) && StringUtils.isNotBlank(dto.getPurchaseTimes()[1])) {
+            queryWrapper.between("a.purchase_time", dto.getPurchaseTimes()[0], dto.getPurchaseTimes()[1]);
+        }
+        return queryWrapper;
+    }
+
+    private QueryWrapper<PsiFoodPurchaseDto> buildStatisticsWrapper(PsiFoodPurchaseDto dto) {
+        QueryWrapper<PsiFoodPurchaseDto> queryWrapper = new QueryWrapper<>();
+        queryWrapper.eq("a.del_flag", 0);
+        if (StringUtils.isNotBlank(dto.getHandledBy())) {
+            queryWrapper.eq("a.handled_by", dto.getHandledBy());
+        }
+        if (StringUtils.isNotBlank(dto.getHandledByOffice())) {
+            List<String> childIds = basicMapper.findChildIds(dto.getHandledByOffice());
+            if (CollectionUtils.isNotEmpty(childIds)) {
+                childIds.add(dto.getHandledByOffice());
+                queryWrapper.in("a.handled_by_office", childIds);
+            } else {
+                queryWrapper.eq("a.handled_by_office", dto.getHandledByOffice());
+            }
+        }
+        if (dto.getPurchaseTimes() != null && dto.getPurchaseTimes().length == 2
+                && StringUtils.isNotBlank(dto.getPurchaseTimes()[0]) && StringUtils.isNotBlank(dto.getPurchaseTimes()[1])) {
+            queryWrapper.between("a.purchase_time", dto.getPurchaseTimes()[0], dto.getPurchaseTimes()[1]);
+        }
+        return queryWrapper;
+    }
+
+    private void validateDetailInfos(List<PsiFoodPurchaseDetail> detailInfos) {
+        if (CollectionUtils.isEmpty(detailInfos)) {
+            throw new RuntimeException("采购明细不能为空");
+        }
+        for (PsiFoodPurchaseDetail detail : detailInfos) {
+            if (StringUtils.isBlank(detail.getGoodsName())) {
+                throw new RuntimeException("采购食材名称不能为空");
+            }
+        }
+    }
+
+    private void saveDetails(List<PsiFoodPurchaseDetail> detailInfos, String basicId, UserDTO userDTO) {
+        int sort = 1;
+        for (PsiFoodPurchaseDetail detail : detailInfos) {
+            normalizeDetail(detail, sort++);
+            detail.setId(UUID.randomUUID().toString().replace("-", ""));
+            detail.setBasicId(basicId);
+            detail.setCreateById(userDTO.getId());
+            detail.setCreateTime(new Date());
+            detail.setUpdateById(userDTO.getId());
+            detail.setUpdateTime(new Date());
+            detail.setDelFlag(0);
+            detailMapper.insert(detail);
+        }
+    }
+
+    private void normalizeDetail(PsiFoodPurchaseDetail detail, int sort) {
+        detail.setSort(sort);
+        if (detail.getTotalPrice() == null && detail.getPurchaseNumber() != null && detail.getUnitPrice() != null) {
+            detail.setTotalPrice(detail.getPurchaseNumber().multiply(detail.getUnitPrice()).setScale(2, RoundingMode.HALF_UP));
+        }
+        if (detail.getPurchaseNumber() != null) {
+            detail.setPurchaseNumber(detail.getPurchaseNumber().setScale(2, RoundingMode.HALF_UP));
+        }
+        if (detail.getUnitPrice() != null) {
+            detail.setUnitPrice(detail.getUnitPrice().setScale(2, RoundingMode.HALF_UP));
+        }
+        if (detail.getTotalPrice() != null) {
+            detail.setTotalPrice(detail.getTotalPrice().setScale(2, RoundingMode.HALF_UP));
+        }
+    }
+
+    private BigDecimal calculateBasicTotal(List<PsiFoodPurchaseDetail> detailInfos) {
+        BigDecimal total = BigDecimal.ZERO;
+        for (PsiFoodPurchaseDetail detail : detailInfos) {
+            if (detail.getTotalPrice() != null) {
+                total = total.add(detail.getTotalPrice());
+            } else if (detail.getPurchaseNumber() != null && detail.getUnitPrice() != null) {
+                total = total.add(detail.getPurchaseNumber().multiply(detail.getUnitPrice()));
+            }
+        }
+        return total.setScale(2, RoundingMode.HALF_UP);
+    }
+
+    private String buildPurchaseNo(UserDTO userDTO) {
+        try {
+            return psiSerialnumTplService.genSerialNum(userDTO.getCompanyDTO().getId(), PsiFoodPurchaseDto.BIZ_CODE, TokenProvider.getCurrentToken());
+        } catch (Exception ex) {
+            return "SCCG" + new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
+        }
+    }
+
+    private String resolveOfficeId(String dtoOfficeId, UserDTO userDTO) {
+        return resolveOfficeId(dtoOfficeId, userDTO, null);
+    }
+
+    private String resolveOfficeId(String dtoOfficeId, UserDTO userDTO, String fallback) {
+        if (StringUtils.isNotBlank(dtoOfficeId)) {
+            return dtoOfficeId;
+        }
+        if (userDTO != null && userDTO.getOfficeDTO() != null && StringUtils.isNotBlank(userDTO.getOfficeDTO().getId())) {
+            return userDTO.getOfficeDTO().getId();
+        }
+        return fallback;
+    }
+}

+ 53 - 0
jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/foodPurchase/service/dto/PsiFoodPurchaseDto.java

@@ -0,0 +1,53 @@
+package com.jeeplus.psimanage.foodPurchase.service.dto;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.jeeplus.psimanage.foodPurchase.domain.PsiFoodPurchaseDetail;
+import lombok.Data;
+
+import java.math.BigDecimal;
+import java.util.Date;
+import java.util.List;
+
+@Data
+public class PsiFoodPurchaseDto {
+
+    public static final String BIZ_CODE = "153";
+
+    private String id;
+
+    private String createBy;
+
+    private String remarks;
+
+    private String purchaseNo;
+
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date purchaseTime;
+
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private String[] purchaseTimes;
+
+    private BigDecimal totalPrice;
+
+    private String handledBy;
+
+    private String handledById;
+
+    private String handledByName;
+
+    private String handledByOffice;
+
+    private String handledByOfficeName;
+
+    private String procInsId;
+
+    private String status;
+
+    private String processDefinitionId;
+
+    private List<PsiFoodPurchaseDetail> detailInfos;
+
+    private String taskId;
+
+    private List<String> auditUserIds;
+}

+ 88 - 0
jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/loss/controller/PsiLossController.java

@@ -0,0 +1,88 @@
+package com.jeeplus.psimanage.loss.controller;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.jeeplus.common.excel.EasyExcelUtils;
+import com.jeeplus.common.excel.ExcelOptions;
+import com.jeeplus.common.excel.annotation.ExportMode;
+import com.jeeplus.common.utils.ResponseUtil;
+import com.jeeplus.logging.annotation.ApiLog;
+import com.jeeplus.logging.constant.enums.LogTypeEnum;
+import com.jeeplus.psimanage.loss.service.PsiLossService;
+import com.jeeplus.psimanage.loss.service.dto.PsiLossDto;
+import com.jeeplus.psimanage.loss.service.dto.PsiLossExportDto;
+import com.jeeplus.psimanage.psiWareHouse.service.dto.PsiWareHouseDto;
+import com.jeeplus.psimanage.psiWareHouse.service.dto.PsiWareSummaryExportDto;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletResponse;
+import java.util.List;
+import java.util.stream.Collectors;
+
+@RestController
+@Api(tags = "物资管理-报损申请")
+@RequestMapping(value = "/psi/loss")
+public class PsiLossController {
+
+    @Resource
+    private PsiLossService psiLossService;
+
+    @ApiOperation(value = "根据id修改状态")
+    @PostMapping(value = "updateStatusById")
+    public void updateStatusById(@RequestBody PsiLossDto dto) {
+        psiLossService.updateStatusById(dto);
+    }
+
+    @ApiOperation(value = "删除")
+    @GetMapping("/remove")
+    public ResponseEntity<String> remove(@RequestParam String id) {
+        return ResponseEntity.ok(psiLossService.remove(id));
+    }
+
+    @ApiOperation(value = "新增、修改")
+    @PostMapping("/save")
+    public ResponseEntity<String> save(@RequestBody PsiLossDto dto) throws Exception {
+        String id = psiLossService.save(dto);
+        return ResponseUtil.newInstance()
+                .add("businessTable", "psi_management_loss_basics")
+                .add("businessId", id)
+                .ok("操作成功");
+    }
+
+    @ApiOperation(value = "查询")
+    @GetMapping("/findById")
+    public ResponseEntity<PsiLossDto> findById(@RequestParam String id) throws Exception {
+        return ResponseEntity.ok(psiLossService.findById(id));
+    }
+
+    @ApiOperation(value = "列表查询")
+    @GetMapping("/list")
+    public ResponseEntity<IPage<PsiLossDto>> list(Page<PsiLossDto> page, PsiLossDto dto) throws Exception {
+        return ResponseEntity.ok(psiLossService.list(page, dto));
+    }
+
+    @ApiLog(value = "导出入库数据", type = LogTypeEnum.EXPORT)
+    @ApiOperation(value = "导出入库数据")
+    @GetMapping("/exportFile")
+    public void exportFile(Page<PsiLossDto> page, PsiLossDto dto, ExcelOptions options, HttpServletResponse response) throws Exception{
+        String fileName = options.getFilename();
+        String sheetName = options.getSheetName();
+        List<PsiLossExportDto> result;
+        if (ExportMode.current.equals(options.getMode())) {
+            result = psiLossService.exportRecordList(page, dto);
+        } else if (ExportMode.selected.equals(options.getMode())) {
+            result = psiLossService.exportRecordList(page, dto).stream().filter(item ->
+                    options.getSelectIds().contains(item.getId())
+            ).collect(Collectors.toList());
+        } else {
+            page.setSize(-1);
+            page.setCurrent(0);
+            result = psiLossService.exportRecordList(page, dto);
+        }
+        EasyExcelUtils.newInstance().exportExcel(result, sheetName, PsiLossExportDto.class, fileName, null, response);
+    }
+}

+ 39 - 0
jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/loss/domain/PsiLossBasic.java

@@ -0,0 +1,39 @@
+package com.jeeplus.psimanage.loss.domain;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.jeeplus.core.domain.BaseEntity;
+import lombok.Data;
+
+import java.util.Date;
+import java.util.List;
+
+@Data
+@TableName("psi_management_loss_basics")
+public class PsiLossBasic extends BaseEntity {
+
+    public static final String BIZ_CODE = "152";
+
+    private String remarks;
+
+    private String procInsId;
+
+    private String status;
+
+    private String processDefinitionId;
+
+    @TableField("collect_no")
+    private String lossNo;
+
+    private String handledBy;
+
+    private String handledByOffice;
+
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    @TableField("collect_date")
+    private Date lossDate;
+
+    @TableField(exist = false)
+    private List<PsiLossDetailed> detailInfos;
+}

+ 54 - 0
jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/loss/domain/PsiLossDetailed.java

@@ -0,0 +1,54 @@
+package com.jeeplus.psimanage.loss.domain;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.jeeplus.core.domain.BaseEntity;
+import com.jeeplus.psimanage.oss.service.dto.WorkAttachmentDto;
+import lombok.Data;
+
+import java.util.Date;
+import java.util.List;
+
+@Data
+@TableName("psi_management_loss_detailed")
+public class PsiLossDetailed extends BaseEntity {
+
+    private String basicId;
+
+    private String recipientAgent;
+
+    @TableField(exist = false)
+    private String recipientAgentId;
+
+    @TableField(exist = false)
+    private String recipientOffice;
+
+    @TableField("collect_type")
+    private String collectType;
+
+    @TableField(exist = false)
+    private String collectTypeId;
+
+    private String goodsName;
+
+    @TableField("loss_number")
+    private String lossNumber;
+
+    private String company;
+
+    @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
+    private Date produceDate;
+
+    private String shelfLife;
+
+    private String spec;
+
+    private String shelfLifeUnit;
+
+    @TableField(exist = false)
+    private String surplusNumber;
+
+    @TableField(exist = false)
+    private List<WorkAttachmentDto> fileInfoLost;
+}

+ 25 - 0
jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/loss/mapper/PsiLossBasicMapper.java

@@ -0,0 +1,25 @@
+package com.jeeplus.psimanage.loss.mapper;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.core.toolkit.Constants;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.jeeplus.psimanage.loss.domain.PsiLossBasic;
+import com.jeeplus.psimanage.loss.service.dto.PsiLossDto;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+public interface PsiLossBasicMapper extends BaseMapper<PsiLossBasic> {
+
+    void updateStatusById(@Param("id") String id, @Param("status") String status);
+
+    List<String> findChildIds(String department);
+
+    IPage<PsiLossDto> findList(Page<PsiLossDto> page, @Param(Constants.WRAPPER) QueryWrapper<PsiLossDto> queryWrapper);
+
+    String getUserNameByUserId(String handledBy);
+
+    String getOfficeNameByOfficeId(String handledByOffice);
+}

+ 16 - 0
jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/loss/mapper/PsiLossDetailedMapper.java

@@ -0,0 +1,16 @@
+package com.jeeplus.psimanage.loss.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.jeeplus.psimanage.loss.domain.PsiLossDetailed;
+import com.jeeplus.psimanage.oss.service.dto.WorkAttachmentDto;
+
+import java.util.List;
+
+public interface PsiLossDetailedMapper extends BaseMapper<PsiLossDetailed> {
+
+    List<PsiLossDetailed> getByBasicId(String id);
+
+    List<WorkAttachmentDto> getByAttachmentId(String id);
+
+    List<String> getIdByBasicId(String id);
+}

+ 54 - 0
jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/loss/mapper/xml/PsiLossBasicMapper.xml

@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.jeeplus.psimanage.loss.mapper.PsiLossBasicMapper">
+
+    <update id="updateStatusById">
+        UPDATE psi_management_loss_basics
+        SET status = #{status}
+        WHERE id = #{id}
+    </update>
+
+    <select id="findChildIds" resultType="java.lang.String">
+        SELECT id
+        FROM sys_office
+        WHERE parent_id = #{department}
+    </select>
+
+    <select id="findList" resultType="com.jeeplus.psimanage.loss.service.dto.PsiLossDto">
+        SELECT DISTINCT
+            a.id,
+            a.create_by_id AS createBy,
+            a.create_time,
+            a.status,
+            a.proc_ins_id,
+            a.process_definition_id,
+            a.collect_no AS lossNo,
+            a.handled_by,
+            a.handled_by_office,
+            a.collect_date AS lossDate,
+            b.goods_name,
+            b.id AS detail_id,
+            so.name AS handledByOfficeName,
+            su.name AS handledByName,
+            art.ID_ AS task_id
+        FROM psi_management_loss_basics a
+        LEFT JOIN sys_user su ON a.handled_by = su.id
+        LEFT JOIN sys_office so ON a.handled_by_office = so.id
+        LEFT JOIN psi_management_loss_detailed b ON a.id = b.basic_id AND b.del_flag = '0'
+        LEFT JOIN act_ru_task art ON a.proc_ins_id = art.PROC_INST_ID_
+        ${ew.customSqlSegment}
+        ORDER BY a.update_time DESC
+    </select>
+
+    <select id="getUserNameByUserId" resultType="java.lang.String">
+        SELECT name
+        FROM sys_user
+        WHERE id = #{handledBy}
+    </select>
+
+    <select id="getOfficeNameByOfficeId" resultType="java.lang.String">
+        SELECT name
+        FROM sys_office
+        WHERE id = #{handledByOffice}
+    </select>
+</mapper>

+ 58 - 0
jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/loss/mapper/xml/PsiLossDetailedMapper.xml

@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.jeeplus.psimanage.loss.mapper.PsiLossDetailedMapper">
+
+    <select id="getByBasicId" resultType="com.jeeplus.psimanage.loss.domain.PsiLossDetailed">
+        SELECT
+            a.id,
+            a.create_by_id,
+            a.create_time,
+            a.update_by_id,
+            a.update_time,
+            a.del_flag,
+            a.remarks,
+            a.basic_id,
+            a.recipient_agent,
+            a.collect_type,
+            a.goods_name,
+            a.loss_number,
+            a.company,
+            a.produce_date,
+            a.shelf_life,
+            a.spec,
+            a.shelf_life_unit,
+            su.name AS recipientAgent,
+            su.id AS recipientAgentId,
+            so.name AS recipientOffice,
+            d.id AS collectTypeId,
+            d.name AS collectType
+
+        FROM psi_management_loss_detailed a
+        LEFT JOIN sys_user su ON a.recipient_agent = su.id
+        LEFT JOIN sys_office so ON su.office_id = so.id
+
+        LEFT JOIN psi_management_type d ON a.collect_type = d.id
+        WHERE a.basic_id = #{id}
+          AND a.del_flag = '0'
+        ORDER BY a.create_time ASC
+    </select>
+
+    <select id="getByAttachmentId" resultType="com.jeeplus.psimanage.oss.service.dto.WorkAttachmentDto">
+        SELECT
+            id,
+            url,
+            attachment_name AS `name`,
+            create_by_id AS `by`,
+            create_time
+        FROM work_attachment
+        WHERE del_flag = 0
+          AND attachment_id = #{id}
+    </select>
+
+    <select id="getIdByBasicId" resultType="java.lang.String">
+        SELECT id
+        FROM psi_management_loss_detailed
+        WHERE basic_id = #{id}
+          AND del_flag = 0
+    </select>
+</mapper>

+ 405 - 0
jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/loss/service/PsiLossService.java

@@ -0,0 +1,405 @@
+package com.jeeplus.psimanage.loss.service;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.extra.spring.SpringUtil;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.jeeplus.common.TokenProvider;
+import com.jeeplus.core.query.QueryWrapperGenerator;
+import com.jeeplus.flowable.feign.IFlowableApi;
+import com.jeeplus.psimanage.collect.domain.PsiCollectDetailedRecord;
+import com.jeeplus.psimanage.collect.service.dto.PsiCollectDto;
+import com.jeeplus.psimanage.collect.service.dto.PsiCollectExportDto;
+import com.jeeplus.psimanage.loss.domain.PsiLossBasic;
+import com.jeeplus.psimanage.loss.domain.PsiLossDetailed;
+import com.jeeplus.psimanage.loss.mapper.PsiLossBasicMapper;
+import com.jeeplus.psimanage.loss.mapper.PsiLossDetailedMapper;
+import com.jeeplus.psimanage.loss.service.dto.PsiLossDto;
+import com.jeeplus.psimanage.loss.service.dto.PsiLossExportDto;
+import com.jeeplus.psimanage.oss.service.dto.WorkAttachmentDto;
+import com.jeeplus.psimanage.psiWareHouse.domain.PsiWareHouseDetailed;
+import com.jeeplus.psimanage.psiWareHouse.mapper.PsiWareHouseDetailedMapper;
+import com.jeeplus.psimanage.psiWareHouse.mapper.PsiWareHouseSummaryMapper;
+import com.jeeplus.psimanage.purchase.service.PsiMaterialService;
+import com.jeeplus.psimanage.serialNumTpl.service.PsiSerialnumTplService;
+import com.jeeplus.sys.feign.IUserApi;
+import com.jeeplus.sys.feign.IWorkAttachmentApi;
+import com.jeeplus.sys.service.dto.UserDTO;
+import com.jeeplus.utils.StringUtils;
+import org.springframework.beans.BeanUtils;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import javax.annotation.Resource;
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.text.SimpleDateFormat;
+import java.util.*;
+import java.util.stream.Collectors;
+
+@Service
+@Transactional
+public class PsiLossService {
+
+    @Resource
+    private PsiLossBasicMapper basicMapper;
+
+    @Resource
+    private PsiLossDetailedMapper detailedMapper;
+
+    @Resource
+    private PsiSerialnumTplService psiSerialnumTplService;
+
+    @Resource
+    private PsiMaterialService psiMaterialService;
+
+    @Resource
+    private PsiWareHouseSummaryMapper summaryMapper;
+
+    @Resource
+    private PsiWareHouseDetailedMapper psiWareHouseDetailedMapper;
+
+    @Resource
+    private IFlowableApi flowTaskService;
+
+    public void updateStatusById(PsiLossDto dto) {
+        basicMapper.updateStatusById(dto.getId(), dto.getStatus());
+    }
+
+    public String remove(String id) {
+        basicMapper.deleteById(id);
+        List<PsiLossDetailed> detailList = detailedMapper.getByBasicId(id);
+        if (detailList != null) {
+            detailList.forEach(detail -> {
+                SpringUtil.getBean(IWorkAttachmentApi.class).deleteByAttachmentId(detail.getId());
+                detailedMapper.deleteById(detail.getId());
+            });
+        }
+        SpringUtil.getBean(IWorkAttachmentApi.class).deleteByAttachmentId(id);
+        return "操作成功";
+    }
+
+    public String save(PsiLossDto dto) throws Exception {
+        UserDTO userDTO = SpringUtil.getBean(IUserApi.class).getByToken(TokenProvider.getCurrentToken());
+        synchronized (this) {
+            if (StringUtils.isNotBlank(dto.getId()) && !"false".equals(dto.getId())) {
+                return update(dto, userDTO);
+            }
+            return add(dto, userDTO);
+        }
+    }
+
+    public String add(PsiLossDto dto, UserDTO userDTO) throws Exception {
+        validateDetailInfos(dto.getDetailInfos());
+        PsiLossDetailed detail = dto.getDetailInfos().get(0);
+        prepareDetail(detail, userDTO);
+        fillStockInfo(detail);
+
+        String id = UUID.randomUUID().toString().replace("-", "");
+        PsiLossBasic info = new PsiLossBasic();
+        BeanUtils.copyProperties(dto, info);
+        info.setId(id);
+        info.setLossNo(buildLossNo(dto, userDTO));
+        info.setHandledBy(dto.getHandledById());
+        info.setCreateById(userDTO.getId());
+        info.setCreateTime(new Date());
+        info.setUpdateById(userDTO.getId());
+        info.setUpdateTime(new Date());
+        info.setDelFlag(0);
+        basicMapper.insert(info);
+
+        detail.setId(UUID.randomUUID().toString().replace("-", ""));
+        detail.setBasicId(id);
+        detailedMapper.insert(detail);
+        saveDetailFiles(detail, userDTO);
+
+        if (CollectionUtils.isNotEmpty(dto.getFiles())) {
+            psiMaterialService.saveFiles(dto.getFiles(), userDTO, id);
+        }
+
+        if (isApproved(info.getStatus())) {
+            deductInventory(detail);
+        }
+        return id;
+    }
+
+    public String update(PsiLossDto dto, UserDTO userDTO) throws Exception {
+        validateDetailInfos(dto.getDetailInfos());
+        PsiLossBasic oldInfo = basicMapper.selectById(dto.getId());
+        if (oldInfo == null) {
+            throw new RuntimeException("报损单不存在");
+        }
+
+        PsiLossBasic info = new PsiLossBasic();
+        BeanUtils.copyProperties(dto, info);
+        info.setId(dto.getId());
+        info.setHandledBy(dto.getHandledById());
+        info.setUpdateById(userDTO.getId());
+        info.setUpdateTime(new Date());
+        basicMapper.updateById(info);
+
+        List<String> dbIds = detailedMapper.getIdByBasicId(dto.getId());
+        List<String> liveIds = new ArrayList<>();
+        PsiLossDetailed detail = dto.getDetailInfos().get(0);
+        prepareDetail(detail, userDTO);
+        fillStockInfo(detail);
+        detail.setBasicId(dto.getId());
+
+        if (StringUtils.isNotBlank(detail.getId())) {
+            liveIds.add(detail.getId());
+        }
+        if (CollectionUtils.isNotEmpty(dbIds)) {
+            dbIds.stream()
+                    .filter(dbId -> !liveIds.contains(dbId))
+                    .forEach(deleteId -> {
+                        SpringUtil.getBean(IWorkAttachmentApi.class).deleteByAttachmentId(deleteId);
+                        detailedMapper.deleteById(deleteId);
+                    });
+        }
+
+        if (StringUtils.isBlank(detail.getId()) || detailedMapper.selectById(detail.getId()) == null) {
+            detail.setId(UUID.randomUUID().toString().replace("-", ""));
+            detail.setCreateById(userDTO.getId());
+            detail.setCreateTime(new Date());
+            detail.setDelFlag(0);
+            detailedMapper.insert(detail);
+            saveDetailFiles(detail, userDTO);
+        } else {
+            detailedMapper.updateById(detail);
+            psiMaterialService.updateFiles(detail.getFileInfoLost(), userDTO, detail.getId());
+        }
+
+        psiMaterialService.updateFiles(dto.getFiles(), userDTO, dto.getId());
+
+        if (!isApproved(oldInfo.getStatus()) && isApproved(info.getStatus())) {
+            deductInventory(detail);
+        }
+        return dto.getId();
+    }
+
+    public PsiLossDto findById(String id) throws Exception {
+        PsiLossDto dto = new PsiLossDto();
+        PsiLossBasic info = basicMapper.selectById(id);
+        if (info == null) {
+            return dto;
+        }
+        BeanUtils.copyProperties(info, dto);
+        List<PsiLossDetailed> detailList = detailedMapper.getByBasicId(id);
+        if (CollectionUtils.isNotEmpty(detailList)) {
+            detailList.forEach(detail -> {
+                detail.setSurplusNumber(formatNumber(getAvailableBottleCount(detail.getGoodsName(), getCollectTypeId(detail))));
+                List<WorkAttachmentDto> fileList = detailedMapper.getByAttachmentId(detail.getId());
+                if (CollectionUtils.isNotEmpty(fileList)) {
+                    fileList.forEach(file -> file.setCreateBy(SpringUtil.getBean(IUserApi.class).getById(file.getBy())));
+                }
+                detail.setFileInfoLost(fileList);
+            });
+        }
+        dto.setDetailInfos(detailList);
+
+        List<WorkAttachmentDto> files = detailedMapper.getByAttachmentId(info.getId());
+        if (CollectionUtils.isNotEmpty(files)) {
+            files.forEach(file -> file.setCreateBy(SpringUtil.getBean(IUserApi.class).getById(file.getBy())));
+        }
+        dto.setFiles(files);
+        dto.setHandledById(info.getHandledBy());
+        dto.setHandledBy(basicMapper.getUserNameByUserId(info.getHandledBy()));
+        dto.setHandledByOfficeName(basicMapper.getOfficeNameByOfficeId(info.getHandledByOffice()));
+        return dto;
+    }
+
+    public IPage<PsiLossDto> list(Page<PsiLossDto> page, PsiLossDto dto) throws Exception {
+        QueryWrapper<PsiLossDto> queryWrapper = QueryWrapperGenerator.buildQueryCondition(dto, PsiLossDto.class);
+        queryWrapper.eq("a.del_flag", "0");
+        if (StringUtils.isNotBlank(dto.getLossNo())) {
+            queryWrapper.like("a.collect_no", dto.getLossNo());
+        }
+        if (StringUtils.isNotBlank(dto.getGoodsName())) {
+            queryWrapper.like("b.goods_name", dto.getGoodsName());
+        }
+        if (StringUtils.isNotBlank(dto.getHandledBy())) {
+            queryWrapper.eq("su.id", dto.getHandledBy());
+        }
+        if (StringUtils.isNotBlank(dto.getHandledByOffice())) {
+            List<String> childIds = basicMapper.findChildIds(dto.getHandledByOffice());
+            if (childIds != null && !childIds.isEmpty()) {
+                childIds.add(dto.getHandledByOffice());
+                queryWrapper.in("a.handled_by_office", childIds);
+            } else {
+                queryWrapper.eq("a.handled_by_office", dto.getHandledByOffice());
+            }
+        }
+        if (dto.getLossDates() != null && dto.getLossDates().length == 2) {
+            queryWrapper.between("a.collect_date", dto.getLossDates()[0], dto.getLossDates()[1]);
+        }
+        IPage<PsiLossDto> pageData = basicMapper.findList(page, queryWrapper);
+        pageData.getRecords().forEach(item -> {
+            if ("2".equals(item.getStatus()) && StringUtils.isNotBlank(item.getTaskId())) {
+                item.setAuditUserIds(flowTaskService.getTaskAuditUsers(item.getTaskId()));
+            }
+        });
+        return pageData;
+    }
+
+    private void validateDetailInfos(List<PsiLossDetailed> detailInfos) {
+        if (CollectionUtils.isEmpty(detailInfos)) {
+            throw new RuntimeException("报损明细不能为空");
+        }
+        if (detailInfos.size() != 1) {
+            throw new RuntimeException("报损单只能保存一条明细");
+        }
+        PsiLossDetailed detail = detailInfos.get(0);
+        if (StringUtils.isBlank(detail.getRecipientAgentId())) {
+            throw new RuntimeException("报损人不能为空");
+        }
+        if (StringUtils.isBlank(getCollectTypeId(detail))) {
+            throw new RuntimeException("报损类型不能为空");
+        }
+        if (StringUtils.isBlank(detail.getGoodsName())) {
+            throw new RuntimeException("物品名称不能为空");
+        }
+        if (StringUtils.isBlank(detail.getLossNumber())) {
+            throw new RuntimeException("报损数量不能为空");
+        }
+    }
+
+    private void prepareDetail(PsiLossDetailed detail, UserDTO userDTO) {
+        detail.setRecipientAgent(detail.getRecipientAgentId());
+        detail.setCollectType(getCollectTypeId(detail));
+        detail.setUpdateById(userDTO.getId());
+        detail.setUpdateTime(new Date());
+        if (StringUtils.isBlank(detail.getId())) {
+            detail.setCreateById(userDTO.getId());
+            detail.setCreateTime(new Date());
+            detail.setDelFlag(0);
+        }
+    }
+
+    private void saveDetailFiles(PsiLossDetailed detail, UserDTO userDTO) throws Exception {
+        if (CollectionUtils.isNotEmpty(detail.getFileInfoLost())) {
+            psiMaterialService.saveFiles(detail.getFileInfoLost(), userDTO, detail.getId());
+        }
+    }
+
+    private void fillStockInfo(PsiLossDetailed detail) {
+        detail.setSurplusNumber(formatNumber(getAvailableBottleCount(detail.getGoodsName(), getCollectTypeId(detail))));
+    }
+
+    private void deductInventory(PsiLossDetailed detail) {
+        double lossNumber = parseDouble(detail.getLossNumber());
+        double available = getAvailableBottleCount(detail.getGoodsName(), getCollectTypeId(detail));
+        if (lossNumber - available > 0.001D) {
+            throw new RuntimeException("报损数量不能大于当前库存数量");
+        }
+        List<PsiWareHouseDetailed> updateList = batchCalculation(detail);
+        if (CollUtil.isNotEmpty(updateList)) {
+            psiWareHouseDetailedMapper.updateBatchById(updateList);
+        }
+    }
+
+    private List<PsiWareHouseDetailed> batchCalculation(PsiLossDetailed detail) {
+        List<PsiWareHouseDetailed> inventoryList = summaryMapper.getInfoByProduceDateDesc(detail.getGoodsName(), getCollectTypeId(detail));
+        List<PsiWareHouseDetailed> updateList = new ArrayList<>();
+        double pending = parseDouble(detail.getLossNumber());
+        for (PsiWareHouseDetailed inventory : inventoryList) {
+            if (pending <= 0.001D) {
+                break;
+            }
+            double currentBox = parseDouble(inventory.getCurrentInventory());
+            double spec = parseSpec(inventory.getSpec());
+            double totalUnit = round(currentBox * spec);
+            if (totalUnit <= 0.001D) {
+                continue;
+            }
+            PsiWareHouseDetailed update = new PsiWareHouseDetailed();
+            update.setId(inventory.getId());
+            if (totalUnit >= pending) {
+                update.setCurrentInventory(formatNumber(round((totalUnit - pending) / spec)));
+                pending = 0D;
+            } else {
+                update.setCurrentInventory("0");
+                pending = round(pending - totalUnit);
+            }
+            updateList.add(update);
+        }
+        return updateList;
+    }
+
+    private double getAvailableBottleCount(String goodsName, String collectTypeId) {
+        if (StringUtils.isBlank(goodsName) || StringUtils.isBlank(collectTypeId)) {
+            return 0D;
+        }
+        List<PsiWareHouseDetailed> inventoryList = summaryMapper.getInfoByProduceDateDesc(goodsName, collectTypeId);
+        double total = 0D;
+        for (PsiWareHouseDetailed inventory : inventoryList) {
+            total += parseDouble(inventory.getCurrentInventory()) * parseSpec(inventory.getSpec());
+        }
+        return round(total);
+    }
+
+    private String getCollectTypeId(PsiLossDetailed detail) {
+        return StringUtils.isNotBlank(detail.getCollectTypeId()) ? detail.getCollectTypeId() : detail.getCollectType();
+    }
+
+    private String buildLossNo(PsiLossDto dto, UserDTO userDTO) {
+        try {
+            return psiSerialnumTplService.genSerialNum(userDTO.getCompanyDTO().getId(), PsiLossDto.BIZ_CODE, TokenProvider.getCurrentToken());
+        } catch (Exception ex) {
+            return "BS" + new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
+        }
+    }
+
+    private boolean isApproved(String status) {
+        return "5".equals(status);
+    }
+
+    private double parseDouble(String value) {
+        if (StringUtils.isBlank(value)) {
+            return 0D;
+        }
+        return Double.parseDouble(value);
+    }
+
+    private double parseSpec(String spec) {
+        double parsed = parseDouble(spec);
+        return parsed <= 0 ? 1D : parsed;
+    }
+
+    private double round(double value) {
+        return BigDecimal.valueOf(value).setScale(2, RoundingMode.HALF_UP).doubleValue();
+    }
+
+    private String formatNumber(double value) {
+        return BigDecimal.valueOf(value).stripTrailingZeros().toPlainString();
+    }
+
+
+    public List<PsiLossExportDto> exportRecordList(Page<PsiLossDto> page , PsiLossDto dto) throws Exception{
+        List<PsiLossDto> basicList = this.list(page, dto).getRecords();
+        List<PsiLossExportDto> result = new ArrayList<>();
+        if (CollectionUtils.isEmpty(basicList)) {
+            return result;
+        }
+        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
+        basicList.forEach(item -> {
+            List<PsiLossDetailed> recordList = detailedMapper.getByBasicId(item.getId());
+            if (CollectionUtils.isEmpty(recordList)) {
+                return;
+            }
+            recordList.forEach(record -> {
+                PsiLossExportDto exportDto = new PsiLossExportDto();
+                exportDto.setLossNo(item.getLossNo());
+                exportDto.setRecipientAgent(record.getRecipientAgent());
+                exportDto.setRecipientOffice(record.getRecipientOffice());
+                exportDto.setCollectType(record.getCollectType());
+                exportDto.setGoodsName(record.getGoodsName());
+                exportDto.setProduceDate(record.getProduceDate() == null ? "暂无生产日期" : dateFormat.format(record.getProduceDate()));
+                exportDto.setLossNumber(record.getLossNumber());
+                result.add(exportDto);
+            });
+        });
+        return result;
+    }
+}

+ 57 - 0
jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/loss/service/dto/PsiLossDto.java

@@ -0,0 +1,57 @@
+package com.jeeplus.psimanage.loss.service.dto;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.jeeplus.psimanage.loss.domain.PsiLossDetailed;
+import com.jeeplus.psimanage.oss.service.dto.WorkAttachmentDto;
+import lombok.Data;
+
+import java.util.Date;
+import java.util.List;
+
+@Data
+public class PsiLossDto {
+
+    private String remarks;
+
+    private String createBy;
+
+    public static final String BIZ_CODE = "152";
+
+    private String id;
+
+    private String goodsName;
+
+    private String procInsId;
+
+    private String status;
+
+    private String processDefinitionId;
+
+    private String lossNo;
+
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    private Date lossDate;
+
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    private String[] lossDates;
+
+    private String handledBy;
+
+    private String handledById;
+
+    private String handledByName;
+
+    private String handledByOffice;
+
+    private String handledByOfficeName;
+
+    private List<WorkAttachmentDto> files;
+
+    private List<PsiLossDetailed> detailInfos;
+
+    private String taskId;
+
+    private List<String> auditUserIds;
+
+    private String detailId;
+}

+ 38 - 0
jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/loss/service/dto/PsiLossExportDto.java

@@ -0,0 +1,38 @@
+package com.jeeplus.psimanage.loss.service.dto;
+
+import com.alibaba.excel.annotation.ExcelIgnore;
+import com.alibaba.excel.annotation.ExcelProperty;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.Data;
+
+import java.util.Date;
+import java.util.List;
+
+@Data
+public class PsiLossExportDto {
+
+    @ExcelIgnore
+    private String id;
+
+    @ExcelProperty("报损编号")
+    private String lossNo;
+
+    @ExcelProperty("报损人")
+    private String recipientAgent;
+
+    @ExcelProperty("报损部门")
+    private String recipientOffice;
+
+    @ExcelProperty("物品类型")
+    private String collectType;
+
+    @ExcelProperty("物品名称")
+    private String goodsName;
+
+    @ExcelProperty("生产日期")
+    private String produceDate;
+
+    @ExcelProperty("报损数量")
+    private String lossNumber;
+
+}

+ 153 - 0
jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/materialType/controller/PsiMaterialTypeController.java

@@ -0,0 +1,153 @@
+package com.jeeplus.psimanage.materialType.controller;
+
+import com.jeeplus.psimanage.materialType.domain.PsiMaterialTypeInfo;
+import com.jeeplus.psimanage.materialType.mapper.PsiMaterialTypeMapper;
+import com.jeeplus.psimanage.materialType.service.PsiMaterialTypeForTreeDataService;
+import com.jeeplus.psimanage.materialType.service.PsiMaterialTypeService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+import java.util.List;
+
+/**
+ * @author: 王强
+ * @create: 2022-11-25 09:18
+ **/
+@RestController
+@Api(tags ="财务-报销类型管理")
+@RequestMapping(value = "/psi/materialType")
+public class PsiMaterialTypeController {
+
+    @Resource
+    private PsiMaterialTypeService service;
+
+    @Resource
+    private PsiMaterialTypeForTreeDataService treeService;
+
+    @Resource
+    private PsiMaterialTypeMapper mapper;
+
+    /**
+     * 列表查询
+     * @param info
+     * @return
+     */
+    @ApiOperation(value = "列表查询")
+    @GetMapping("/list")
+    public ResponseEntity<List<PsiMaterialTypeInfo>> list(PsiMaterialTypeInfo info) {
+        List<PsiMaterialTypeInfo> list = service.list(info);
+        return ResponseEntity.ok(list);
+    }
+
+    /**
+     * 列表查询
+     * @param info
+     * @return
+     */
+    @ApiOperation(value = "列表查询")
+    @GetMapping("/bxList")
+    public ResponseEntity<List<PsiMaterialTypeInfo>> bxList(PsiMaterialTypeInfo info) {
+        List<PsiMaterialTypeInfo> list = service.bxList(info);
+        return ResponseEntity.ok(list);
+    }
+
+    /**
+     * 采购类型列表查询
+     * @param info
+     * @return
+     */
+    @ApiOperation(value = "采购类型列表查询")
+    @GetMapping("/cgList")
+    public ResponseEntity<List<PsiMaterialTypeInfo>> cgList(PsiMaterialTypeInfo info) {
+        List<PsiMaterialTypeInfo> list = service.cgList(info);
+        return ResponseEntity.ok(list);
+    }
+
+    /**
+     * 新增/修改
+     * @param info
+     * @return
+     */
+    @ApiOperation(value = "新增/修改")
+    @PostMapping("/save")
+    public ResponseEntity<String> save(@RequestBody PsiMaterialTypeInfo info) {
+        String s = service.saveM(info);
+        return ResponseEntity.ok(s);
+    }
+
+    /**
+     * 根据id查询
+     * @param id
+     * @return
+     */
+    @ApiOperation(value = "根据id查询")
+    @GetMapping("/findById")
+    public ResponseEntity<PsiMaterialTypeInfo> findById(String id) {
+        PsiMaterialTypeInfo info = service.getById(id);
+        return ResponseEntity.ok(info);
+    }
+
+    /**
+     * 根据id删除
+     * @param id
+     * @return
+     */
+    @ApiOperation(value = "根据id删除")
+    @GetMapping("/deleteById")
+    public ResponseEntity<String> deleteById(String id) {
+        String s = service.remove(id);
+        return ResponseEntity.ok(s);
+    }
+
+    /**
+     * 查询树形
+     * @param extId 排除的ID
+     * @return
+     */
+    @ApiOperation(value = "查询树形")
+    @GetMapping("/treeData")
+    public ResponseEntity<List<PsiMaterialTypeInfo>> treeData(@RequestParam(required = false) String extId, @RequestParam(required = false) String type) throws Exception{
+        List<PsiMaterialTypeInfo> infos = treeService.treeDataForType(extId, type);
+        return ResponseEntity.ok(infos);
+    }
+
+    /**
+     * 查询树形
+     * @param extId 排除的ID
+     * @return
+     */
+    @ApiOperation(value = "查询树形")
+    @GetMapping("/treeData1")
+    public ResponseEntity<List<PsiMaterialTypeInfo>> treeData1(@RequestParam(required = false) String extId, @RequestParam(required = false) String type) throws Exception{
+        List<PsiMaterialTypeInfo> infos = treeService.treeDataForType1(extId, type);
+        return ResponseEntity.ok(infos);
+    }
+
+    /**
+     * 查询树形
+     * @param extId 排除的ID
+     * @return
+     */
+    @ApiOperation(value = "查询树形")
+    @GetMapping("/summaryTreeData")
+    public ResponseEntity<List<PsiMaterialTypeInfo>> summaryTreeData(@RequestParam(required = false) String extId, @RequestParam(required = false) String type) throws Exception{
+        List<PsiMaterialTypeInfo> infos = treeService.summaryTreeData(extId, type);
+        return ResponseEntity.ok(infos);
+    }
+
+    /**
+     * 查询树形
+     * @param extId 排除的ID
+     * @return
+     */
+    @ApiOperation(value = "查询树形")
+    @GetMapping("/treeData2")
+    public ResponseEntity<List<PsiMaterialTypeInfo>> treeData2(@RequestParam(required = false) String extId, @RequestParam(required = false) String type) throws Exception{
+        List<PsiMaterialTypeInfo> infos = treeService.treeDataForType2(extId, type);
+        return ResponseEntity.ok(infos);
+    }
+
+}

+ 86 - 0
jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/materialType/domain/PsiMaterialTypeInfo.java

@@ -0,0 +1,86 @@
+package com.jeeplus.psimanage.materialType.domain;
+
+import com.baomidou.mybatisplus.annotation.*;
+import com.jeeplus.core.domain.TreeEntity;
+import com.jeeplus.core.query.Query;
+import lombok.Data;
+
+import java.util.Date;
+
+/**
+ * 物资类型信息列表
+ * @author: 王强
+ * @create: 2022-11-25 08:59
+ **/
+@Data
+@TableName(value = "psi_management_type")
+public class PsiMaterialTypeInfo extends TreeEntity<PsiMaterialTypeInfo> {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 实体主键
+     */
+    @TableId
+    private String id;
+
+    /**
+     * 创建日期
+     */
+    @TableField(exist = false)
+    private Date createDate;
+
+    /**
+     * 创建人
+     */
+    @Query
+    @TableField(exist = false)
+    private String createBy;
+
+    /**
+     * 更新日期
+     */
+    @TableField(exist = false)
+    private Date updateDate;
+
+    /**
+     * 更新人
+     */
+    @TableField(exist = false)
+    private String updateBy;
+
+    /**
+     * 逻辑删除标记
+     */
+    @TableLogic
+    @TableField(fill = FieldFill.INSERT)
+    private Integer delFlag;
+
+    /**
+     * 层级
+     */
+    private String level;
+
+    /**
+     * 报销类型名称
+     */
+    @Query
+    private String name;
+
+    /**
+     * 序号
+     */
+    @Query
+    private Integer sort;
+
+    /**
+     * 父节点id
+     */
+    private String parentId;
+
+    private String parentIds;
+
+    @TableField(exist = false)
+    private Boolean disabled = false;
+
+}

+ 70 - 0
jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/materialType/mapper/PsiMaterialTypeMapper.java

@@ -0,0 +1,70 @@
+package com.jeeplus.psimanage.materialType.mapper;
+
+import com.baomidou.mybatisplus.core.conditions.Wrapper;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.core.toolkit.Constants;
+import com.jeeplus.core.domain.TreeMapper;
+import com.jeeplus.psimanage.materialType.domain.PsiMaterialTypeInfo;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+/**
+ * @author: 王强
+ * @create: 2022-11-25 09:02
+ **/
+public interface PsiMaterialTypeMapper extends BaseMapper<PsiMaterialTypeInfo>, TreeMapper<PsiMaterialTypeInfo> {
+
+    /**
+     * 查询数据集合
+     * @param queryWrapper
+     * @return
+     */
+    List<PsiMaterialTypeInfo> findList(@Param(Constants.WRAPPER) Wrapper<PsiMaterialTypeInfo> queryWrapper);
+
+
+    /**
+     * 根据id查询详情信息
+     * @param id
+     * @return
+     */
+    PsiMaterialTypeInfo getById(String id);
+    /**
+     * 根据name和parentId查询名称是否重复
+     * @param name
+     * @param parentId
+     * @return
+     */
+    Integer checkNameIsExist(@Param("name") String name, @Param("parentId") String parentId);
+
+    Integer getNo(@Param("parentId") String parentId);
+
+    Integer getLevel(@Param("parentId") String parentId);
+
+    List<String> getChildId(String id);
+
+    /**
+     * 获取所有业务类型的数据
+     * @return
+     */
+    List<PsiMaterialTypeInfo> getAllList();
+
+    /**
+     * 删除报销类型关联表对应信息
+     * @param id
+     */
+    void deleteReimbursementTypeOfficeInfo(String id);
+
+    /**
+     * 删除三级层级
+     * @param id
+     */
+    void deleteLevel3(String id);
+
+    /**
+     * 删除二级层级
+     * @param id
+     */
+    void deleteLevel2(String id);
+
+}

+ 106 - 0
jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/materialType/mapper/xml/PsiMaterialTypeMapper.xml

@@ -0,0 +1,106 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.jeeplus.psimanage.materialType.mapper.PsiMaterialTypeMapper">
+	<resultMap id="BaseResultMap" type="com.jeeplus.psimanage.materialType.domain.PsiMaterialTypeInfo">
+		<id property="id" column="id" jdbcType="VARCHAR"/>
+		<result property="createBy" column="create_by_id" jdbcType="VARCHAR"/>
+		<result property="createDate" column="create_time" jdbcType="TIMESTAMP"/>
+		<result property="updateBy" column="update_by_id" jdbcType="VARCHAR"/>
+		<result property="updateDate" column="update_time" jdbcType="TIMESTAMP"/>
+		<result property="delFlag" column="del_flag" jdbcType="INTEGER"/>
+
+		<result property="level" column="level" jdbcType="VARCHAR"/>
+		<result property="name" column="name" jdbcType="VARCHAR"/>
+		<result property="sort" column="sort" jdbcType="VARCHAR"/>
+		<result property="parentId" column="parent_id" jdbcType="VARCHAR"/>
+		<result property="parentIds" column="parent_ids" jdbcType="VARCHAR"/>
+
+	</resultMap>
+
+
+	<sql id="Base_Column_List">
+        a.id,
+        a.create_by_id as createBy,
+        a.create_time,
+        a.update_by_id,
+        a.update_time,
+        a.del_flag,
+        a.level,
+		a.name,
+		a.sort,
+		a.parent_id,
+		a.parent_ids
+    </sql>
+
+
+	<select id="findList" resultMap="BaseResultMap">
+		select
+		<include refid="Base_Column_List"></include>
+		from psi_management_type a
+		${ew.customSqlSegment}
+	</select>
+
+
+	<select id="getById" resultMap="BaseResultMap">
+		select
+		<include refid="Base_Column_List"></include>
+		from psi_management_type a
+		<where>
+			a.del_flag = 0 and a.id = #{id}
+		</where>
+	</select>
+
+	<select id="checkNameIsExist" resultType="java.lang.Integer">
+        SELECT
+			COUNT( 0 )
+		FROM
+			psi_management_type
+		WHERE
+			del_flag = 0
+			AND `name` = #{name}
+			AND parent_id = #{parentId}
+    </select>
+    <select id="getNo" resultType="java.lang.Integer">
+        SELECT
+			(MAX(`sort`) + 1) AS `sort`
+		FROM
+			psi_management_type
+		WHERE
+			del_flag = 0
+			AND parent_id = #{parentId}
+    </select>
+    <select id="getLevel" resultType="java.lang.Integer">
+        SELECT
+			(MAX(level) + 1) AS `level`
+		FROM
+			psi_management_type
+		WHERE
+			del_flag = 0
+			AND id = #{parentId}
+    </select>
+	<select id="getChildId" resultType="java.lang.String">
+		select id from psi_management_type where parent_id = #{id}
+	</select>
+	<select id="getAllList"
+			resultType="com.jeeplus.psimanage.materialType.domain.PsiMaterialTypeInfo">
+		select * from psi_management_type where  del_flag = '0' order by sort asc
+	</select>
+
+	<delete id="deleteReimbursementTypeOfficeInfo">
+		delete from psi_management_type where reimbursement_type_id = #{id}
+	</delete>
+	<delete id="deleteLevel3">
+		UPDATE psi_management_type set del_flag = 1 WHERE id in (
+		SELECT a.id FROM
+		( SELECT id FROM psi_management_type WHERE parent_id in
+		(SELECT id FROM psi_management_type WHERE parent_id = #{id}
+		)) a)
+	</delete>
+	<delete id="deleteLevel2">
+		UPDATE psi_management_type set del_flag = 1 WHERE id in (
+		SELECT a.id FROM
+		(SELECT id FROM psi_management_type WHERE parent_id = #{id}
+		) a)
+	</delete>
+
+</mapper>

+ 178 - 0
jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/materialType/service/PsiMaterialTypeForTreeDataService.java

@@ -0,0 +1,178 @@
+package com.jeeplus.psimanage.materialType.service;
+
+import cn.hutool.core.util.StrUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.jeeplus.core.service.TreeService;
+import com.jeeplus.core.service.dto.TreeDTO;
+import com.jeeplus.psimanage.materialType.domain.PsiMaterialTypeInfo;
+import com.jeeplus.psimanage.materialType.mapper.PsiMaterialTypeMapper;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author: 王强
+ * @create: 2022-11-25 09:01
+ **/
+@Service
+public class PsiMaterialTypeForTreeDataService extends TreeService<PsiMaterialTypeMapper, PsiMaterialTypeInfo> {
+
+    @Resource
+    private PsiMaterialTypeMapper typeMapper;
+
+    /**
+     * 获取JSON树形数据。
+     *
+     * @param extId 排除的ID
+     * @param type 禁选类型
+     * @return
+     */
+    public List<PsiMaterialTypeInfo> treeDataForType(String extId, String type) throws Exception{
+        //获取所有的业务类型为1的数据
+//        List<CwReimbursementTypeInfo> allList = typeMapper.getAllList("1");
+        List<PsiMaterialTypeInfo> allList = typeMapper.findList (new LambdaQueryWrapper<>( (Class <PsiMaterialTypeInfo>) entityClass ).eq(PsiMaterialTypeInfo::getDelFlag, 0).orderByAsc ( PsiMaterialTypeInfo::getSort ));
+        PsiMaterialTypeInfo root = entityClass.getConstructor ( ).newInstance ( );
+        root.setId ( TreeDTO.getRootId () );
+        List <PsiMaterialTypeInfo> rootTree = this.formatListToTreeForType ( root, allList, extId, type );
+        return rootTree;
+    }
+
+    /**
+     * 获取JSON树形数据。
+     *
+     * @param extId 排除的ID
+     * @param type 禁选类型
+     * @return
+     */
+    public List<PsiMaterialTypeInfo> treeDataForType1(String extId, String type) throws Exception{
+        //获取所有的业务类型为1的数据
+        List<PsiMaterialTypeInfo> allList = typeMapper.getAllList();
+//        List<CwReimbursementTypeInfo> allList = super.list (new LambdaQueryWrapper<>( (Class <CwReimbursementTypeInfo>) entityClass ).orderByAsc ( CwReimbursementTypeInfo::getSort ));
+        PsiMaterialTypeInfo root = entityClass.getConstructor ( ).newInstance ( );
+        root.setId ( TreeDTO.getRootId () );
+        List <PsiMaterialTypeInfo> rootTree = this.formatListToTreeForType ( root, allList, extId, type );
+        return rootTree;
+    }
+
+    /**
+     * 获取JSON树形数据。
+     *
+     * @param extId 排除的ID
+     * @param type 禁选类型
+     * @return
+     */
+    public List<PsiMaterialTypeInfo> summaryTreeData(String extId, String type) throws Exception{
+        //获取所有的业务类型为1的数据
+        List<PsiMaterialTypeInfo> allList = typeMapper.getAllList();
+        PsiMaterialTypeInfo root = entityClass.getConstructor ( ).newInstance ( );
+        root.setId ( TreeDTO.getRootId () );
+        List <PsiMaterialTypeInfo> rootTree = this.formatListToTreeForType ( root, allList, extId, type );
+        return rootTree;
+    }
+
+    /**
+     * 获取JSON树形数据。
+     *
+     * @param extId 排除的ID
+     * @param type 禁选类型
+     * @return
+     */
+    public List<PsiMaterialTypeInfo> treeDataForType2(String extId, String type) throws Exception{
+        //获取所有的业务类型为1的数据
+        List<PsiMaterialTypeInfo> allList = typeMapper.getAllList();
+//        List<CwReimbursementTypeInfo> allList = super.list (new LambdaQueryWrapper<>( (Class <CwReimbursementTypeInfo>) entityClass ).orderByAsc ( CwReimbursementTypeInfo::getSort ));
+        PsiMaterialTypeInfo root = entityClass.getConstructor ( ).newInstance ( );
+        root.setId ( TreeDTO.getRootId () );
+        List <PsiMaterialTypeInfo> rootTree = this.formatListToTreeForType ( root, allList, extId, type );
+        return rootTree;
+    }
+
+    /**
+     * 以root为根节点, 将allList从线性列表转为树形列表
+     *
+     * @param root    根节点, 为空抛出空指针异常
+     * @param allList 所有需要参与构造为树的列表
+     * @param extId   需要排除在树之外的节点(子节点一并被排除)
+     * @return java.util.List<T>
+     * @Author 滕鑫源
+     * @Date 2020/10/23 17:04
+     **/
+    public List <PsiMaterialTypeInfo> formatListToTreeForType (PsiMaterialTypeInfo root, List <PsiMaterialTypeInfo> allList, String extId, String type) {
+        String rootId = root.getId ( );
+        // 最终的树形态
+        List <PsiMaterialTypeInfo> trees = Lists.newArrayList ( );
+
+        // 把需要构造树的所有列表, 根据以父id作为key, 整理为列表
+        Map<String, List <PsiMaterialTypeInfo>> treeMap = Maps.newHashMap ( );
+        for (PsiMaterialTypeInfo entity : allList) {
+            List <PsiMaterialTypeInfo> entities = treeMap.get ( entity.getParentId ( ) );
+            if ( entities == null ) {
+                entities = Lists.newLinkedList ( );
+            }
+
+            // 剔除排除项, 构造treeMap, 转递归为线性操作
+            if ( StrUtil.isBlank ( extId ) || (!extId.equals ( entity.getId ( ) ) && entity.getParentIds ( ).indexOf ( "," + extId + "," ) == -1) ) {
+                entities.add ( entity );
+                treeMap.put ( entity.getParentId ( ), entities );
+            }
+
+            if (StringUtils.isNotEmpty(type)) {
+                //禁选类型设置disable值为true
+                if ("last".equals(type)) {
+                    allList.stream().forEach(item -> {
+                        if (StringUtils.isNotBlank(item.getParentId())) {
+                            if (item.getParentId().equals(entity.getId())) {
+                                entity.setDisabled(true);
+                            }
+                        }
+                    });
+                } else {
+                    if (type.contains(entity.getLevel())) {
+                        entity.setDisabled(true);
+                    }
+                }
+            }
+        }
+
+        // 没有给定的子树, 返回空树
+        if ( treeMap.get ( rootId ) == null || treeMap.get ( rootId ).isEmpty ( ) ) {
+            return trees;
+        }
+
+        // 开始递归格式化
+        List <PsiMaterialTypeInfo> children = treeMap.get ( rootId );
+        for (PsiMaterialTypeInfo parent : children) {
+            formatFillChildren ( parent, treeMap );
+            trees.add ( parent );
+        }
+        if ( StrUtil.equals ( rootId, TreeDTO.getRootId () ) ) {
+            return children;
+        } else {
+            root.setChildren ( trees );
+            return Lists.newArrayList ( root );
+        }
+    }
+    /**
+     * 从treeMap中取出子节点填入parent, 并递归此操作
+     *
+     * @param parent
+     * @param treeMap
+     * @return void
+     * @Author 滕鑫源
+     * @Date 2020/9/30 16:33
+     **/
+    private void formatFillChildren(PsiMaterialTypeInfo parent, Map <String, List <PsiMaterialTypeInfo>> treeMap) {
+        List <PsiMaterialTypeInfo> children = treeMap.get ( parent.getId ( ) );
+        parent.setChildren ( children );
+        if ( children != null && !children.isEmpty ( ) ) {
+            for (PsiMaterialTypeInfo child : children) {
+                formatFillChildren ( child, treeMap );
+            }
+        }
+    }
+}

+ 303 - 0
jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/materialType/service/PsiMaterialTypeService.java

@@ -0,0 +1,303 @@
+package com.jeeplus.psimanage.materialType.service;
+
+import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.extra.spring.SpringUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.jeeplus.common.TokenProvider;
+import com.jeeplus.core.domain.BaseEntity;
+import com.jeeplus.psimanage.materialType.domain.PsiMaterialTypeInfo;
+import com.jeeplus.psimanage.materialType.mapper.PsiMaterialTypeMapper;
+import com.jeeplus.sys.feign.IUserApi;
+import com.jeeplus.sys.service.dto.UserDTO;
+import com.jeeplus.utils.StringUtils;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.UUID;
+import java.util.stream.Collectors;
+
+/**
+ * @author: 王强
+ * @create: 2022-11-25 09:13
+ **/
+@Service
+public class PsiMaterialTypeService extends ServiceImpl<PsiMaterialTypeMapper, PsiMaterialTypeInfo> {
+
+    @Resource
+    private PsiMaterialTypeMapper mapper;
+
+    public List<PsiMaterialTypeInfo> list(PsiMaterialTypeInfo info) {
+        LambdaQueryWrapper<PsiMaterialTypeInfo> wrapper = new LambdaQueryWrapper<>();
+        if(StringUtils.isNotBlank(info.getName())){
+            //根据type模糊查询
+            List<PsiMaterialTypeInfo> materialTypeInfoList = this.list(new QueryWrapper<PsiMaterialTypeInfo>().lambda()
+                    .like(StringUtils.isNotBlank(info.getName()), PsiMaterialTypeInfo::getName, info.getName())
+            );
+            List<String> collect = materialTypeInfoList.stream().map(PsiMaterialTypeInfo::getId).collect(Collectors.toList());
+            //materialTypeInfoList的父级id全部获取
+            List<String> cupIdList = materialTypeInfoList.stream().map(PsiMaterialTypeInfo::getParentId).collect(Collectors.toList()).stream().distinct().collect(Collectors.toList());
+            //获取materialTypeInfoList的父级id的父级id
+            List<String> cupIdPList = new ArrayList<>();
+            if (CollectionUtil.isNotEmpty(cupIdList)) {
+                cupIdList.stream().forEach(item -> {
+                    PsiMaterialTypeInfo byId = this.getById(item);
+                    if (ObjectUtil.isNotEmpty(byId)) {
+                        if (StringUtils.isNotBlank(byId.getParentId())) {
+                            cupIdPList.add(byId.getParentId());
+                        }
+                    }
+                });
+            }
+            //获取collect的下级id
+            List<String> childIdList = new ArrayList<>();
+            collect.stream().forEach(item -> {
+                List<PsiMaterialTypeInfo> list = this.list(new LambdaQueryWrapper<PsiMaterialTypeInfo>().eq(PsiMaterialTypeInfo::getParentId, item));
+                if (CollectionUtil.isNotEmpty(list)) {
+                    List<String> collect1 = list.stream().map(PsiMaterialTypeInfo::getId).collect(Collectors.toList()).stream().distinct().collect(Collectors.toList());
+                    if (CollectionUtil.isNotEmpty(collect1)) {
+                        childIdList.addAll(collect1);
+                        //获取collect的下级的下级的id
+                        collect1.stream().forEach(i -> {
+                            List<PsiMaterialTypeInfo> l = this.list(new LambdaQueryWrapper<PsiMaterialTypeInfo>().eq(PsiMaterialTypeInfo::getParentId, i));
+                            if (CollectionUtil.isNotEmpty(l)) {
+                                List<String> collect2 = l.stream().map(PsiMaterialTypeInfo::getId).collect(Collectors.toList()).stream().distinct().collect(Collectors.toList());
+                                if (CollectionUtil.isNotEmpty(collect2)) {
+                                    childIdList.addAll(collect2);
+                                }
+                            }
+                        });
+                    }
+                }
+            });
+            //将获取到的这几个id集合融合到一起并去重,然后根据id查询,即可得到结果
+            collect.addAll(cupIdList);
+            collect.addAll(cupIdPList);
+            collect.addAll(childIdList);
+
+            List<String> idList = collect.stream().distinct().collect(Collectors.toList());
+            if(CollectionUtil.isNotEmpty(idList)){
+                wrapper.in(PsiMaterialTypeInfo::getId,idList);
+            }
+        }
+//        if (info.getSort() != null) {
+//            wrapper.like(MaterialTypeInfo::getSort, info.getSort());
+//        }
+//        wrapper.eq(CwReimbursementTypeInfo::getBusinessType, "1");
+
+        wrapper.eq(BaseEntity::getDelFlag, 0);
+        wrapper.orderByAsc(PsiMaterialTypeInfo::getSort);
+        return mapper.findList(wrapper);
+    }
+
+
+    /**
+     * 根据id查询项目详情
+     * @param id
+     * @return
+     */
+    public PsiMaterialTypeInfo getById(String id) {
+        PsiMaterialTypeInfo info = mapper.getById(id);
+        return info;
+    }
+
+    public List<PsiMaterialTypeInfo> bxList(PsiMaterialTypeInfo info) {
+        LambdaQueryWrapper<PsiMaterialTypeInfo> wrapper = new LambdaQueryWrapper<>();
+        if (StringUtils.isNotEmpty(info.getName())) {
+            wrapper.like(PsiMaterialTypeInfo::getName, info.getName());
+        }
+        if (info.getSort() != null) {
+            wrapper.like(PsiMaterialTypeInfo::getSort, info.getSort());
+        }
+
+        wrapper.eq(BaseEntity::getDelFlag, 0);
+        wrapper.orderByAsc(PsiMaterialTypeInfo::getSort);
+        return mapper.selectList(wrapper);
+    }
+
+    public List<PsiMaterialTypeInfo> cgList(PsiMaterialTypeInfo info) {
+        LambdaQueryWrapper<PsiMaterialTypeInfo> wrapper = new LambdaQueryWrapper<>();
+        if(StringUtils.isNotBlank(info.getName())){
+            //根据type模糊查询
+            List<PsiMaterialTypeInfo> materialTypeInfoList = this.list(new QueryWrapper<PsiMaterialTypeInfo>().lambda()
+                    .like(StringUtils.isNotBlank(info.getName()), PsiMaterialTypeInfo::getName, info.getName())
+            );
+            List<String> collect = materialTypeInfoList.stream().map(PsiMaterialTypeInfo::getId).collect(Collectors.toList());
+            //materialTypeInfoList的父级id全部获取
+            List<String> cupIdList = materialTypeInfoList.stream().map(PsiMaterialTypeInfo::getParentId).collect(Collectors.toList()).stream().distinct().collect(Collectors.toList());
+            //获取materialTypeInfoList的父级id的父级id
+            List<String> cupIdPList = new ArrayList<>();
+            if (CollectionUtil.isNotEmpty(cupIdList)) {
+                cupIdList.stream().forEach(item -> {
+                    PsiMaterialTypeInfo byId = this.getById(item);
+                    if (ObjectUtil.isNotEmpty(byId)) {
+                        if (StringUtils.isNotBlank(byId.getParentId())) {
+                            cupIdPList.add(byId.getParentId());
+                        }
+                    }
+                });
+            }
+            //获取collect的下级id
+            List<String> childIdList = new ArrayList<>();
+            collect.stream().forEach(item -> {
+                List<PsiMaterialTypeInfo> list = this.list(new LambdaQueryWrapper<PsiMaterialTypeInfo>().eq(PsiMaterialTypeInfo::getParentId, item));
+                if (CollectionUtil.isNotEmpty(list)) {
+                    List<String> collect1 = list.stream().map(PsiMaterialTypeInfo::getId).collect(Collectors.toList()).stream().distinct().collect(Collectors.toList());
+                    if (CollectionUtil.isNotEmpty(collect1)) {
+                        childIdList.addAll(collect1);
+                        //获取collect的下级的下级的id
+                        collect1.stream().forEach(i -> {
+                            List<PsiMaterialTypeInfo> l = this.list(new LambdaQueryWrapper<PsiMaterialTypeInfo>().eq(PsiMaterialTypeInfo::getParentId, i));
+                            if (CollectionUtil.isNotEmpty(l)) {
+                                List<String> collect2 = l.stream().map(PsiMaterialTypeInfo::getId).collect(Collectors.toList()).stream().distinct().collect(Collectors.toList());
+                                if (CollectionUtil.isNotEmpty(collect2)) {
+                                    childIdList.addAll(collect2);
+                                }
+                            }
+                        });
+                    }
+                }
+            });
+            //将获取到的这几个id集合融合到一起并去重,然后根据id查询,即可得到结果
+            collect.addAll(cupIdList);
+            collect.addAll(cupIdPList);
+            collect.addAll(childIdList);
+
+            List<String> idList = collect.stream().distinct().collect(Collectors.toList());
+            if(CollectionUtil.isNotEmpty(idList)){
+                wrapper.in(PsiMaterialTypeInfo::getId,idList);
+            }
+        }
+
+        wrapper.eq(BaseEntity::getDelFlag, 0);
+        wrapper.orderByAsc(PsiMaterialTypeInfo::getSort);
+        return mapper.selectList(wrapper);
+    }
+
+    public String saveM(PsiMaterialTypeInfo info) {
+        // parentId未传值,则表示一级菜单
+        if(StringUtils.isEmpty(info.getParentId())) {
+            info.setParentId("0");
+        }
+        // 保存数据
+        if (StringUtils.isNotEmpty(info.getId())) {
+            return update(info);
+        }
+        return add(info);
+    }
+
+    /**
+     * 新增
+     * @param info
+     * @return
+     */
+    public String add(PsiMaterialTypeInfo info) {
+
+        // 判断名称是否已存在
+        Integer isExist = mapper.checkNameIsExist(info.getName(), info.getParentId());
+        if (isExist > 0) {
+            return "false";
+        }
+        // 获取当前登录人信息
+        UserDTO userDto = SpringUtil.getBean ( IUserApi.class ).getByToken(TokenProvider.getCurrentToken ( ));
+//        UserDTO userDto = UserUtils.getCurrentUserDTO();
+        // 生成id值
+        String id = UUID.randomUUID().toString().replace("-", "");
+        info.setId(id);
+        info.setCreateBy(userDto.getId());
+        info.setCreateDate(new Date());
+        info.setUpdateBy(userDto.getId());
+        info.setUpdateDate(new Date());
+        info.setDelFlag(0);
+        // 生成序号/层级
+        getNo(info);
+        mapper.insert(info);
+        return "操作完成";
+    }
+
+    /**
+     * 修改
+     * @param info
+     * @return
+     */
+    public String update(PsiMaterialTypeInfo info) {
+        UserDTO userDto = SpringUtil.getBean ( IUserApi.class ).getByToken(TokenProvider.getCurrentToken ( ));
+        // 获取当前登录人信息
+//        UserDTO userDto = UserUtils.getCurrentUserDTO();
+        info.setUpdateBy(userDto.getId());
+        info.setUpdateDate(new Date());
+        mapper.updateById(info);
+        return "操作完成";
+    }
+
+    /**
+     * 生成序号/层级
+     * @param info
+     * @return
+     */
+    public PsiMaterialTypeInfo getNo(PsiMaterialTypeInfo info) {
+        PsiMaterialTypeInfo parentInfo = null;
+        if (!"0".equals(info.getParentId())) {
+            //根据parentId查询父节点信息
+            LambdaQueryWrapper<PsiMaterialTypeInfo> wrapper = new LambdaQueryWrapper<>();
+            wrapper.eq(BaseEntity::getDelFlag, 0);
+            wrapper.eq(BaseEntity::getId, info.getParentId());
+            parentInfo = mapper.selectOne(wrapper);
+        }
+        //查询序号
+        Integer no = mapper.getNo(info.getParentId());
+        // 该层级下有数据,正常返回序号值
+        if (no != null) {
+            info.setSort(no);
+        } else {
+            // 父节点存在,根据父节点序号生成;不存在,则表示无上级层级,从1开始
+            if (parentInfo != null) {
+                String s = parentInfo.getSort() + "01";
+                info.setSort(Integer.parseInt(s));
+            } else {
+                info.setSort(1);
+            }
+        }
+        // 生成层级
+        //查询层级
+        Integer level = mapper.getLevel(info.getParentId());
+        if (level != null) {
+            info.setLevel(level.toString());
+        } else {
+            // 父节点存在,根据父节点level生成,不存在,则表示无上级层级,从1开始
+            if (parentInfo != null) {
+                Integer i = Integer.parseInt(parentInfo.getLevel())+1;
+                info.setLevel(i.toString());
+            } else {
+                info.setLevel("1");
+            }
+        }
+        return info;
+    }
+
+    public String remove(String id) {
+        //如果层级是一级或者是二级,则应该将一级下的所有信息删除或二级下的所有信息删除,反之为三级则直接删除
+        PsiMaterialTypeInfo typeInfo = mapper.getById(id);
+        if (typeInfo.getLevel().equals("1")){
+            //三个层级的情况
+            mapper.deleteLevel3(id);
+            //删除二级的信息
+            mapper.deleteLevel2(id);
+            //删除一级的信息
+            mapper.deleteById(id);
+        } else if (typeInfo.getLevel().equals("2")) {
+            //两个层级的情况
+            mapper.deleteLevel2(id);
+            //删除二级的信息
+            mapper.deleteById(id);
+        } else if (typeInfo.getLevel().equals("3")) {
+            mapper.deleteById(id);
+        }
+        return "操作成功";
+    }
+}

+ 21 - 0
jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/materialType/service/dto/PsiMaterialTypeDto.java

@@ -0,0 +1,21 @@
+package com.jeeplus.psimanage.materialType.service.dto;
+
+import com.jeeplus.core.domain.BaseEntity;
+import lombok.Data;
+
+/**
+ * @author: 王强
+ * @create: 2022-11-25 09:04
+ **/
+@Data
+public class PsiMaterialTypeDto extends BaseEntity {
+
+    private String level;
+
+    private String name;
+
+    private Integer sort;
+
+    private String parentId;
+
+}

+ 177 - 0
jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/oss/controller/PsiOssController.java

@@ -0,0 +1,177 @@
+package com.jeeplus.psimanage.oss.controller;
+
+import cn.hutool.extra.spring.SpringUtil;
+import com.aliyuncs.DefaultAcsClient;
+import com.aliyuncs.auth.sts.AssumeRoleRequest;
+import com.aliyuncs.auth.sts.AssumeRoleResponse;
+import com.aliyuncs.exceptions.ClientException;
+import com.aliyuncs.http.MethodType;
+import com.aliyuncs.http.ProtocolType;
+import com.aliyuncs.profile.DefaultProfile;
+import com.aliyuncs.profile.IClientProfile;
+import com.jeeplus.psimanage.oss.service.PsiOSSClientService;
+import com.jeeplus.sys.feign.IUserApi;
+//import com.jeeplus.sys.utils.FileKit;
+//import com.jeeplus.sys.utils.FileUtils;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.util.HashMap;
+import java.util.Map;
+
+@Slf4j
+@Api(tags ="oss")
+@RestController
+@RequestMapping(value = "/psi/oss")
+public class PsiOssController {
+
+    private static final String DIRECTORY = "/attachment-file";
+
+    private static final String ALIYUNURL = "http://oss.gangwaninfo.com";
+
+    private static final String ALIYUNDOWNLOADURL = "";
+
+    @Value("${config.accessory.aliyun.bucketName}")
+    private String bucketName;
+
+    @Value("${config.accessory.aliyun.endpoint}")
+    private String endpoint;
+
+    @Autowired
+    private PsiOSSClientService psiOssClientService;
+
+    /**
+     * 文件上传
+     * @param storeAs
+     * @param file
+     * @return
+     * @throws Exception
+     */
+    @ApiOperation(value = "文件上传")
+    @PostMapping("/upload")
+    public ResponseEntity<String> upload(@RequestParam String storeAs, @RequestParam("file") MultipartFile file) throws Exception {
+        //取得上传文件
+        if (file != null && !file.isEmpty()) {
+            // 文件保存路径
+            String realPath =DIRECTORY.replaceFirst("/","")+"/"+storeAs+ psiOssClientService.datePath()+"/"+ System.currentTimeMillis();
+            //文件原名称
+            String newName = file.getOriginalFilename();
+            psiOssClientService.uploadFile2OSS(file.getInputStream(),realPath,newName);
+            String filepath = ALIYUNURL + "/" + realPath + newName;
+            return ResponseEntity.ok (filepath);
+        }
+        return ResponseEntity.ok(null);
+    }
+
+    @PostMapping("/getAccess")
+    @ApiOperation(value = "文件上传(前端调用)")
+    public Map<Object, Object> getAccess() {
+        // 只有 RAM用户(子账号)才能调用 AssumeRole 接口
+        // 阿里云主账号的AccessKeys不能用于发起AssumeRole请求
+        // 请首先在RAM控制台创建一个RAM用户,并为这个用户创建AccessKeys
+        String accessKeyId =  "LTAI5tBBnQdpZapU28Ds89fb";
+        String accessKeySecret = "A37CuoALjoxCjPolzRm3ct5o8UHILF";
+        // RoleArn 需要在 RAM 控制台上获取
+        String roleArn = "acs:ram::1132186699724035:role/yf";
+        long durationSeconds = Long.parseLong("3600");
+        String policy = "{\n" +
+                "  \"Version\": \"1\",\n" +
+                "  \"Statement\": [\n" +
+                "    {\n" +
+                "      \"Effect\": \"Allow\",\n" +
+                "      \"Action\": [\n" +
+                "        \"oss:*\"\n" +
+                "      ],\n" +
+                "      \"Resource\": [\n" +
+                "        \"acs:oss:*:*:*\"\n" +
+                "      ],\n" +
+                "      \"Condition\": {}\n" +
+                "    }\n" +
+                "  ]\n" +
+                "}";
+        // RoleSessionName 是临时Token的会话名称,自己指定用于标识你的用户,主要用于审计,或者用于区分Token颁发给谁
+        // 但是注意RoleSessionName的长度和规则,不要有空格,只能有'-' '_' 字母和数字等字符
+        // 具体规则请参考API文档中的格式要求
+        String roleSessionName = "yf";
+        // 此处必须为 HTTPS
+        ProtocolType protocolType = ProtocolType.HTTPS;
+        try {
+            final AssumeRoleResponse stsResponse = assumeRole(accessKeyId, accessKeySecret, roleArn, roleSessionName,
+                    policy, protocolType, durationSeconds);
+
+            Map<Object, Object> respMap = new HashMap<Object, Object>();
+            respMap.put("status", "200");
+            respMap.put("AccessKeyId", stsResponse.getCredentials().getAccessKeyId());
+            respMap.put("AccessKeySecret", stsResponse.getCredentials().getAccessKeySecret());
+            respMap.put("SecurityToken", stsResponse.getCredentials().getSecurityToken());
+            respMap.put("Expiration", stsResponse.getCredentials().getExpiration());
+            respMap.put("AliyunUrl",ALIYUNDOWNLOADURL);
+            respMap.put("Bucket", bucketName);
+            respMap.put("Endpoint", endpoint);
+            return respMap;
+        } catch (ClientException e) {
+            log.error("调用ali获取临时token报错,错误信息:" + e.getMessage());
+            Map<Object, Object> respMap = new HashMap<Object, Object>();
+            respMap.put("status", e.getErrCode());
+            respMap.put("AccessKeyId", "");
+            respMap.put("AccessKeySecret", "");
+            respMap.put("SecurityToken", "");
+            respMap.put("Expiration", "");
+            respMap.put("AliyunUrl", "");
+            respMap.put("Bucket", "");
+            respMap.put("Endpoint", "");
+            return respMap;
+        }
+    }
+
+    public static final String REGION_CN_HANGZHOU = "cn-hangzhou";
+    public static final String STS_API_VERSION = "2015-04-01";
+    protected AssumeRoleResponse assumeRole(String accessKeyId, String accessKeySecret, String roleArn,
+                                            String roleSessionName, String policy, ProtocolType protocolType, long durationSeconds) throws ClientException
+    {
+        try {
+            // 创建一个 Aliyun Acs Client, 用于发起 OpenAPI 请求
+            IClientProfile profile = DefaultProfile.getProfile(REGION_CN_HANGZHOU, accessKeyId, accessKeySecret);
+            DefaultAcsClient client = new DefaultAcsClient(profile);
+            // 创建一个 AssumeRoleRequest 并设置请求参数
+            final AssumeRoleRequest request = new AssumeRoleRequest();
+            request.setVersion(STS_API_VERSION);
+            request.setMethod(MethodType.POST);
+            request.setProtocol(protocolType);
+            request.setRoleArn(roleArn);
+            request.setRoleSessionName(roleSessionName);
+            request.setPolicy(policy);
+            request.setDurationSeconds(durationSeconds);
+            // 发起请求,并得到response
+            final AssumeRoleResponse response = client.getAcsResponse(request);
+            return response;
+        } catch (ClientException e) {
+            throw e;
+        }
+    }
+
+    /**
+     * 根据url删除文件
+     * @param url
+     * @return
+     */
+    @ApiOperation("根据url删除文件")
+    @GetMapping("/deleteByUrl")
+    public ResponseEntity delFileByUrl(@RequestParam String url) {
+        String id = SpringUtil.getBean ( IUserApi.class ).getFileDir(url);
+//        String id = FileKit.getFileDir(url);
+        boolean b = SpringUtil.getBean(IUserApi.class).delFile(id);
+        if(b){
+            return ResponseEntity.ok ("删除文件成功");
+        }else{
+            return ResponseEntity.badRequest().body ("删除文件失败");
+        }
+
+    }
+}

+ 802 - 0
jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/oss/controller/PsiOssFileController.java

@@ -0,0 +1,802 @@
+package com.jeeplus.psimanage.oss.controller;
+
+import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.extra.spring.SpringUtil;
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.TypeReference;
+import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
+import com.jeeplus.aop.demo.annotation.DemoMode;
+import com.jeeplus.common.TokenProvider;
+import com.jeeplus.logging.annotation.ApiLog;
+import com.jeeplus.psimanage.oss.domain.PsiWorkAttachment;
+import com.jeeplus.psimanage.oss.service.PsiOSSClientService;
+import com.jeeplus.psimanage.oss.service.PsiOssService;
+import com.jeeplus.psimanage.oss.service.dto.*;
+import com.jeeplus.psimanage.oss.utils.FileUtil;
+import com.jeeplus.psimanage.serialNumTpl.service.PsiSerialnumTplService;
+import com.jeeplus.sys.domain.WorkAttachmentInfo;
+import com.jeeplus.sys.feign.IOfficeApi;
+//import com.jeeplus.sys.service.OfficeService;
+import com.jeeplus.sys.feign.IUserApi;
+//import com.jeeplus.sys.service.UserService;
+import com.jeeplus.sys.service.dto.CertDTO;
+import com.jeeplus.sys.service.dto.OfficeDTO;
+import com.jeeplus.sys.service.dto.UserDTO;
+import com.jeeplus.sys.service.dto.WorkAttachmentInfoDTO;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.*;
+
+@Slf4j
+@Api(tags ="oss")
+@RestController
+@RequestMapping(value = "/psi/file")
+public class PsiOssFileController {
+
+    @Value("${config.accessory.aliyun.aliyunUrl}")
+    private String aliyunUrl;
+
+    @Value("${config.accessory.aliyun.aliyunDownloadUrl}")
+    private String aliyunDownloadUrl;
+
+    @Resource
+    private PsiOssService psiOssService;
+
+    @Resource
+    private PsiSerialnumTplService psiSerialnumTplService;
+
+    @Autowired
+    private PsiOSSClientService psiOssClientService;
+
+//    @Autowired
+//    private UserService userService;
+
+//    @Autowired
+//    private OfficeService officeService;
+
+    @ApiOperation(value = "保存数据")
+    @PostMapping("/saveMsg")
+    public void saveMsg(@RequestBody List<PsiWorkAttachment> psiWorkAttachments) {
+        String currentToken = TokenProvider.getCurrentToken();
+        psiOssService.saveMsg(psiWorkAttachments,currentToken);
+    }
+
+    @GetMapping("/deleteMsgByFileName")
+    @ApiOperation(value = "删除数据")
+    public void deleteMsgByFileName(@RequestParam String url) {
+        psiOssService.deleteMsgByFileName(url);
+    }
+
+    @GetMapping("/deleteMsgById")
+    @ApiOperation(value = "根据id删除数据")
+    public void deleteMsgById(@RequestParam String id) {
+        psiOssService.deleteMsgById(id);
+    }
+
+    @GetMapping("/getTemporaryUrl")
+    @ApiOperation(value = "根据url获取临时文件地址")
+    public ResponseEntity<String> getTemporaryUrl(@RequestParam String url) {
+        String temporaryLookUrl = psiOssService.getFileTemporaryLookUrl(aliyunUrl + url);
+        return ResponseEntity.ok(temporaryLookUrl);
+    }
+
+    @GetMapping("/getThumbnailTemporaryLookUrl")
+    @ApiOperation(value = "根据url获取临时文件缩略图地址")
+    public ResponseEntity<String> getThumbnailTemporaryLookUrl(@RequestParam String url) {
+        String temporaryLookUrl = psiOssService.getThumbnailTemporaryLookUrl(aliyunUrl + url);
+        return ResponseEntity.ok(temporaryLookUrl);
+    }
+
+    @GetMapping("/getFileTemporaryLookUrlWithWatermark")
+    @ApiOperation(value = "根据url获取临时文件带水印、虚化原图地址")
+    public ResponseEntity<String> getFileTemporaryLookUrlWithWatermark(@RequestParam String url) {
+        String temporaryLookUrl = psiOssService.getFileTemporaryLookUrlWithWatermark(aliyunUrl + url);
+        return ResponseEntity.ok(temporaryLookUrl);
+    }
+
+    @GetMapping("/getThumbnailTemporaryWithWatermarkDimLookUrl")
+    @ApiOperation(value = "根据url获取临时文件带水印、虚化、缩略图地址")
+    public ResponseEntity<String> getThumbnailTemporaryWithWatermarkDimLookUrl(@RequestParam String url) {
+        String temporaryLookUrl = psiOssService.getThumbnailTemporaryWithWatermarkDimLookUrl(aliyunUrl + url);
+        return ResponseEntity.ok(temporaryLookUrl);
+    }
+
+    @GetMapping("/findFileList")
+    @ApiOperation(value = "查询数据")
+    public ResponseEntity<List<AttachmentDTO>> findFileList(@RequestParam("attachmentId") String attachmentId) {
+        List<AttachmentDTO> list = psiOssService.findFileList(attachmentId);
+        return ResponseEntity.ok(list);
+    }
+
+    /**
+     * 下载附件
+     */
+    @GetMapping("/downLoadAttach")
+    @ApiOperation(value = "下载附件")
+    public String downLoadAttach(@RequestParam String file, HttpServletResponse response, HttpServletRequest request) throws IOException {
+        file = "http://oss.gangwaninfo.com" + file;
+        file = file.replace("amp;", "");
+        String fileName = file.substring(file.lastIndexOf("/") + 1, file.length());
+        String cons = "";
+        if (file.contains(aliyunUrl)) {
+            cons = aliyunUrl;
+        } else if (file.contains("http://gangwan-app.oss-cn-hangzhou.aliyuncs.com")) {
+            cons = "http://gangwan-app.oss-cn-hangzhou.aliyuncs.com";
+        } else {
+            cons = aliyunDownloadUrl;
+        }
+        String key = file.split(cons + "/")[1];
+        log.info("-----------------------------------------");
+        log.info("fileName=" + fileName);
+        log.info("key=" + key);
+        log.info("-----------------------------------------");
+        psiOssService.downByStream(key, fileName, response, request.getHeader("USER-AGENT"));
+        return null;
+    }
+
+    @GetMapping("/getFileSizeByUrl")
+    @ApiOperation(value = "根据文件路径获取文件信息")
+    public ResponseEntity<FileDetailDTO> getFileSizeByUrl(@RequestParam("url") String url) {
+        FileDetailDTO fileDetailDTO = psiOssService.getFileSizeByUrl(url);
+        return ResponseEntity.ok(fileDetailDTO);
+    }
+
+    @GetMapping("/getSFZSizeByUrl")
+    @ApiOperation(value = "根据文件路径获取身份证图片信息")
+    public ResponseEntity<FileDetailDTO> getSFZSizeByUrl(@RequestParam("url") String url) {
+        FileDetailDTO fileDetailDTO = psiOssService.getSFZSizeByUrl(url);
+        return ResponseEntity.ok(fileDetailDTO);
+    }
+
+    /**
+     * 上传文件
+     * @return
+     * @throws IOException
+     */
+    @ApiOperation("上传文件")
+    @PostMapping("webUpload/upload")
+    public ResponseEntity<FileUrlDto> webUpload(MultipartFile file) throws IOException {
+        String dir = "note";
+        FileUrlDto dto = psiOssService.webUpload(file,dir);
+        return ResponseEntity.ok(dto);
+    }
+
+    /**
+     * 上传文件
+     * @return
+     * @throws IOException
+     */
+    @ApiOperation("上传文件")
+    @PostMapping("webUpload/fileUpload")
+    public ResponseEntity<FileUrlDto> fileUpload(MultipartFile file,@RequestParam(required = false) String dir) throws IOException {
+        if(StringUtils.isBlank(dir)){
+            dir = "oss";
+        }
+        FileUrlDto dto = psiOssService.webUpload(file,dir);
+        return ResponseEntity.ok(dto);
+    }
+
+    /**
+     * 根据attachmentId查询附件信息(list)
+     * @param id
+     * @return
+     */
+    @PostMapping("selectWorkAttachmentByAttachmentId")
+    public List<WorkAttachmentInfo> selectWorkAttachmentByAttachmentId(String id){
+        return psiOssService.selectWorkAttachmentByAttachmentId(id);
+    }
+
+    /**
+     * 根据id查询用户
+     *
+     * @param id
+     * @return
+     */
+    @ApiLog("查询用户")
+    @GetMapping("queryById")
+    @ApiOperation(value = "查询用户")
+    public ResponseEntity queryById(@RequestParam("id") String id) {
+        UserDTO userDTO = SpringUtil.getBean ( IUserApi.class ).getById ( id );
+        if (CollectionUtil.isEmpty(userDTO.getCertDTOList())){
+            List<CertDTO> certListByUserId = SpringUtil.getBean ( IUserApi.class ).getCertListByUserId();
+//            List<CertDTO> certListByUserId = userService.getCertListByUserId();
+            userDTO.setCertDTOList(certListByUserId);
+        }
+
+        for (CertDTO cert : userDTO.getCertDTOList()) {
+            List<WorkAttachmentInfoDTO> files = psiOssService.findAttachement(cert.getId(), "certificate");
+            if (CollectionUtils.isNotEmpty(files)) {
+                cert.setCertificateAttachment(files);
+            }
+        }
+        if(StringUtils.isNotBlank(userDTO.getManageOfficeIds())){
+            //获取当前人管理的部门id
+            List<String> manageOfficeIdList= Arrays.asList(userDTO.getManageOfficeIds().split(","));
+            //查询这些部门信息
+            List<String> officeNameList = SpringUtil.getBean ( IOfficeApi.class ).getOfficeNameByIds(manageOfficeIdList);
+//            List<String> officeNameList = officeService.getOfficeNameByIds(manageOfficeIdList);
+            userDTO.setManageOfficeNameList(officeNameList);
+        }
+        if(ObjectUtil.isNotEmpty(userDTO)) {
+            if(CollectionUtil.isNotEmpty(userDTO.getCertDTOList())){
+                userDTO.getCertDTOList().stream().forEach(item->{
+                    if (StringUtils.isNotBlank(item.getFileUrl())){
+                        String fileTemporaryLookUrl = psiOssService.getFileTemporaryLookUrl(item.getFileUrl());
+                        item.setFileLsUrl(fileTemporaryLookUrl);
+                    }
+                });
+            }
+        }
+        //根据office.id 查询部门的所有父节点信息
+        if(null != userDTO.getOfficeDTO() && StringUtils.isNotBlank(userDTO.getOfficeDTO().getId())){
+            OfficeDTO office = SpringUtil.getBean ( IOfficeApi.class ).getOfficeById(userDTO.getOfficeDTO().getId());
+//            OfficeDTO office = officeService.getOfficeById(userDTO.getOfficeDTO().getId());
+            //将office的父节点信息进行分割并查询赋值
+            if(null != office){
+                List<String> officeIdList = Arrays.asList(office.getParentIds().split(","));
+                Integer sort = 0;
+                if(null != officeIdList && officeIdList.size()>0){
+                    for (String officeId : officeIdList) {
+                        if(StringUtils.isNotBlank(officeId) && !"0".equals(officeId)){
+                            sort ++ ;
+                            OfficeDTO officeChild = SpringUtil.getBean ( IOfficeApi.class ).getOfficeById(officeId);
+//                            OfficeDTO officeChild = officeService.getOfficeById(officeId);
+                            if(null != officeChild) {
+                                switch (sort){
+                                    case 1:
+                                        userDTO.setCompanyDTO(officeChild);
+                                        break;
+                                    case 2:
+                                        userDTO.setCorporationDTO(officeChild);
+                                        break;
+                                    case 3:
+                                        userDTO.setOfficeDTO(officeChild);
+                                        break;
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+
+        }
+        return ResponseEntity.ok ( userDTO );
+    }
+
+    /**
+     * 财务模块保存附件使用
+     * @param map
+     */
+    @RequestMapping(value = "financeFileSave", method = RequestMethod.POST)
+    public void insertWorkAttachment (@RequestBody Map<String ,String > map){
+        String attachmentInfo = map.get("workAttachment");
+        String userDtoInfo = map.get("userDTO");
+        PsiWorkAttachment attachment = JSON.parseObject(attachmentInfo, new TypeReference<PsiWorkAttachment>() {});
+        UserDTO userDTO = JSON.parseObject(userDtoInfo, new TypeReference<UserDTO>() {});
+        psiOssService.insertWorkAttachment(attachment,userDTO);
+    }
+
+    @GetMapping("/deleteById")
+    @ApiOperation(value = "根据id删除财务文件数据")
+    public void deleteById(@RequestParam String id) {
+        psiOssService.deleteById(id);
+    }
+
+    /**
+     * 保存附件操作
+     * @param map
+     */
+    @RequestMapping(value = "saveOrUpdateFileList", method = RequestMethod.POST)
+    public void saveOrUpdateFileList(@RequestBody Map<String ,String > map){
+        String fileListInfo = map.get("fileList");
+        String attachmentId = map.get("attachmentId");
+        String attachmentFlag = map.get("attachmentFlag");
+        String currentToken = map.get("currentToken");
+        List<WorkAttachmentDto> fileList = JSON.parseObject(fileListInfo, new TypeReference<List<WorkAttachmentDto>>() {});
+        psiOssService.saveOrUpdateFileList(fileList,attachmentId,attachmentFlag,currentToken);
+    }
+
+    @RequestMapping(value = "saveOrUpdateFileListFlag", method = RequestMethod.POST)
+    public void saveOrUpdateFileListFlag(@RequestBody Map<String ,String > map) {
+        String fileListInfo = map.get("fileList");
+        String attachmentId = map.get("attachmentId");
+        String attachmentFlag = map.get("attachmentFlag");
+        String currentToken = map.get("currentToken");
+        List<WorkAttachmentInfoDTO> fileList = JSON.parseObject(fileListInfo, new TypeReference<List<WorkAttachmentInfoDTO>>() {});
+        psiOssService.saveOrUpdateFileListFlag(fileList,attachmentId,attachmentFlag,currentToken);
+    }
+
+
+    @GetMapping("/deleteByAttachmentId")
+    @ApiOperation(value = "根据attachmentId删除附件")
+    public void deleteByAttachmentId(String attachmentId) {
+        psiOssService.deleteByAttachmentId(attachmentId);
+    }
+
+    @GetMapping("/deleteByAttachmentIdNotInIds")
+    @ApiOperation(value = "根据attachmentId删除附件")
+    public void deleteByAttachmentIdNotInIds(String attachmentId,List<String> delIds) {
+        psiOssService.deleteByAttachmentIdNotInIds(attachmentId,delIds);
+    }
+
+    /**
+     * 根据attachmentId查询附件信息(list)
+     * @param attachmentId
+     * @return
+     */
+    @PostMapping("selectListByAttachmentId")
+    public List<WorkAttachmentInfo> selectListByAttachmentId(@RequestParam String attachmentId){
+        return psiOssService.selectListByAttachmentId(attachmentId);
+    }
+
+    @ApiOperation(value = "根据ids删除财务文件数据")
+    @RequestMapping(value = "deleteByIds", method = RequestMethod.POST)
+    public void deleteByIds(@RequestBody String ids) {
+        List<String> idList = JSON.parseObject(ids, new TypeReference<List<String>>() {});
+        idList.forEach(id->{
+            psiOssService.deleteById(id);
+        });
+
+    }
+
+    /**
+     * 保存附件操作
+     * @param map
+     */
+    @RequestMapping(value = "saveFile", method = RequestMethod.POST)
+    public String saveFile(@RequestBody Map<String ,String > map){
+        WorkAttachmentDto workAttachmentDto = JSON.parseObject(map.get("workAttachmentDtoInfo"), new TypeReference<WorkAttachmentDto>() {});
+        UserDTO userDTO = JSON.parseObject(map.get("userDTOInfo"), new TypeReference<UserDTO>() {});
+        String attachmentId = map.get("attachmentId");
+        String attachmentFlag = map.get("attachmentFlag");
+        Integer sort = Integer.parseInt(map.get("sortInfo"));
+        return psiOssService.saveFile(workAttachmentDto,userDTO,attachmentId,attachmentFlag,sort);
+    }
+
+    /**
+     * 附件下载到本地指定文件夹
+     * @param key
+     * @param fileName
+     * @param downFileStr
+     */
+    @RequestMapping(value = "/downByStreamSaveLocal", method = RequestMethod.POST)
+    public void downByStreamSaveLocal(String key, String fileName, String downFileStr) {
+        psiOssClientService.downByStreamSaveLocal(key, fileName, downFileStr);
+    }
+
+
+    /**
+     * 根据路径下载所有文件到本地指定文件夹
+     */
+    @RequestMapping(value = "/downloadFolderFromOss", method = RequestMethod.POST)
+    public void downloadFolderFromOss(String prefix, String localDir) {
+        psiOssClientService.downloadFolderFromOss(prefix, localDir);
+    }
+
+    /**
+     * 获取编号模板编号
+     * @param companyId
+     * @param bizCode
+     * @return
+     * @throws Exception
+     */
+    @RequestMapping(value = "/genSerialNum", method = RequestMethod.POST)
+    public String genSerialNum(String companyId, String bizCode,String currentToken) throws Exception{
+        return psiSerialnumTplService.genSerialNum(companyId, bizCode, currentToken);
+    }
+
+    /**
+     * 获取编号模板报告编号
+     * @param companyId
+     * @param bizCode
+     * @return
+     * @throws Exception
+     */
+    @RequestMapping(value = "/genSerialNumNoSort", method = RequestMethod.POST)
+    public String genSerialNumNoSort(String companyId, String bizCode,String currentToken) throws Exception{
+        return psiSerialnumTplService.genSerialNumNoSort(companyId, bizCode,currentToken);
+    }
+
+    /**
+     * 获取编号模板报告编号
+     * @param companyId
+     * @param bizCode
+     * @return
+     * @throws Exception
+     */
+    @RequestMapping(value = "/genSerialReviewNum", method = RequestMethod.POST)
+    public String genSerialReviewNum(String companyId, String bizCode,String currentToken) throws Exception{
+        return psiSerialnumTplService.genSerialReviewNum(companyId, bizCode,currentToken);
+    }
+
+    /**
+     * 根据关联id和url查询数据信息
+     * @param workattachment
+     * @return
+     */
+    @RequestMapping(value = "getByAttachmentIdAndUrlAndAttachmentFlag", method = RequestMethod.POST)
+    public List<WorkAttachmentInfo> getByAttachmentIdAndUrlAndAttachmentFlag(@RequestBody WorkAttachmentInfo workattachment){
+        return psiOssService.getByAttachmentIdAndUrlAndAttachmentFlag(workattachment);
+    }
+
+    /**
+     * 附件下载到本地指定文件夹(签章系统)
+     * @param key
+     * @param fileName
+     * @param downFileStr
+     */
+    @RequestMapping(value = "/downQzByStreamSaveLocal", method = RequestMethod.POST)
+    public void downQzByStreamSaveLocal(String key, String fileName,String downFileStr) throws Exception{
+        psiOssClientService.downQzByStreamSaveLocal(key,fileName,downFileStr);
+    }
+
+    @PostMapping("datePath")
+    public String datePath() {
+        return psiOssClientService.datePath();
+    }
+
+    @RequestMapping(value = "/uploadFile2OSS", method = RequestMethod.POST)
+    public String uploadFile2OSS(InputStream inStream,String fileDir,String fileName) {
+        return psiOssClientService.uploadFile2OSS(inStream, fileDir, fileName);
+    }
+
+    @RequestMapping(value = "/uploadFileSignatureOSS", method = RequestMethod.POST)
+    public String uploadFileSignatureOSS(String filePath,String fileDir,String fileName) {
+        return psiOssClientService.uploadFileSignatureOSS(filePath, fileDir, fileName);
+    }
+
+    /**
+     * 保存附件操作
+     * @param map
+     */
+    @RequestMapping(value = "saveMsg2", method = RequestMethod.POST)
+    public void saveMsg2(@RequestBody Map<String ,String > map){
+        String attachmentInfo = map.get("workAttachments");
+        String currentToken = map.get("currentToken");
+        List<PsiWorkAttachment> list = JSON.parseObject(attachmentInfo, new TypeReference<List<PsiWorkAttachment>>() {});
+        psiOssService.saveMsg(list,currentToken);
+    }
+
+    /**
+     * 移动端所需
+     * 解析xml文件附件信息(发票报销)
+     * @param file
+     * @return
+     */
+    @DemoMode
+    @PostMapping("/disposeXmlFileApp")
+    @ApiOperation(value = "解析xml文件附件信息(发票报销)")
+    public Map<String,Object> disposeXmlFileApp( MultipartFile file) throws IOException {
+        Map<String,Object> map = new HashMap();
+        //创建DOM4J解析器对象
+        File newFile = null;
+        try {
+            //MultipartFile转File
+            newFile = FileUtil.transformMultipartFile(file);
+            // 创建一个 DocumentBuilderFactory
+            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+            // 使用工厂创建一个 DocumentBuilder
+            DocumentBuilder builder = factory.newDocumentBuilder();
+            // 使用 DocumentBuilder 解析 XML 文件
+            Document document = builder.parse(newFile);
+            // 获取所有header节点的集合
+            NodeList headerList = document.getElementsByTagName("Header");
+            // 获取所有eInvoiceDataList节点的集合
+            NodeList eInvoiceDataList = document.getElementsByTagName("EInvoiceData");
+            // 获取所有taxSupervisionInfo节点的集合
+            NodeList taxSupervisionInfoList = document.getElementsByTagName("TaxSupervisionInfo");
+
+            Map<String,String> map1 = xmlNodeListDataDispose(headerList, document);
+            Map<String,String> map2 = xmlNodeListDataDispose(eInvoiceDataList, document);
+            Map<String,String> map3 = xmlNodeListDataDispose(taxSupervisionInfoList, document);
+            map.putAll(map1);
+            map.putAll(map2);
+            map.putAll(map3);
+
+        } catch (Exception e) {
+            e.printStackTrace();
+        }finally {
+            newFile.delete();
+        }
+
+        //对文件进行上传到阿里云操作
+        String dir = "note";
+        FileUrlDto dto = psiOssService.webUpload(file,dir);
+        map.put("url", dto.getUrl());
+        map.put("lsUrl", dto.getLsUrl());
+        return map;
+    }
+
+    /**
+     * 解析xml文件附件信息(发票报销)
+     * @param file
+     * @return
+     */
+    @DemoMode
+    @PostMapping("/disposeXmlFile")
+    @ApiOperation(value = "解析xml文件附件信息(发票报销)")
+    public Map<String,Object> disposeXmlFile( MultipartFile file) {
+        Map<String,Object> map = new HashMap();
+        //创建DOM4J解析器对象
+        File newFile = null;
+        try {
+            //MultipartFile转File
+            newFile = FileUtil.transformMultipartFile(file);
+            // 创建一个 DocumentBuilderFactory
+            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+            // 使用工厂创建一个 DocumentBuilder
+            DocumentBuilder builder = factory.newDocumentBuilder();
+            // 使用 DocumentBuilder 解析 XML 文件
+            Document document = builder.parse(newFile);
+            // 获取所有header节点的集合
+            NodeList headerList = document.getElementsByTagName("Header");
+            // 获取所有eInvoiceDataList节点的集合
+            NodeList eInvoiceDataList = document.getElementsByTagName("EInvoiceData");
+            // 获取所有taxSupervisionInfo节点的集合
+            NodeList taxSupervisionInfoList = document.getElementsByTagName("TaxSupervisionInfo");
+
+            Map<String,String> map1 = xmlNodeListDataDispose(headerList, document);
+            Map<String,String> map2 = xmlNodeListDataDispose(eInvoiceDataList, document);
+            Map<String,String> map3 = xmlNodeListDataDispose(taxSupervisionInfoList, document);
+            map.putAll(map1);
+            map.putAll(map2);
+            map.putAll(map3);
+
+        } catch (Exception e) {
+            e.printStackTrace();
+        }finally {
+            newFile.delete();
+        }
+        return map;
+    }
+
+    /**
+     * 下载附件
+     */
+    @PostMapping("/downLoadFileDisposeXmlFile")
+    @ApiOperation(value = "下载附件")
+    public Map<String,Object> downLoadFileDisposeXmlFile(@RequestParam String file) {
+        file = "http://oss.gangwaninfo.com" + file;
+        file = file.replace("amp;", "");
+        String fileName = file.substring(file.lastIndexOf("/") + 1, file.length());
+        String cons = "";
+        if (file.contains(aliyunUrl)) {
+            cons = aliyunUrl;
+        } else if (file.contains("http://gangwan-app.oss-cn-hangzhou.aliyuncs.com")) {
+            cons = "http://gangwan-app.oss-cn-hangzhou.aliyuncs.com";
+        } else {
+            cons = aliyunDownloadUrl;
+        }
+        String key = file.split(cons + "/")[1];
+        log.info("-----------------------------------------");
+        log.info("fileName=" + fileName);
+        log.info("key=" + key);
+        log.info("-----------------------------------------");
+
+        String path = null;
+        if(System.getProperty("os.name").toLowerCase().contains("win")){
+            path = "D:/attachment-file/";
+        }else{
+            path = "/attachment-file/";
+        }
+        psiOssClientService.downByStreamSaveLocal(key, fileName, path+fileName);
+
+        Map<String,Object> map = new HashMap();
+        //创建DOM4J解析器对象
+        File newFile = new File(path + fileName);
+        try {
+            //MultipartFile转File
+            //newFile = FileUtil.transformMultipartFile(file);
+            // 创建一个 DocumentBuilderFactory
+            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+            // 使用工厂创建一个 DocumentBuilder
+            DocumentBuilder builder = factory.newDocumentBuilder();
+            // 使用 DocumentBuilder 解析 XML 文件
+            Document document = builder.parse(newFile);
+            // 获取所有header节点的集合
+            NodeList headerList = document.getElementsByTagName("Header");
+            // 获取所有eInvoiceDataList节点的集合
+            NodeList eInvoiceDataList = document.getElementsByTagName("EInvoiceData");
+            // 获取所有taxSupervisionInfo节点的集合
+            NodeList taxSupervisionInfoList = document.getElementsByTagName("TaxSupervisionInfo");
+
+            Map<String,String> map1 = xmlNodeListDataDispose(headerList, document);
+            Map<String,String> map2 = xmlNodeListDataDispose(eInvoiceDataList, document);
+            Map<String,String> map3 = xmlNodeListDataDispose(taxSupervisionInfoList, document);
+            map.putAll(map1);
+            map.putAll(map2);
+            map.putAll(map3);
+
+        } catch (Exception e) {
+            e.printStackTrace();
+        }finally {
+            newFile.delete();
+        }
+        return map;
+    }
+
+    /**
+     * 对节点集合进行遍历,并获取每个节点下的参数信息
+     * @param nodeList
+     * @param document
+     * @return
+     */
+    public Map<String,String> xmlNodeListDataDispose(NodeList nodeList,Document document){
+        Map<String,String> map = new HashMap<>();
+        Map<String, Integer> keyCounter = new HashMap<>(); // 同名节点计数器
+        if(null != nodeList && nodeList.getLength()>0){
+            for (int i = 0; i < nodeList.getLength(); i++) {
+                Node topNode = nodeList.item(i); // 0层:Header/EInvoiceData/TaxSupervisionInfo
+                NodeList childNodes = topNode.getChildNodes();
+                // 初始化层级为1(顶层直接子节点),父前缀为空
+                Map<String,String> map1 = xmlDataDispose(childNodes, document, "", 1, keyCounter);
+                map.putAll(map1);
+            }
+        }
+        return map;
+    }
+
+    /**
+     * 修复同名节点重复拼接问题:第2层与第1层同名时,仅保留1次节点名
+     * 规则:0/1层不拼接,2层若与1层同名则不重复拼接,3层及以下正常拼接
+     */
+    public Map<String,String> xmlDataDispose(NodeList childNodes,Document document, String parentPrefix, int currentLevel, Map<String, Integer> keyCounter){
+        Map<String,String> map = new HashMap<>();
+        for (int k = 0; k < childNodes.getLength(); k++) {
+            if (childNodes.item(k).getNodeType() == Node.ELEMENT_NODE) {
+                Node currentNode = childNodes.item(k);
+                String nodeName = currentNode.getNodeName();
+                String cleanNodeName = nodeName.replaceAll("-", "");
+                NodeList grandChildNodes = currentNode.getChildNodes();
+
+                String currentKeyPrefix;
+                if (currentLevel == 1) {
+                    currentKeyPrefix = cleanNodeName;
+                } else if (currentLevel == 2) {
+                    if (cleanNodeName.equals(parentPrefix)) {
+                        currentKeyPrefix = parentPrefix;
+                    } else {
+                        currentKeyPrefix = parentPrefix + cleanNodeName;
+                    }
+                } else {
+                    currentKeyPrefix = parentPrefix + cleanNodeName;
+                }
+
+                String textValue = getNodeTextValue(grandChildNodes);
+                // 修复:空文本但有子元素时仍递归(避免漏解析深层节点)
+                if (StringUtils.isNotBlank(textValue) || hasChildElements(grandChildNodes)) {
+                    if (StringUtils.isNotBlank(textValue)) {
+                        String finalKey = generateUniqueKey(currentKeyPrefix, keyCounter);
+                        map.put(finalKey, textValue);
+                    }
+                    if (hasChildElements(grandChildNodes)) {
+                        Map<String,String> childMap = xmlDataDispose(grandChildNodes, document, currentKeyPrefix, currentLevel + 1, keyCounter);
+                        map.putAll(childMap);
+                    }
+                }
+            }
+        }
+        return map;
+    }
+
+    /**
+     * 提取节点有效文本值(仅保留非空白文本)
+     */
+    private String getNodeTextValue(NodeList childNodes) {
+        StringBuilder text = new StringBuilder();
+        for (int i = 0; i < childNodes.getLength(); i++) {
+            Node child = childNodes.item(i);
+            // 修复1:新增CDATA节点处理(数电票核心字段多为CDATA包裹)
+            if (child.getNodeType() == Node.TEXT_NODE || child.getNodeType() == Node.CDATA_SECTION_NODE) {
+                // 修复2:先拼接原始值,最后统一trim(避免中间有效换行/空格被过滤)
+                text.append(child.getNodeValue());
+            }
+        }
+        // 仅首尾trim,保留中间有效文本(如Remark里的换行转义后内容)
+        return StringUtils.trim(text.toString());
+    }
+
+    /**
+     * 判断是否有子元素节点
+     */
+    private boolean hasChildElements(NodeList childNodes) {
+        for (int i = 0; i < childNodes.getLength(); i++) {
+            if (childNodes.item(i).getNodeType() == Node.ELEMENT_NODE) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * 生成不重复key(同名节点加序号,避免覆盖)
+     */
+    private String generateUniqueKey(String keyPrefix, Map<String, Integer> keyCounter) {
+        // 修复:先获取当前计数(初始为0),再判断是否需要加序号
+        int count = keyCounter.getOrDefault(keyPrefix, 0);
+        if (count == 0) {
+            // 首次出现:直接返回前缀,计数置为1
+            keyCounter.put(keyPrefix, 1);
+            return keyPrefix;
+        } else {
+            // 重复出现:计数+1,返回前缀+序号(如SellerName2)
+            keyCounter.put(keyPrefix, count + 1);
+            return keyPrefix + count;
+        }
+    }
+
+    @ApiOperation("处理数电发票数据中的购买方名称信息")
+    @GetMapping("/disposeElectronicEngineeringInvoice")
+    public Map<String,String> disposeElectronicEngineeringInvoice(@RequestParam List<String> attachmentIdList, @RequestParam String type){
+        //首先获取所有数电发票报销信息
+        Map<String, String> map = psiOssService.disposeElectronicEngineeringInvoice(attachmentIdList, type);
+
+        return map;
+    }
+
+    @ApiOperation("获取数电发票数据中的发票号信息")
+    @GetMapping("/disposeElectronicEngineeringInvoiceNumber")
+    public Map<String,String> disposeElectronicEngineeringInvoiceNumber(@RequestParam List<String> attachmentIdList, @RequestParam String type){
+        //首先获取所有数电发票报销信息
+        Map<String, String> map = psiOssService.disposeElectronicEngineeringInvoiceNumber(attachmentIdList, type);
+
+        return map;
+    }
+
+    /**
+     * 根据发票号查询是否已经被报销
+     */
+    @ApiOperation("根据发票号查询是否已经被报销")
+    @GetMapping("/isUsedByInvoiceNumber")
+    public Boolean isUsedByInvoiceNumber(@RequestParam String invoiceNumber){
+        Boolean data = psiOssService.isUsedByInvoiceNumber(invoiceNumber);
+        return data;
+    }
+
+
+    /**
+     * 用户选择资料库文件重新上传
+     */
+    @ApiOperation("用户选择资料库文件重新上传")
+    @PostMapping("/downloadAndUploadToOSS")
+    public String downloadAndUploadToOSS(@RequestBody DownToOssDTO downToOssDTO){
+        String  filePath = psiOssClientService.downloadAndUploadToOSS(downToOssDTO.getUrl(),downToOssDTO.getFileName(),downToOssDTO.getDir());
+        return filePath;
+    }
+
+    @RequestMapping(value = "/downBytesByStream", method = RequestMethod.POST)
+    public  byte[] downBytesByStream(String key, String fileName){
+        return     psiOssClientService.downBytesByStream(key, fileName);
+    }
+
+
+
+    /**
+     * 根据ids查询附件信息(list)
+     * @return
+     */
+    @PostMapping("getByAttachmentIdListAndFlag")
+    public List<WorkAttachmentInfo> getByAttachmentIdListAndFlag(@RequestParam List<String> ids){
+        return psiOssService.getByAttachmentIdListAndFlag(ids);
+    }
+}

+ 71 - 0
jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/oss/domain/PsiWorkAttachment.java

@@ -0,0 +1,71 @@
+package com.jeeplus.psimanage.oss.domain;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.jeeplus.core.domain.BaseEntity;
+import lombok.Data;
+
+@Data
+@TableName("work_attachment")
+public class PsiWorkAttachment extends BaseEntity {
+
+    /**
+     * 附件地址
+     */
+    private String url;
+
+    /**
+     * 文件类型(文件后缀名)
+     */
+    private String type;
+
+    /**
+     * 附件对应父节点id(记录是谁的id)
+     */
+    private String attachmentId;
+
+    /**
+     * 文件名
+     */
+    private String attachmentName;
+
+    /**
+     * 文件所属业务模块(数据字典配置)
+     */
+    private String attachmentFlag;
+
+    /**
+     * 所属模块子模块
+     */
+    private String moduleType;
+
+    /**
+     * 附件类型
+     */
+    private String attachmentType;
+
+    /**
+     * 附件大小
+     */
+    private String fileSize;
+
+    /**
+     * 排序
+     */
+    private Integer sort;
+
+    /**
+     * 文件描述
+     */
+    private String description;
+
+    /**
+     * 附件临时地址
+     *该属性不是实体字段
+     */
+    @TableField(exist = false)
+    private String temporaryUrl;
+
+
+    private  String remarks;
+}

+ 84 - 0
jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/oss/mapper/PsiOssServiceMapper.java

@@ -0,0 +1,84 @@
+package com.jeeplus.psimanage.oss.mapper;
+
+import com.baomidou.mybatisplus.annotation.InterceptorIgnore;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.core.toolkit.Constants;
+import com.jeeplus.psimanage.oss.domain.PsiWorkAttachment;
+import com.jeeplus.psimanage.oss.service.dto.AttachmentDTO;
+import com.jeeplus.sys.domain.WorkAttachmentInfo;
+import com.jeeplus.sys.service.dto.UserDTO;
+import com.jeeplus.sys.service.dto.WorkAttachmentInfoDTO;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+public interface PsiOssServiceMapper extends BaseMapper<PsiWorkAttachment> {
+
+    @InterceptorIgnore(tenantLine = "true")
+    Integer deleteById(String id);
+
+    @InterceptorIgnore(tenantLine = "true")
+    Integer selectSaveById(String id);
+
+    @InterceptorIgnore(tenantLine = "true")
+    void updateProjectRecord(String id);
+
+    //@InterceptorIgnore(tenantLine = "true")
+    List<AttachmentDTO> findList(@Param(Constants.WRAPPER) QueryWrapper queryWrapper);
+
+    @InterceptorIgnore(tenantLine = "true")
+    void insertWorkAttachment (@Param("workAttachment") PsiWorkAttachment psiWorkAttachment, @Param("userDto") UserDTO userDto);
+
+    /**
+     * 根据关联id和url查询数据信息
+     * @param workAttachment
+     * @return
+     */
+    //@InterceptorIgnore(tenantLine = "true")
+    List<WorkAttachmentInfo> getByAttachmentIdAndUrlAndAttachmentFlag(WorkAttachmentInfo workAttachment);
+
+    /**
+     * 查询电子章文件信息
+     * @param id
+     * @return
+     */
+    @InterceptorIgnore(tenantLine = "true")
+    List<WorkAttachmentInfo> selectWorkAttachmentByAttachmentId(String id);
+
+    /**
+     * 根据attachmentId删除附件
+     * @param attachmentId
+     */
+    @InterceptorIgnore(tenantLine = "true")
+    void deleteByAttachmentId(@Param("attachmentId")String attachmentId);
+
+    /**
+     * 根据attachmentId查询附件信息
+     * @param attachmentId
+     * @return
+     */
+    @InterceptorIgnore(tenantLine = "true")
+    List<WorkAttachmentInfo> selectListByAttachmentId(String attachmentId);
+
+    @InterceptorIgnore(tenantLine = "true")
+    void deleteByAttachmentIdNotInIds(@Param("attachmentId")String attachmentId, @Param("delIds")List<String> delIds);
+
+    /**
+     * 根据attachmentId查询附件数据信息
+     * @param attachmentIdList
+     * @return
+     */
+    List<WorkAttachmentInfo> getElectronicEngineeringInvoiceAttachmentList(@Param("attachmentIdList")List<String> attachmentIdList, @Param("attachmentFlag")String attachmentFlag);
+
+    Integer isUsedByInvoiceNumber(@Param("invoiceNumber") String invoiceNumber);
+
+    List<WorkAttachmentInfoDTO> findDtos(@Param("id")String id, @Param("attachmentFlag")String attachmentFlag);
+
+
+    /**
+     * @return
+     */
+    @InterceptorIgnore(tenantLine = "true")
+    List<WorkAttachmentInfo> getByAttachmentIdListAndFlag(@Param("ids")List<String> ids);
+}

+ 199 - 0
jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/oss/mapper/xml/PsiOssServiceMapper.xml

@@ -0,0 +1,199 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.jeeplus.psimanage.oss.mapper.PsiOssServiceMapper">
+    <delete id="deleteById">
+        delete from work_attachment where id = #{id}
+    </delete>
+    <delete id="deleteByAttachmentId">
+        delete from work_attachment where attachment_id = #{attachmentId}
+    </delete>
+    <delete id="deleteByAttachmentIdNotInIds">
+        delete from work_attachment where attachment_id = #{attachmentId}
+        and id not in
+        <foreach collection="delIds" item="item" index="index" open="(" close=")" separator=",">
+            #{item}
+        </foreach>
+    </delete>
+
+    <select id="selectSaveById" resultType="java.lang.Integer">
+    SELECT
+        COUNT( 0 )
+    FROM
+        work_attachment
+    WHERE
+        del_flag = 0
+        AND attachment_id = (
+        SELECT
+            attachment_id
+        FROM
+            work_attachment
+    WHERE
+        id = #{id})
+  </select>
+
+  <update id="updateProjectRecord">
+    UPDATE project_records
+    SET file_upload_type = 0
+    WHERE
+        id = (
+        SELECT
+            attachment_id
+        FROM
+            work_attachment
+    WHERE
+        id = #{id})
+  </update>
+
+    <select id="findList" resultType="com.jeeplus.psimanage.oss.service.dto.AttachmentDTO">
+        SELECT a.id, a.url, a.type, a.attachment_id, a.attachment_name, a.attachment_flag,
+        a.module_type, a.attachment_type, a.file_size, a.sort, a.description,
+        a.create_time, a.create_by_id as "create_by.id", su.name as "createBy.name" , a.update_time, a.update_by_id as "updateBy.id", a.del_flag
+         FROM work_attachment a
+         left join sys_user su on su.id = a.create_by_id
+         ${ew.customSqlSegment}
+         ORDER BY a.sort ASC;
+    </select>
+
+    <insert id="insertWorkAttachment">
+        INSERT INTO work_attachment (
+            id,
+            create_by_id,
+            create_time,
+            update_by_id,
+            update_time,
+            del_flag,
+            url,
+            type,
+            attachment_id,
+            attachment_name,
+            attachment_flag,
+            file_size,
+            sort,
+            remarks
+            )
+        VALUES(
+            #{psiWorkAttachment.id},
+            #{userDto.id},
+            #{psiWorkAttachment.createTime},
+            #{userDto.id},
+            #{psiWorkAttachment.updateTime},
+            #{psiWorkAttachment.delFlag},
+            #{psiWorkAttachment.url},
+            #{psiWorkAttachment.type},
+            #{psiWorkAttachment.attachmentId},
+            #{psiWorkAttachment.attachmentName},
+            #{psiWorkAttachment.attachmentFlag},
+            #{psiWorkAttachment.fileSize},
+            #{psiWorkAttachment.sort},
+            #{psiWorkAttachment.remarks}
+            )
+    </insert>
+
+    <select id="getByAttachmentIdAndUrlAndAttachmentFlag" resultType="com.jeeplus.sys.domain.WorkAttachmentInfo">
+        SELECT a.id, a.url, a.type, a.attachment_id, a.attachment_name, a.attachment_flag,
+        a.module_type, a.attachment_type, a.file_size, a.sort, a.description,
+        a.create_time, a.create_by_id as "create_by.id", su.name as "createBy.name" , a.update_time, a.update_by_id as "updateBy.id", a.del_flag
+         FROM work_attachment a
+         left join sys_user su on su.id = a.create_by_id
+         <where>
+             a.del_flag = 0
+             <if test="attachmentId != null and attachmentId != ''">
+                 and a.attachment_id = #{attachmentId}
+             </if>
+             <if test="attachmentName != null and attachmentName != ''">
+                 and a.attachment_name = #{attachmentName}
+             </if>
+             <if test="attachmentFlag != null and attachmentFlag != ''">
+                 and a.attachment_flag = #{attachmentFlag}
+             </if>
+         </where>
+    </select>
+
+    <select id="selectWorkAttachmentByAttachmentId"
+            resultType="com.jeeplus.sys.domain.WorkAttachmentInfo">
+
+        select a.* from work_attachment a
+        left join cw_project_report_file cf on cf.report_file_id = a.id
+        where a.attachment_id = #{id} and cf.seal_type = 1 and a.del_flag = 0
+    </select>
+    <select id="selectListByAttachmentId" resultType="com.jeeplus.sys.domain.WorkAttachmentInfo">
+        select a.* from work_attachment a where a.attachment_id = #{id} order by a.sort ASC
+    </select>
+
+
+
+    <select id="getElectronicEngineeringInvoiceAttachmentList" resultType="com.jeeplus.sys.domain.WorkAttachmentInfo">
+        SELECT a.id, a.url, a.type, a.attachment_id, a.attachment_name, a.attachment_flag,
+        a.module_type, a.attachment_type, a.file_size, a.sort, a.description,
+        a.create_time, a.create_by_id as "create_by.id" , a.update_time, a.update_by_id as "updateBy.id", a.del_flag
+        FROM work_attachment a
+        <where>
+            a.del_flag = 0
+
+            <if test="attachmentIdList != null">
+                AND a.attachment_id IN
+                <foreach collection="attachmentIdList" item="attachmentId" index="index" open="(" close=")" separator=",">
+                    #{attachmentId}
+                </foreach>
+            </if>
+            <if test="attachmentFlag != null and attachmentFlag != ''">
+                and a.attachment_flag = #{attachmentFlag}
+            </if>
+        </where>
+    </select>
+
+
+    <select id="isUsedByInvoiceNumber" resultType="int">
+        select  MAX(counts)
+        from(select count(a.number) as counts from reimbursement_amount_info a
+        left join reimbursement_info ri on ri.id = a.info_id
+        where a.number  = #{invoiceNumber} and a.del_flag = 0 and ri.del_flag = 0  and (ri.type = '2' or ri.type = '5')
+        union all
+        select count(a.number) as counts from cw_reimbursement_amount_info a
+        left join cw_reimbursement_info ri on ri.id = a.info_id
+        where a.number  = #{invoiceNumber} and a.del_flag = 0 and ri.del_flag = 0  and (ri.type = '2' or ri.type = '5')
+        union all
+        select count(a.number) as counts from ccpm_reimbursement_amount_info a
+        left join ccpm_reimbursement_info ri on ri.id = a.info_id
+        where a.number  = #{invoiceNumber} and a.del_flag = 0 and ri.del_flag = 0  and (ri.type = '2' or ri.type = '5')
+        union all
+        select count(a.number) as counts from zs_reimbursement_amount_info a
+        left join zs_reimbursement_info ri on ri.id = a.info_id
+        where a.number  = #{invoiceNumber} and a.del_flag = 0 and ri.del_flag = 0  and (ri.type = '2' or ri.type = '5')
+        union all
+        select count(a.number) as counts from consultancy_reimbursement_amount_info a
+        left join consultancy_reimbursement_info ri on ri.id = a.info_id
+        where a.number  = #{invoiceNumber} and a.del_flag = 0 and ri.del_flag = 0  and (ri.type = '2' or ri.type = '5')
+        ) as result
+    </select>
+
+
+    <select id="findDtos" resultType="com.jeeplus.sys.service.dto.WorkAttachmentInfoDTO">
+        SELECT
+            id,
+            url,
+            attachment_name AS `name`,
+            create_by_id AS `by`,
+            create_time,
+            attachment_flag AS attachmentFlag
+        FROM
+            work_attachment
+        WHERE
+            del_flag = 0
+          AND attachment_id = #{id}
+          AND attachment_flag = #{attachmentFlag}
+
+    </select>
+
+
+    <select id="getByAttachmentIdListAndFlag"
+            resultType="com.jeeplus.sys.domain.WorkAttachmentInfo">
+        select a.*
+        from work_attachment a
+        where a.del_flag = 0
+        and a.attachment_id in
+        <foreach collection="ids" item="id" open="(" close=")" separator=",">
+            #{id}
+        </foreach>
+    </select>
+</mapper>

+ 478 - 0
jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/oss/service/PsiOSSClientService.java

@@ -0,0 +1,478 @@
+package com.jeeplus.psimanage.oss.service;
+
+import com.aliyun.oss.OSSClient;
+import com.aliyun.oss.model.*;
+//import com.jeeplus.sys.utils.Global;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+import org.springframework.web.multipart.MultipartFile;
+import org.springframework.mock.web.MockMultipartFile;
+
+import java.io.*;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.util.Calendar;
+import java.util.Date;
+
+@Slf4j
+@Service
+public class PsiOSSClientService {
+
+    @Value("${config.accessory.aliyun.aliyunDownloadUrl}")
+    private String aliyunDownloadUrl;
+
+    @Value("${config.accessory.aliyun.aliyunUrl}")
+    private String aliyunUrl;
+
+    @Value("${config.accessory.aliyun.bucketName}")
+    private String bucketName;
+
+    @Value("${qzBucketName}")
+    private String qzBucketName;
+
+    @Value("${config.accessory.aliyun.endpoint}")
+    private String endpoint;
+
+    @Value("${config.accessory.aliyun.accessKeyId}")
+    private String accessKeyId;
+
+    @Value("${config.accessory.aliyun.accessKeySecret}")
+    private String accessKeySecret;
+
+    private static final String DIRECTORY = "/attachment-file";
+
+    private static final String ALIYUNURL = "http://oss.gangwaninfo.com";
+    /**
+     * 上传到OSS服务器  如果同名文件会覆盖服务器上的
+     *
+     * @param fileName 文件名称 包括后缀名
+     * @return 出错返回"" ,唯一MD5数字签名
+     */
+    public String uploadFile2OSS(InputStream inStream, String fileDir, String fileName) {
+        //初始化OSSClient
+        OSSClient ossClient = new OSSClient(endpoint,accessKeyId,accessKeySecret);
+        long start = System.currentTimeMillis();
+        //上传文件
+        PutObjectResult putResult = ossClient.putObject(bucketName, fileDir + fileName, inStream);
+        String ret = putResult.getETag();
+
+        try {
+            if (inStream != null) {
+                inStream.close();
+            }
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+        long end = System.currentTimeMillis();
+        log.info("上传文件到云服务器成功,文件名:{},耗时:{}ms",fileName,end-start);
+        return ret;
+    }
+    /**
+     * 上传到OSS服务器  如果同名文件会覆盖服务器上的
+     *
+     * @param fileName 文件名称 包括后缀名
+     * @return 出错返回"" ,唯一MD5数字签名
+     */
+    public String uploadFileSignatureOSS(String filePath, String fileDir, String fileName) {
+        //初始化OSSClient
+        OSSClient ossClient = new OSSClient(endpoint,accessKeyId,accessKeySecret);
+        File f = new File(filePath);
+
+        try {
+        MultipartFile cMultiFile = new MockMultipartFile("file", f.getName(), null, new FileInputStream(f));
+        if (!cMultiFile.isEmpty()) {
+            //文件原名称
+            String newName = cMultiFile.getOriginalFilename();
+            InputStream inStream = cMultiFile.getInputStream();
+            if(StringUtils.isNotBlank(newName)){
+
+                long start = System.currentTimeMillis();
+                //上传文件
+                PutObjectResult putResult = ossClient.putObject(bucketName, fileDir + fileName, inStream);
+                String ret = putResult.getETag();
+
+                try {
+                    if (inStream != null) {
+                        inStream.close();
+                    }
+                } catch (IOException e) {
+                    e.printStackTrace();
+                }
+                long end = System.currentTimeMillis();
+                log.info("上传文件到云服务器成功,文件名:{},耗时:{}ms",fileName,end-start);
+                return ret;
+            }
+        }
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+
+    /**
+     * 获得url链接
+     *
+     * @param key
+     * @return
+     */
+    public String getUrl(String key) {
+        OSSClient ossClient = new OSSClient(endpoint,accessKeyId,accessKeySecret);
+        // 设置URL过期时间为10年  3600l* 1000*24*365*10
+        Date expiration = new Date(new Date().getTime() + 3600l * 1000 * 24 * 365 * 10);
+        // 生成URL
+        URL url = ossClient.generatePresignedUrl(bucketName, key, expiration);
+        if (url != null) {
+            return url.toString();
+        }
+        return null;
+    }
+
+
+
+    /**
+     * 阿里云获取临时文件大小
+     * @param file
+     */
+    public Long getSimplifiedObjectMeta(String file){
+        //初始化OSSClient
+        OSSClient ossClient = new OSSClient(endpoint,accessKeyId,accessKeySecret);
+
+        URL url = null;
+        SimplifiedObjectMeta simplifiedObjectMeta = new SimplifiedObjectMeta();
+        try {
+
+            file = file.replace("amp;","");
+            String aliyunDownload = aliyunDownloadUrl;
+            String aliDownloadUrl = aliyunUrl;
+            String cons = "";
+            if (file.contains(aliyunDownload)){
+                cons = aliyunDownload;
+            }else if (file.contains("http://gangwan-app.oss-cn-hangzhou.aliyuncs.com")){
+                cons = "http://gangwan-app.oss-cn-hangzhou.aliyuncs.com";
+            }else {
+                cons = aliDownloadUrl;
+            }
+            String key = file.split(cons+"/")[1];
+            simplifiedObjectMeta = ossClient.getSimplifiedObjectMeta(bucketName, key);
+
+        } catch (Exception e) {
+            e.printStackTrace();
+            return null;
+        }
+        return simplifiedObjectMeta.getSize();
+    }
+
+
+    /**
+     * 文件下载
+     * @param key
+     * @param fileName
+     */
+    public byte[] downBytesByStream(String key, String fileName){
+        OSSClient ossClient = new OSSClient(endpoint,accessKeyId,accessKeySecret);
+        byte[] bytes = null;
+        BufferedInputStream in = null;
+        ByteArrayOutputStream outputStream = null;
+        log.info("开始从云服务器加载文件,文件名:{}",fileName);
+        try {
+            // 创建OSSClient实例
+            long start = System.currentTimeMillis();
+            OSSObject ossObject = ossClient.getObject(bucketName, key);
+            in = new BufferedInputStream(ossObject.getObjectContent());
+            outputStream = new ByteArrayOutputStream();
+            byte[] car=new byte[1024];
+            int L=0;
+            while((L=in.read(car))!=-1){
+                outputStream.write(car, 0,L);
+            }
+            bytes = outputStream.toByteArray();
+            long end = System.currentTimeMillis();
+            log.info("从云服务器加载文件成功,文件名:{},耗时:{}ms",fileName,end-start);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }finally {
+            if (in!=null){
+                try {
+                    in.close();
+                } catch (IOException e) {
+                    e.printStackTrace();
+                }
+            }
+            if (outputStream!=null){
+                try {
+                    outputStream.close();
+                } catch (IOException e) {
+                    e.printStackTrace();
+                }
+            }
+        }
+        return  bytes;
+    }
+
+
+    /**
+     * 附件下载到本地指定文件夹
+     * @param key
+     * @param fileName
+     */
+    public void downByStreamSaveLocal(String key, String fileName,String downFileStr){
+        try {
+            // 创建OSSClient实例
+            OSSClient ossClient = new OSSClient(endpoint,accessKeyId,accessKeySecret);
+            OSSObject ossObject = ossClient.getObject(bucketName, key);
+            BufferedInputStream in = new BufferedInputStream(ossObject.getObjectContent());
+
+
+            //写入到文件(注意文件保存路径的后面一定要加上文件的名称)
+            FileOutputStream fileOut = new FileOutputStream(downFileStr);
+            BufferedOutputStream bos = new BufferedOutputStream(fileOut);
+            byte[] buf = new byte[4096];
+            int length = in.read(buf);
+            //保存文件
+            while(length != -1)
+            {
+                bos.write(buf, 0, length);
+                length = in.read(buf);
+            }
+            if(bos!=null){
+                bos.flush();
+                bos.close();
+            }
+            if(in!=null){
+                in.close();
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+    /**
+     * 根据路径下载所有文件到本地指定文件夹
+     */
+    public void downloadFolderFromOss(String prefix, String localDir) {
+        OSSClient ossClient = null;
+        try {
+            ossClient = new OSSClient(endpoint, accessKeyId, accessKeySecret);
+
+            ListObjectsRequest request = new ListObjectsRequest(bucketName);
+            request.setPrefix(prefix); // OSS 文件夹前缀
+            request.setMaxKeys(1000);
+
+            ObjectListing listing;
+
+            do {
+                listing = ossClient.listObjects(request);
+
+
+                for (OSSObjectSummary summary : listing.getObjectSummaries()) {
+                    String objectKey = summary.getKey();
+
+                    // 跳过“文件夹”
+                    if (objectKey.endsWith("/")) {
+                        continue;
+                    }
+
+                    // 本地文件路径
+                    String localFilePath = localDir + File.separator
+                            + objectKey.substring(prefix.length());
+
+                    File localFile = new File(localFilePath);
+
+                    // 创建父目录
+                    if (!localFile.getParentFile().exists()) {
+                        localFile.getParentFile().mkdirs();
+                    }
+
+                    // 下载文件
+                    OSSObject ossObject = ossClient.getObject(bucketName, objectKey);
+                    try (
+                            InputStream in = new BufferedInputStream(ossObject.getObjectContent());
+                            OutputStream out = new BufferedOutputStream(new FileOutputStream(localFile))
+                    ) {
+                        byte[] buffer = new byte[4096];
+                        int len;
+                        while ((len = in.read(buffer)) != -1) {
+                            out.write(buffer, 0, len);
+                        }
+                    }
+                }
+
+                request.setMarker(listing.getNextMarker());
+            } while (listing.isTruncated());
+
+        } catch (Exception e) {
+            e.printStackTrace();
+        } finally {
+            if (ossClient != null) {
+                ossClient.shutdown();
+            }
+        }
+    }
+
+    /**
+     * 文件下载(签章系统)
+     * @param key
+     * @param fileName
+     */
+    public byte[] downQzBytesByStream(String key, String fileName){
+        OSSClient ossClient = new OSSClient(endpoint,accessKeyId,accessKeySecret);
+        byte[] bytes = null;
+        BufferedInputStream in = null;
+        ByteArrayOutputStream outputStream = null;
+        log.info("开始从云服务器加载文件,文件名:{}",fileName);
+        try {
+            // 创建OSSClient实例
+            long start = System.currentTimeMillis();
+            OSSObject ossObject = ossClient.getObject(qzBucketName, key);
+            in = new BufferedInputStream(ossObject.getObjectContent());
+            outputStream = new ByteArrayOutputStream();
+            byte[] car=new byte[1024];
+            int L=0;
+            while((L=in.read(car))!=-1){
+                outputStream.write(car, 0,L);
+            }
+            bytes = outputStream.toByteArray();
+            long end = System.currentTimeMillis();
+            log.info("从云服务器加载文件成功,文件名:{},耗时:{}ms",fileName,end-start);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }finally {
+            if (in!=null){
+                try {
+                    in.close();
+                } catch (IOException e) {
+                    e.printStackTrace();
+                }
+            }
+            if (outputStream!=null){
+                try {
+                    outputStream.close();
+                } catch (IOException e) {
+                    e.printStackTrace();
+                }
+            }
+        }
+        return  bytes;
+    }
+
+
+    /**
+     * 附件下载到本地指定文件夹(签章系统)
+     * @param key
+     * @param fileName
+     */
+    public void downQzByStreamSaveLocal(String key, String fileName,String downFileStr){
+        try {
+            // 创建OSSClient实例
+            OSSClient ossClient = new OSSClient(endpoint,accessKeyId,accessKeySecret);
+            OSSObject ossObject = ossClient.getObject(qzBucketName, key);
+            BufferedInputStream in = new BufferedInputStream(ossObject.getObjectContent());
+
+
+            //写入到文件(注意文件保存路径的后面一定要加上文件的名称)
+            FileOutputStream fileOut = new FileOutputStream(downFileStr);
+            BufferedOutputStream bos = new BufferedOutputStream(fileOut);
+            byte[] buf = new byte[4096];
+            int length = in.read(buf);
+            //保存文件
+            while(length != -1)
+            {
+                bos.write(buf, 0, length);
+                length = in.read(buf);
+            }
+            if(bos!=null){
+                bos.flush();
+                bos.close();
+            }
+            if(in!=null){
+                in.close();
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+    /**
+     * 阿里云获取临时文件查看url
+     * 签章文件查看
+     * @param file
+     */
+    public String getQzFileTemporaryLookUrl(String file){
+        URL url = null;
+        try {
+            OSSClient ossClient = new OSSClient(endpoint,accessKeyId,accessKeySecret);
+
+            file = file.replace("amp;","");
+//            String aliyunUrl = Global.getAliyunUrl();
+//            String aliDownloadUrl = Global.getAliDownloadUrl();
+            String cons = "";
+            if (file.contains(aliyunUrl)){
+                cons = aliyunUrl;
+            }else if (file.contains("http://gangwan-app.oss-cn-hangzhou.aliyuncs.com")){
+                cons = "http://gangwan-app.oss-cn-hangzhou.aliyuncs.com";
+            }else {
+//                cons = aliDownloadUrl;
+            }
+            String key = file.split(cons+"/")[1];
+            // 指定过期时间为24小时。
+            Date expiration = new Date(new Date().getTime() + 1000 * 60 * 60 * 24 );
+            url = ossClient.generatePresignedUrl(qzBucketName, key, expiration);
+
+        } catch (Exception e) {
+            e.printStackTrace();
+            return "";
+        }
+        return url.toString();
+    }
+
+
+    public String datePath(){
+        Calendar date = Calendar.getInstance();
+        String year = String.valueOf(date.get(Calendar.YEAR));
+        String month = String.valueOf(date.get(Calendar.MONTH)+1);
+        String day = String.valueOf(date.get(Calendar.DAY_OF_MONTH));
+        String path = "/"+year+"/"+month+"/"+day;
+        return path;
+    }
+
+    // 文件下载和上传方法
+    public String downloadAndUploadToOSS(String fileUrl,String fileName,String dir) {
+        // 创建OSS客户端
+        OSSClient ossClient = new OSSClient(endpoint,accessKeyId,accessKeySecret);
+
+        InputStream inputStream = null;
+        try {
+            // Step 1: 下载文件
+            inputStream = downloadFile(fileUrl);
+            String realPath =DIRECTORY.replaceFirst("/","")+"/"+ dir +datePath()+"/"+ System.currentTimeMillis();
+            String ret = uploadFile2OSS(inputStream,realPath,fileName);
+            // Step 2: 上传到OSS
+            return "/"+realPath+fileName;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return null;
+        } finally {
+            // 关闭资源
+            try {
+                if (inputStream != null) inputStream.close();
+            } catch (IOException ignored) {}
+            ossClient.shutdown();
+        }
+    }
+    public static InputStream downloadFile(String fileUrl) throws Exception {
+        URL url = new URL(fileUrl);
+        HttpURLConnection connection = (HttpURLConnection) url.openConnection();
+        connection.setRequestMethod("GET");
+        connection.setConnectTimeout(5000);
+        connection.setReadTimeout(5000);
+
+        if (connection.getResponseCode() == 200) {
+            return connection.getInputStream();
+        } else {
+            throw new RuntimeException("Failed to download file, response code: " + connection.getResponseCode());
+        }
+    }
+
+}

+ 954 - 0
jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/oss/service/PsiOssService.java

@@ -0,0 +1,954 @@
+package com.jeeplus.psimanage.oss.service;
+
+import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.extra.spring.SpringUtil;
+import com.alibaba.fastjson.JSONObject;
+import com.aliyun.oss.HttpMethod;
+import com.aliyun.oss.OSSClient;
+import com.aliyun.oss.model.GeneratePresignedUrlRequest;
+import com.aliyun.oss.model.OSSObject;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.jeeplus.psimanage.oss.domain.PsiWorkAttachment;
+import com.jeeplus.psimanage.oss.mapper.PsiOssServiceMapper;
+import com.jeeplus.psimanage.oss.service.dto.AttachmentDTO;
+import com.jeeplus.psimanage.oss.service.dto.FileDetailDTO;
+import com.jeeplus.psimanage.oss.service.dto.FileUrlDto;
+import com.jeeplus.psimanage.oss.service.dto.WorkAttachmentDto;
+import com.jeeplus.sys.domain.WorkAttachmentInfo;
+import com.jeeplus.sys.feign.IUserApi;
+import com.jeeplus.sys.service.dto.UserDTO;
+import com.jeeplus.sys.service.dto.WorkAttachmentInfoDTO;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+import org.springframework.web.multipart.MultipartFile;
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletResponse;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.net.URL;
+import java.net.URLEncoder;
+import java.util.*;
+import java.util.stream.Collectors;
+
+@Slf4j
+@Service
+public class PsiOssService extends ServiceImpl<PsiOssServiceMapper, PsiWorkAttachment> {
+
+    @Value("${config.accessory.aliyun.aliyunUrl}")
+    private String aliyunUrl;
+
+    @Value("${config.accessory.aliyun.aliyunDownloadUrl}")
+    private String aliyunDownloadUrl;
+
+    @Value("${config.accessory.aliyun.endpoint}")
+    private String endpoint;
+
+    @Value("${config.accessory.aliyun.accessKeyId}")
+    private String accessKeyId;
+
+    @Value("${config.accessory.aliyun.accessKeySecret}")
+    private String accessKeySecret;
+
+    @Value("${config.accessory.aliyun.bucketName}")
+    private String bucketName;
+
+    @Resource
+    private PsiOssServiceMapper psiOssServiceMapper;
+
+    @Value("${aliyun_directory}")
+    private String directory = "attachment-file/assess";
+
+    @Resource
+    private PsiOSSClientService psiOssClientService;
+
+    public void insertWorkAttachment (PsiWorkAttachment psiWorkAttachment, UserDTO userDto){
+        psiOssServiceMapper.insertWorkAttachment(psiWorkAttachment, userDto);
+    }
+
+
+    /**
+     * 保存数据
+     * @param psiWorkAttachments
+     * @return
+     */
+    public void saveMsg(List<PsiWorkAttachment> psiWorkAttachments, String currentToken) {
+//        String currentToken = TokenProvider.getCurrentToken();
+        if (CollectionUtil.isNotEmpty(psiWorkAttachments)) {
+            //获取当前登录人信息
+            String id = SpringUtil.getBean ( IUserApi.class ).getByToken (currentToken).getId();
+            int i = 1;
+            for (PsiWorkAttachment psiWorkAttachment : psiWorkAttachments) {
+                //判断文件是否存在
+                /*LambdaQueryWrapper<WorkAttachment> lambdaQueryWrapper = new LambdaQueryWrapper<>();
+                lambdaQueryWrapper.eq(WorkAttachment::getUrl, workAttachment.getUrl());
+                lambdaQueryWrapper.eq(WorkAttachment::getAttachmentId, workAttachment.getAttachmentId());*/
+                WorkAttachmentInfo workAttachmentInfo = new WorkAttachmentInfo();
+                workAttachmentInfo.setUrl(psiWorkAttachment.getUrl());
+                workAttachmentInfo.setAttachmentId(psiWorkAttachment.getAttachmentId());
+                List<WorkAttachmentInfo> list = psiOssServiceMapper.getByAttachmentIdAndUrlAndAttachmentFlag(workAttachmentInfo);
+                if (CollectionUtil.isNotEmpty(list)) {
+                    i++;
+                    continue;
+                }
+                log.info("开始执行保存操作,入参:{}" , JSONObject.toJSONString(psiWorkAttachments));
+                //文件后缀名赋值
+                List<String> strings = Arrays.asList(psiWorkAttachment.getUrl().split("\\."));
+                psiWorkAttachment.setType(strings.get(strings.size()-1));
+                psiWorkAttachment.setId(UUID.randomUUID().toString().replace("-",""));
+                //排序赋值
+                psiWorkAttachment.setSort(i);
+                //基础信息赋值
+                //workAttachment.getCreateBy().setId(id);
+                psiWorkAttachment.setCreateTime(new Date());
+                //workAttachment.getUpdateBy().setId(id);
+                psiWorkAttachment.setUpdateTime(new Date());
+                psiWorkAttachment.setDelFlag(0);
+                i++;
+
+                UserDTO userDTO = SpringUtil.getBean ( IUserApi.class ).getByToken (currentToken);
+                psiOssServiceMapper.insertWorkAttachment(psiWorkAttachment, userDTO);
+            }
+
+
+            log.info("保存操作执行完成");
+        }
+    }
+
+    /**
+     * 根据文件路径删除文件
+     * @param url
+     */
+    public void deleteMsgByFileName(String url) {
+        log.info("开始执行删除操作,入参:{}" , url);
+        Map<String,Object> map = new HashMap<>();
+        map.put("url", url);
+        int i = psiOssServiceMapper.deleteByMap(map);
+        log.info("删除操作完成,共删除{}条数据" , i);
+    }
+
+    /**
+     * 根据id删除数据
+     * @param id
+     */
+    public void deleteMsgById(String id) {
+        log.info("开始执行删除操作,入参:{}" , id);
+        Map<String,Object> map = new HashMap<>();
+        map.put("id", id);
+        int i = psiOssServiceMapper.deleteById(id);
+        //项目文件删除后处理项目文件状态
+        Integer num = psiOssServiceMapper.selectSaveById(id);
+        if (num == 0) {
+            psiOssServiceMapper.updateProjectRecord(id);
+        }
+        log.info("删除操作完成,共删除{}条数据" , i);
+    }
+
+    /**
+     * 根据附件对应父节点id查询文件列表
+     * @param attachmentId
+     * @return
+     */
+    public List<AttachmentDTO> findFileList(String attachmentId) {
+
+        log.info("文件查询开始,入参:{}" , attachmentId);
+        QueryWrapper<PsiWorkAttachment> queryWrapper = new QueryWrapper<>();
+        queryWrapper.eq ("a.attachment_id", attachmentId );
+        queryWrapper.eq ("a.del_flag", "0" );
+        List<AttachmentDTO> list = psiOssServiceMapper.findList(queryWrapper);
+        //创建人和文件名称处理
+        if (CollectionUtil.isNotEmpty(list)) {
+            temporaryUrl(list);
+        }
+        log.info("文件查询结束,查询结果:{}" , JSONObject.toJSONString(list));
+        return list;
+    }
+
+    /**
+     * 生成临时文件
+     * @param list
+     * @return
+     */
+    public List<AttachmentDTO> temporaryUrl(List<AttachmentDTO> list) {
+        list.stream().forEach(work -> {
+            String url = null;
+            if (StringUtils.isNotEmpty(work.getUrl())) {
+                url = aliyunUrl + work.getUrl();
+                work.setTemporaryUrl(getFileTemporaryLookUrl(url));
+            }
+
+            //对文件大小进行处理
+            if(StringUtils.isBlank(work.getFileSize())){
+                work.setFileSize("0");
+            }
+            if(StringUtils.isNotBlank(work.getFileSize())){
+                Long fileSizeBytes = Long.parseLong(work.getFileSize());
+                //如果数据库文件大小小于等于0, 则访问阿里云获取文件大小
+                fileSizeBytes = 0L;
+                if (fileSizeBytes<=0){
+                    fileSizeBytes = psiOssClientService.getSimplifiedObjectMeta(url);
+                }
+
+                if(null != fileSizeBytes){
+                    Double fileSize = (double)fileSizeBytes/1024/1024;
+                    work.setFileSize(String.format("%.2f", fileSize));
+                }else{
+                    work.setFileSize("0.00");
+                }
+            }
+        });
+        return list;
+    }
+
+    /**
+     * 根据文件路径获取文件信息
+     * @param url
+     * @return
+     */
+    public FileDetailDTO getFileSizeByUrl(String url){
+        FileDetailDTO fileDetailDTO = new FileDetailDTO();
+        fileDetailDTO.setUrl(getFileTemporaryLookUrl(aliyunUrl + url));
+        Long fileSizeBytes = psiOssClientService.getSimplifiedObjectMeta(aliyunUrl + url);
+        if(null != fileSizeBytes){
+            Double fileSize = (double)fileSizeBytes;
+            fileDetailDTO.setSize(String.format("%.2f", fileSize));
+        }else{
+            fileDetailDTO.setSize("0");
+        }
+        return fileDetailDTO;
+    }
+
+
+    /**
+     * 根据文件路径获取文件信息
+     * @param url
+     * @return
+     */
+    public FileDetailDTO getSFZSizeByUrl(String url){
+        FileDetailDTO fileDetailDTO = new FileDetailDTO();
+        fileDetailDTO.setUrl(getFileTemporaryLookUrlWithWatermark(aliyunUrl + url));
+        Long fileSizeBytes = psiOssClientService.getSimplifiedObjectMeta(aliyunUrl + url);
+        if(null != fileSizeBytes){
+            Double fileSize = (double)fileSizeBytes;
+            fileDetailDTO.setSize(String.format("%.2f", fileSize));
+        }else{
+            fileDetailDTO.setSize("0");
+        }
+        return fileDetailDTO;
+    }
+
+
+    /**
+     * 阿里云获取临时文件查看url
+     * @param url
+     */
+    public String getFileTemporaryLookUrl(String url){
+        url = url.replace("amp;","");
+        String cons = "";
+        if (url.contains(aliyunUrl)){
+            cons = aliyunUrl;
+        }else if (url.contains("http://gangwan-app.oss-cn-hangzhou.aliyuncs.com")){
+            cons = "http://gangwan-app.oss-cn-hangzhou.aliyuncs.com";
+        }else {
+            cons = aliyunDownloadUrl;
+        }
+        String key = "";
+        String[] split = url.split(cons + "/");
+        if(split.length>1){
+            key = split[1];
+        }else{
+            key = url;
+        }
+        // 指定过期时间为24小时。
+        Date expiration = new Date(new Date().getTime() + 1000 * 60 * 60 * 24 );
+        //初始化OSSClient
+        OSSClient ossClient = new OSSClient(endpoint,accessKeyId,accessKeySecret);
+        return ossClient.generatePresignedUrl(bucketName, key, expiration).toString();
+    }
+
+    /**
+     * 缩略图
+     * 获取阿里云 OSS 上图片的缩略图临时访问地址
+     * @param file 图片完整路径(包含 http(s)://)
+     * @return 带缩略图样式的临时URL
+     */
+    public String getThumbnailTemporaryLookUrl(String file) {
+        try {
+            file = file.replace("amp;", "");
+            String cons;
+
+            if (file.contains(aliyunUrl)) {
+                cons = aliyunUrl;
+            } else if (file.contains("http://gangwan-app.oss-cn-hangzhou.aliyuncs.com")) {
+                cons = "http://gangwan-app.oss-cn-hangzhou.aliyuncs.com";
+            } else {
+                cons = aliyunDownloadUrl;
+            }
+
+            // 获取 key(即 OSS 路径)
+            String key = file.split(cons + "/")[1];
+
+            // 设置过期时间(24小时)
+            Date expiration = new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 24);
+
+            // 设置图片处理参数,这里按宽度200缩放
+            GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(bucketName, key, HttpMethod.GET);
+            request.setExpiration(expiration);
+            request.setProcess("image/resize,w_200"); // ✅ 这里是关键:缩略图处理样式
+
+            //初始化OSSClient
+            OSSClient ossClient = new OSSClient(endpoint,accessKeyId,accessKeySecret);
+            // 生成带签名的URL
+            URL url = ossClient.generatePresignedUrl(request);
+            return url.toString();
+
+        } catch (Exception e) {
+            e.printStackTrace();
+            return "";
+        }
+    }
+
+    /**
+     * 带水印、虚化原图(水印旋转45度)
+     * 阿里云获取临时文件查看url(带水印)
+     * @param file OSS 文件完整 URL
+     * @return 带临时访问权限的 URL
+     */
+    public String getFileTemporaryLookUrlWithWatermark(String file) {
+        try {
+            file = file.replace("amp;", "");
+
+            String cons;
+            if (file.contains(aliyunUrl)) {
+                cons = aliyunUrl;
+            } else if (file.contains("http://gangwan-app.oss-cn-hangzhou.aliyuncs.com")) {
+                cons = "http://gangwan-app.oss-cn-hangzhou.aliyuncs.com";
+            } else {
+                cons = aliyunDownloadUrl;
+            }
+
+            String key = file.split(cons + "/")[1];
+
+            // 过期时间 24 小时
+            Date expiration = new Date(System.currentTimeMillis() + 1000L * 60 * 60 * 24);
+
+            // 构建预签名请求(带水印)
+            GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(bucketName, key, HttpMethod.GET);
+
+            String text = "仅用于公司人员信息备案,其他用途无效";
+            // 将字符串转为 UTF-8 字节
+            byte[] bytes = text.getBytes(java.nio.charset.StandardCharsets.UTF_8);
+
+            // 使用 URL Safe Base64 编码
+            String base64Text = Base64.getUrlEncoder().withoutPadding().encodeToString(bytes);
+
+            // 设置水印参数:中间 g_center,红色 FF0000,字号 40
+            String imageProcess = "image/blur,r_50,s_5" + "/watermark,text_" + base64Text + ",color_FF0000,size_40,g_center,rotate_45";
+
+            request.setProcess(imageProcess);
+
+            request.setExpiration(expiration);
+
+            //初始化OSSClient
+            OSSClient ossClient = new OSSClient(endpoint,accessKeyId,accessKeySecret);
+            URL url = ossClient.generatePresignedUrl(request);
+            return url.toString();
+
+        } catch (Exception e) {
+            e.printStackTrace();
+            return "";
+        }
+    }
+
+
+    /**
+     * 带水印、虚化、缩略图(水印旋转45度)
+     * 获取阿里云 OSS 上图片的缩略图临时访问地址(带水印、缩略图、图片虚化)
+     * @param file 图片完整路径(包含 http(s)://)
+     * @return 带缩略图样式的临时URL
+     */
+    public String getThumbnailTemporaryWithWatermarkDimLookUrl(String file) {
+        try {
+            file = file.replace("amp;", "");
+
+            String cons;
+
+            if (file.contains(aliyunUrl)) {
+                cons = aliyunUrl;
+            } else if (file.contains("http://gangwan-app.oss-cn-hangzhou.aliyuncs.com")) {
+                cons = "http://gangwan-app.oss-cn-hangzhou.aliyuncs.com";
+            } else {
+                cons = aliyunDownloadUrl;
+            }
+
+            // 获取 key(即 OSS 路径)
+            String key = file.split(cons + "/")[1];
+
+            // 设置过期时间(24小时)
+            Date expiration = new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 24);
+
+            // 设置图片处理参数,这里按宽度200缩放
+            GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(bucketName, key, HttpMethod.GET);
+            request.setExpiration(expiration);
+
+            String text = "仅用于公司人员信息备案,其他用途无效";
+            // 将字符串转为 UTF-8 字节
+            byte[] bytes = text.getBytes(java.nio.charset.StandardCharsets.UTF_8);
+
+            // 使用 URL Safe Base64 编码
+            String base64Text = Base64.getUrlEncoder().withoutPadding().encodeToString(bytes);
+
+            String imageProcess = "image/blur,r_50,s_5" + "/watermark,text_" + base64Text + ",color_FF0000,size_40,g_center,rotate_45"+ "/resize,w_200";
+
+            request.setProcess(imageProcess);
+
+            //初始化OSSClient
+            OSSClient ossClient = new OSSClient(endpoint,accessKeyId,accessKeySecret);
+            // 生成带签名的URL
+            URL url = ossClient.generatePresignedUrl(request);
+            return url.toString();
+
+        } catch (Exception e) {
+            e.printStackTrace();
+            return "";
+        }
+    }
+
+
+    /**
+     * 附件下载
+     * @param key
+     * @param fileName
+     * @param response
+     */
+    public void downByStream(String key, String fileName, HttpServletResponse response, String agent){
+        try {
+            String newName = URLEncoder.encode(fileName, "UTF-8").replaceAll("\\+", "%20").replaceAll("%28", "\\(").replaceAll("%29", "\\)").replaceAll("%3B", ";").replaceAll("%40", "@").replaceAll("%23", "\\#").replaceAll("%26", "\\&").replaceAll("%2C", "\\,");
+            // 创建OSSClient实例
+            //初始化OSSClient
+            OSSClient ossClient = new OSSClient(endpoint,accessKeyId,accessKeySecret);
+            OSSObject ossObject = ossClient.getObject(bucketName, key);
+            BufferedInputStream in = new BufferedInputStream(ossObject.getObjectContent());
+            BufferedOutputStream out = new BufferedOutputStream(response.getOutputStream());
+            response.setHeader("Content-Disposition","attachment;filename*=UTF-8''"+ newName);
+
+            /*if(agent != null && agent.toLowerCase().indexOf("firefox") > 0){
+                response.setHeader("Content-Disposition", "attachment; filename*=UTF-8''"+ URLEncoder.encode(fileName,"utf-8"));
+            }else {
+                response.setHeader("Content-Disposition","attachment;filename="+ URLEncoder.encode(fileName,"utf-8"));
+            }*/
+            byte[] car=new byte[1024];
+            int L=0;
+            while((L=in.read(car))!=-1){
+                out.write(car, 0,L);
+            }
+            if(out!=null){
+                out.flush();
+                out.close();
+            }
+            if(in!=null){
+                in.close();
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+    /**
+     * 上传文件
+     * @param file
+     * @param dir 存放文件夹名称
+     * @return
+     * @throws Exception
+     */
+    public FileUrlDto webUpload(MultipartFile file, String dir) throws IOException {
+        FileUrlDto dto = new FileUrlDto();
+        // 文件保存路径
+        String fileDir =directory+"/"+dir+ psiOssClientService.datePath()+"/"+ System.currentTimeMillis();
+        // 判断文件是否为空
+        if (!file.isEmpty()) {
+            String name = file.getOriginalFilename ();
+            psiOssClientService.uploadFile2OSS(file.getInputStream(), fileDir, name);
+            String url = fileDir +name;
+            String lsUrl = this.getFileTemporaryLookUrl(aliyunUrl + "/" + fileDir +name);
+            dto.setUrl(url);
+            dto.setLsUrl(lsUrl);
+        }
+        return dto;
+    }
+
+    /**
+     * 保存/修改附件
+     * @param fileList 要保存的附件,传空值则删除attachmentId下的所有附件
+     * @param attachmentId 附件的attachmentId
+     * @param attachmentFlag 附件的attachmentFlag
+     */
+    public void saveOrUpdateFileList(List<WorkAttachmentDto> fileList, String attachmentId, String attachmentFlag, String currentToken){
+//        String currentToken = TokenProvider.getCurrentToken();
+
+        UserDTO userDTO = SpringUtil.getBean ( IUserApi.class ).getByToken (currentToken);
+        if (CollectionUtil.isNotEmpty(fileList)) {
+            List<String> ids = fileList.stream().filter(item -> {
+                if (StringUtils.isNotBlank(item.getId())) {
+                    return true;
+                }
+                return false;
+            }).map(WorkAttachmentDto::getId).collect(Collectors.toList());
+            if(CollectionUtil.isNotEmpty(ids)){
+                if(StringUtils.isNotBlank(attachmentFlag)){
+                    psiOssServiceMapper.delete(new QueryWrapper<PsiWorkAttachment>().lambda()
+                            .eq(PsiWorkAttachment::getAttachmentId, attachmentId)
+                            .eq(PsiWorkAttachment::getAttachmentFlag, attachmentFlag)
+                            .notIn(PsiWorkAttachment::getId,ids));
+                }else{
+                    psiOssServiceMapper.delete(new QueryWrapper<PsiWorkAttachment>().lambda()
+                            .eq(PsiWorkAttachment::getAttachmentId, attachmentId)
+                            .notIn(PsiWorkAttachment::getId,ids));
+                }
+            }else{
+                if(StringUtils.isNotBlank(attachmentFlag)){
+                    psiOssServiceMapper.delete(new QueryWrapper<PsiWorkAttachment>().lambda()
+                            .eq(PsiWorkAttachment::getAttachmentId, attachmentId)
+                            .eq(PsiWorkAttachment::getAttachmentFlag, attachmentFlag));
+                }else{
+                    psiOssServiceMapper.delete(new QueryWrapper<PsiWorkAttachment>().lambda()
+                            .eq(PsiWorkAttachment::getAttachmentId, attachmentId));
+                }
+            }
+
+            List<WorkAttachmentDto> dtoList = fileList.stream().filter(item -> {
+                if (StringUtils.isNotBlank(item.getId())) {
+                    return false;
+                }
+                return true;
+            }).collect(Collectors.toList());
+
+            this.saveFileList(dtoList, userDTO, attachmentId,attachmentFlag);
+        } else {
+            if(StringUtils.isNotBlank(attachmentFlag)){
+                psiOssServiceMapper.delete(new QueryWrapper<PsiWorkAttachment>().lambda()
+                                .eq(PsiWorkAttachment::getAttachmentId, attachmentId)
+                                .eq(PsiWorkAttachment::getAttachmentFlag, attachmentFlag));
+            }else{
+                psiOssServiceMapper.delete(new QueryWrapper<PsiWorkAttachment>().lambda()
+                        .eq(PsiWorkAttachment::getAttachmentId, attachmentId));
+            }
+
+        }
+    }
+
+    /**
+     * 保存/修改附件
+     * @param fileList 要保存的附件,传空值则删除attachmentId下attachmentFlag下的所有附件
+     * @param attachmentId 附件的attachmentId
+     * @param attachmentFlag 附件的attachmentFlag
+     */
+    public void saveOrUpdateFileListFlag(List<WorkAttachmentInfoDTO> fileList, String attachmentId, String attachmentFlag,String currentToken){
+
+//        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
+//        String bearerToken = authentication.getCredentials().toString();
+
+        UserDTO userDTO = SpringUtil.getBean ( IUserApi.class ).getByToken (currentToken);
+        if (CollectionUtil.isNotEmpty(fileList)) {
+            List<String> ids = fileList.stream().filter(item -> {
+                if (StringUtils.isNotBlank(item.getId())) {
+                    return true;
+                }
+                return false;
+            }).map(WorkAttachmentInfoDTO::getId).collect(Collectors.toList());
+            if(CollectionUtil.isNotEmpty(ids)){
+                psiOssServiceMapper.delete(new QueryWrapper<PsiWorkAttachment>().lambda()
+                        .eq(PsiWorkAttachment::getAttachmentId, attachmentId)
+                        .eq(PsiWorkAttachment::getAttachmentFlag, attachmentFlag)
+                        .notIn(PsiWorkAttachment::getId,ids));
+            }else{
+                psiOssServiceMapper.delete(new QueryWrapper<PsiWorkAttachment>().lambda()
+                        .eq(PsiWorkAttachment::getAttachmentId, attachmentId)
+                        .eq(PsiWorkAttachment::getAttachmentFlag, attachmentFlag));
+            }
+
+            List<WorkAttachmentInfoDTO> dtoList = fileList.stream().filter(item -> {
+                if (StringUtils.isNotBlank(item.getId())) {
+                    return false;
+                }
+                return true;
+            }).collect(Collectors.toList());
+
+            this.saveFileList2(dtoList, userDTO, attachmentId,attachmentFlag);
+        } else {
+            psiOssServiceMapper.delete(new QueryWrapper<PsiWorkAttachment>().lambda().eq(PsiWorkAttachment::getAttachmentId, attachmentId).eq(PsiWorkAttachment::getAttachmentFlag, attachmentFlag));
+        }
+    }
+
+    /**
+     * 保存附件信息
+     * @param list 待保存的附件列表
+     * @param userDTO 当前登录用户
+     * @param attachmentId 关联id
+     */
+    public void saveFileList2(List<WorkAttachmentInfoDTO> list, UserDTO userDTO, String attachmentId,String attachmentFlag) {
+        int sort = 1;
+        for (WorkAttachmentInfoDTO dto : list) {
+            PsiWorkAttachment i = new PsiWorkAttachment();
+            //包含了url、size、name
+            i.setId(UUID.randomUUID().toString().replace("-", ""));
+//            i.getCreateBy().setId(userDTO.getId());
+            i.setCreateTime(new Date());
+//            i.getUpdateBy().setId(userDTO.getId());
+            i.setUpdateTime(new Date());
+            i.setDelFlag(0);
+            i.setUrl(dto.getUrl());
+            //文件类型处理
+            String fileName = dto.getName();
+            List<String> strings = Arrays.asList(fileName.split("\\."));
+            // 检查文件名是否有后缀
+            if (CollectionUtil.isNotEmpty(strings) && strings.size() > 1) {
+                // 获取最后一个部分作为文件类型
+                i.setType(strings.get(strings.size() - 1));
+            } else {
+                // 如果没有后缀或文件名无效,设置一个默认类型或空
+                i.setType("");
+            }
+            i.setAttachmentId(attachmentId);
+            i.setAttachmentName(dto.getName());
+            i.setAttachmentFlag(attachmentFlag);
+            i.setFileSize(dto.getSize());
+            i.setSort(sort);
+            psiOssServiceMapper.insertWorkAttachment(i, userDTO);
+            sort++;
+        }
+    }
+
+    /**
+     * 保存附件信息
+     * @param list 待保存的附件列表
+     * @param userDTO 当前登录用户
+     * @param attachmentId 关联id
+     */
+    public void saveFileList(List<WorkAttachmentDto> list, UserDTO userDTO, String attachmentId,String attachmentFlag) {
+        int sort = 1;
+        for (WorkAttachmentDto dto : list) {
+            PsiWorkAttachment i = new PsiWorkAttachment();
+            //包含了url、size、name
+            i.setId(UUID.randomUUID().toString().replace("-", ""));
+//            i.getCreateBy().setId(userDTO.getId());
+            i.setCreateTime(new Date());
+//            i.getUpdateBy().setId(userDTO.getId());
+            i.setUpdateTime(new Date());
+            i.setDelFlag(0);
+            i.setUrl(dto.getUrl());
+            // 文件类型处理
+            String fileName = dto.getName();
+            List<String> strings = Arrays.asList(fileName.split("\\."));
+            // 检查文件名是否有后缀
+            if (CollectionUtil.isNotEmpty(strings) && strings.size() > 1) {
+                // 获取最后一个部分作为文件类型
+                i.setType(strings.get(strings.size() - 1));
+            } else {
+                // 如果没有后缀或文件名无效,设置一个默认类型或空
+                i.setType("");
+            }
+            i.setAttachmentId(attachmentId);
+            i.setAttachmentName(dto.getName());
+            i.setAttachmentFlag(attachmentFlag);
+            i.setFileSize(dto.getSize());
+            i.setSort(sort);
+            psiOssServiceMapper.insertWorkAttachment(i, userDTO);
+            sort++;
+        }
+    }
+
+    /**
+     * 保存附件信息
+     * @param workAttachmentDto 待保存的附件信息
+     * @param userDTO 当前登录用户
+     * @param attachmentId 关联id
+     * @param attachmentFlag
+     * @param sort
+     */
+    public String saveFile(WorkAttachmentDto workAttachmentDto, UserDTO userDTO, String attachmentId,String attachmentFlag, Integer sort) {
+        PsiWorkAttachment i = new PsiWorkAttachment();
+        //包含了url、size、name
+        i.setId(UUID.randomUUID().toString().replace("-", ""));
+        i.setCreateTime(new Date());
+        i.setUpdateTime(new Date());
+        i.setDelFlag(0);
+        i.setUrl(workAttachmentDto.getUrl());
+        //文件类型处理
+        String fileName = workAttachmentDto.getName();
+        List<String> strings = Arrays.asList(fileName.split("\\."));
+        // 检查文件名是否有后缀
+        if (CollectionUtil.isNotEmpty(strings) && strings.size() > 1) {
+            // 获取最后一个部分作为文件类型
+            i.setType(strings.get(strings.size() - 1));
+        } else {
+            // 如果没有后缀或文件名无效,设置一个默认类型或空
+            i.setType("");
+        }
+        i.setAttachmentId(attachmentId);
+        i.setAttachmentName(workAttachmentDto.getName());
+        i.setAttachmentFlag(attachmentFlag);
+        i.setFileSize(workAttachmentDto.getSize());
+        i.setSort(sort);
+        psiOssServiceMapper.insertWorkAttachment(i, userDTO);
+        return i.getId();
+    }
+
+    public List<WorkAttachmentInfo> selectWorkAttachmentByAttachmentId (String id){
+        return psiOssServiceMapper.selectWorkAttachmentByAttachmentId(id);
+    }
+
+
+    public void deleteById(String id) {
+        psiOssServiceMapper.deleteById(id);
+    }
+
+    /**
+     * 根据attachmentId删除附件
+     * @param attachmentId
+     */
+    public void deleteByAttachmentId(String attachmentId) {
+        psiOssServiceMapper.deleteByAttachmentId(attachmentId);
+    }
+
+    public List<WorkAttachmentInfo> selectListByAttachmentId(String attachmentId) {
+        return psiOssServiceMapper.selectListByAttachmentId(attachmentId);
+    }
+
+    public List<WorkAttachmentInfo> getByAttachmentIdAndUrlAndAttachmentFlag(WorkAttachmentInfo workattachment) {
+
+        return psiOssServiceMapper.getByAttachmentIdAndUrlAndAttachmentFlag(workattachment);
+    }
+
+    public void deleteByAttachmentIdNotInIds(String attachmentId, List<String> delIds) {
+        psiOssServiceMapper.deleteByAttachmentIdNotInIds(attachmentId,delIds);
+    }
+
+
+    public Map<String,Object> downLoadFileDisposeXmlFile(String file) {
+        file = "http://oss.gangwaninfo.com" + file;
+        file = file.replace("amp;", "");
+        String fileName = file.substring(file.lastIndexOf("/") + 1, file.length());
+        String cons = "";
+        if (file.contains(aliyunUrl)) {
+            cons = aliyunUrl;
+        } else if (file.contains("http://gangwan-app.oss-cn-hangzhou.aliyuncs.com")) {
+            cons = "http://gangwan-app.oss-cn-hangzhou.aliyuncs.com";
+        } else {
+            cons = aliyunDownloadUrl;
+        }
+        String key = file.split(cons + "/")[1];
+        log.info("-----------------------------------------");
+        log.info("fileName=" + fileName);
+        log.info("key=" + key);
+        log.info("-----------------------------------------");
+
+        String path = null;
+        if(System.getProperty("os.name").toLowerCase().contains("win")){
+            path = "D:/attachment-file/";
+        }else{
+            path = "/attachment-file/";
+        }
+        psiOssClientService.downByStreamSaveLocal(key, fileName, path+fileName);
+
+        Map<String,Object> map = new HashMap();
+        //创建DOM4J解析器对象
+        File newFile = new File(path + fileName);
+        try {
+            //MultipartFile转File
+            //newFile = FileUtil.transformMultipartFile(file);
+            // 创建一个 DocumentBuilderFactory
+            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+            // 使用工厂创建一个 DocumentBuilder
+            DocumentBuilder builder = factory.newDocumentBuilder();
+            // 使用 DocumentBuilder 解析 XML 文件
+            Document document = builder.parse(newFile);
+            // 获取所有header节点的集合
+            NodeList headerList = document.getElementsByTagName("Header");
+            // 获取所有eInvoiceDataList节点的集合
+            NodeList eInvoiceDataList = document.getElementsByTagName("EInvoiceData");
+            // 获取所有taxSupervisionInfo节点的集合
+            NodeList taxSupervisionInfoList = document.getElementsByTagName("TaxSupervisionInfo");
+
+            Map<String,String> map1 = xmlNodeListDataDispose(headerList, document);
+            Map<String,String> map2 = xmlNodeListDataDispose(eInvoiceDataList, document);
+            Map<String,String> map3 = xmlNodeListDataDispose(taxSupervisionInfoList, document);
+            map.putAll(map1);
+            map.putAll(map2);
+            map.putAll(map3);
+
+        } catch (Exception e) {
+            e.printStackTrace();
+        }finally {
+            newFile.delete();
+        }
+        return map;
+    }
+
+    /**
+     * 对节点集合进行遍历,并获取每个节点下的参数信息
+     * @param nodeList
+     * @param document
+     * @return
+     */
+    public Map<String,String> xmlNodeListDataDispose(NodeList nodeList,Document document){
+        Map<String,String> map = new HashMap<>();
+        if(null != nodeList && nodeList.getLength()>0){
+            //遍历每一个header节点
+            for (int i = 0; i < nodeList.getLength(); i++) {
+                //通过 item(i)方法 获取一个header节点,nodelist的索引值从0开始
+                Node header = nodeList.item(i);
+                //解析定义节点的子节点
+                NodeList childNodes = header.getChildNodes();
+                //节点数据处理
+                Map<String,String> map1 = xmlDataDispose(childNodes, document);
+                map.putAll(map1);
+            }
+        }
+        return map;
+    }
+
+    /**
+     * 子节点遍历获取参数,若其下还有子节点,则循环调用 xmlNodeListDataDispose 方法
+     * @param childNodes
+     * @param document
+     * @return
+     */
+    public Map<String,String> xmlDataDispose(NodeList childNodes,Document document){
+        Map<String,String> map = new HashMap<>();
+        for (int k = 0; k < childNodes.getLength(); k++) {
+            // 区分出text类型的node以及element类型的node
+            if (childNodes.item(k).getNodeType() == Node.ELEMENT_NODE) {
+                Node firstChild = childNodes.item(k).getFirstChild();
+                if(null != firstChild){
+                    if(StringUtils.isBlank(childNodes.item(k).getFirstChild().getNodeValue())){
+                        // 获取所有header节点的集合
+                        NodeList childList = document.getElementsByTagName(childNodes.item(k).getNodeName());
+
+                        String parentName = childNodes.item(k).getNodeName();
+                        //循环调用,获取最低级节点数据信息
+                        Map<String,String> map1 = xmlNodeListDataDispose(childList, document);
+                        Map<String,String> map2 = new HashMap<>();
+                        if(map1.size()>0){
+                            //将获取到的数据进行遍历,添加父节点的参数信息,防止子节点key键相同,导致数据被覆盖
+                            for (String key : map1.keySet()) {
+                                if(key.contains("-")){
+                                    String newKey = key.replaceAll("-","");
+                                    map2.put(parentName + newKey,map1.get(key));
+                                }else{
+                                    map2.put(parentName + key,map1.get(key));
+                                }
+                            }
+                        }
+                        map.putAll(map2);
+                    }
+                    //判定key 和value 值均存在,则进行储存,否则不进行储存
+                    if(StringUtils.isNotBlank(childNodes.item(k).getNodeName()) && StringUtils.isNotBlank(childNodes.item(k).getFirstChild().getNodeValue())){
+                        map.put(childNodes.item(k).getNodeName(),childNodes.item(k).getFirstChild().getNodeValue());
+                    }
+                }
+            }
+        }
+        return map;
+    }
+
+
+
+
+
+
+    /**
+     *
+     * @param attachmentIdList
+     * @param type  代表处理类型,不同类型代表不同的分公司的报销数据:1、评估;2、会计;3、ccpm;4、中审;5、咨询
+     */
+    public Map<String,String> disposeElectronicEngineeringInvoice(List<String> attachmentIdList, String type){
+        Map<String,String> map = new HashMap<>();
+        //首先获取所有数电发票报销信息
+        List<WorkAttachmentInfo> attachmentList = psiOssServiceMapper.getElectronicEngineeringInvoiceAttachmentList(attachmentIdList,"");
+        //遍历所有附件发票信息,并将其下载到本地固定文件夹,并对下载的文件进行数据解析
+        try{
+            for (WorkAttachmentInfo attachmentInfo : attachmentList) {
+                if(attachmentInfo.getUrl().contains(".xml")){
+                    Map<String, Object> stringObjectMap = this.downLoadFileDisposeXmlFile(attachmentInfo.getUrl());
+                    String invoiceNumber = (String) stringObjectMap.get("InvoiceNumber");
+                    String buyerInformationBuyerName = (String) stringObjectMap.get("BuyerInformationBuyerName");
+                    if(StringUtils.isNotBlank(invoiceNumber) && StringUtils.isNotBlank(buyerInformationBuyerName)){
+                        map.put(invoiceNumber,buyerInformationBuyerName);
+                    }
+                }
+            }
+        } catch (Exception e) {
+            e.getMessage();
+        }
+        return map;
+    }
+
+    /**
+     *
+     * @param attachmentIdList
+     * @param type  代表处理类型,不同类型代表不同的分公司的报销数据:1、评估;2、会计;3、ccpm;4、中审;5、咨询
+     */
+    public Map<String,String> disposeElectronicEngineeringInvoiceNumber(List<String> attachmentIdList, String type){
+        Map<String,String> map = new HashMap<>();
+        //首先获取所有数电发票报销信息
+        List<WorkAttachmentInfo> attachmentList = psiOssServiceMapper.getElectronicEngineeringInvoiceAttachmentList(attachmentIdList,"");
+        //遍历所有附件发票信息,并将其下载到本地固定文件夹,并对下载的文件进行数据解析
+        try{
+            for (WorkAttachmentInfo attachmentInfo : attachmentList) {
+                if(attachmentInfo.getUrl().contains(".xml")){
+                    Map<String, Object> stringObjectMap = this.downLoadFileDisposeXmlFile(attachmentInfo.getUrl());
+                    if (stringObjectMap != null){
+                        String invoiceNumber = (String) stringObjectMap.get("InvoiceNumber");
+                        String buyerInformationBuyerName = (String) stringObjectMap.get("BuyerInformationBuyerName");
+                        if(StringUtils.isNotBlank(invoiceNumber) && StringUtils.isNotBlank(buyerInformationBuyerName)){
+                            map.put(invoiceNumber,attachmentInfo.getUrl());
+                        }
+                    }
+
+                }
+            }
+        } catch (Exception e) {
+            e.getMessage();
+        }
+        return map;
+    }
+
+    /**
+     * 根据发票号查询该发票是否已经被报销
+     * @param invoiceNumber
+     * @return
+     */
+    public Boolean isUsedByInvoiceNumber(String invoiceNumber) {
+        Integer data = psiOssServiceMapper.isUsedByInvoiceNumber(invoiceNumber);
+        if (data != 0){
+            //被报销
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * 查询资质附件
+     * @param id
+     * @return
+     */
+    public List<WorkAttachmentInfoDTO> findAttachement(String id, String attachmentFlag) {
+        return psiOssServiceMapper.findDtos(id, attachmentFlag);
+    }
+
+
+    public List<WorkAttachmentInfo> getByAttachmentIdListAndFlag (List<String> ids){
+        return psiOssServiceMapper.getByAttachmentIdListAndFlag(ids);
+    }
+}

+ 67 - 0
jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/oss/service/dto/AttachmentDTO.java

@@ -0,0 +1,67 @@
+package com.jeeplus.psimanage.oss.service.dto;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.jeeplus.core.domain.BaseEntity;
+import com.jeeplus.core.service.dto.BaseDTO;
+import lombok.Data;
+
+@Data
+public class AttachmentDTO extends BaseDTO {
+
+    /**
+     * 附件地址
+     */
+    private String url;
+
+    /**
+     * 文件类型(文件后缀名)
+     */
+    private String type;
+
+    /**
+     * 附件对应父节点id(记录是谁的id)
+     */
+    private String attachmentId;
+
+    /**
+     * 文件名
+     */
+    private String attachmentName;
+
+    /**
+     * 文件所属业务模块(数据字典配置)
+     */
+    private String attachmentFlag;
+
+    /**
+     * 所属模块子模块
+     */
+    private String moduleType;
+
+    /**
+     * 附件类型
+     */
+    private String attachmentType;
+
+    /**
+     * 附件大小
+     */
+    private String fileSize;
+
+    /**
+     * 排序
+     */
+    private Integer sort;
+
+    /**
+     * 文件描述
+     */
+    private String description;
+
+    /**
+     * 附件临时地址
+     *该属性不是实体字段
+     */
+    private String temporaryUrl;
+}

+ 12 - 0
jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/oss/service/dto/DownToOssDTO.java

@@ -0,0 +1,12 @@
+package com.jeeplus.psimanage.oss.service.dto;
+
+import lombok.Data;
+
+@Data
+public class DownToOssDTO {
+
+    private String url;
+    private String dir;
+    private String fileName;
+
+}

+ 11 - 0
jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/oss/service/dto/FileDetailDTO.java

@@ -0,0 +1,11 @@
+package com.jeeplus.psimanage.oss.service.dto;
+
+import lombok.Data;
+
+@Data
+public class FileDetailDTO {
+
+    private String url;
+
+    private String size;
+}

+ 12 - 0
jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/oss/service/dto/FileUrlDto.java

@@ -0,0 +1,12 @@
+package com.jeeplus.psimanage.oss.service.dto;
+
+import lombok.Data;
+
+@Data
+public class FileUrlDto {
+
+    private String url;
+
+    private String lsUrl;
+
+}

+ 6 - 0
jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/oss/service/dto/OssServiceDto.java

@@ -0,0 +1,6 @@
+package com.jeeplus.psimanage.oss.service.dto;
+
+import com.jeeplus.psimanage.oss.domain.PsiWorkAttachment;
+
+public class OssServiceDto extends PsiWorkAttachment {
+}

+ 20 - 0
jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/oss/service/dto/WorkAttachmentDto.java

@@ -0,0 +1,20 @@
+package com.jeeplus.psimanage.oss.service.dto;
+
+import com.jeeplus.core.service.dto.BaseDTO;
+import com.jeeplus.sys.service.dto.UserDTO;
+import lombok.Data;
+
+@Data
+public class WorkAttachmentDto extends BaseDTO {
+
+    private String name;
+
+    private String size;
+
+    private String url;
+
+    private UserDTO createBy;
+
+    private String by;
+
+}

+ 53 - 0
jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/oss/utils/FileUtil.java

@@ -0,0 +1,53 @@
+package com.jeeplus.psimanage.oss.utils;
+
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.*;
+
+/**
+ * @author: 徐滕
+ * @version: 2023-10-30 10:43
+ */
+public class FileUtil {
+
+    /**
+     * MultipartFile转File
+     * @param file
+     * @return
+     * @throws IOException
+     */
+    public static File transformMultipartFile(MultipartFile file) throws IOException {
+        File srcFile = null;
+        //MultipartFile转File
+        if (file.equals("") || file.getSize() <= 0) {
+            file = null;
+        } else {
+            InputStream ins = null;
+            ins = file.getInputStream();
+            srcFile = new File(file.getOriginalFilename());
+            inputStreamToFile(ins, srcFile);
+            ins.close();
+        }
+        return srcFile;
+    }
+
+    /**
+     * 获取流文件
+     * @param ins
+     * @param file
+     */
+    public static void inputStreamToFile(InputStream ins, File file) {
+        try {
+            OutputStream os = new FileOutputStream(file);
+            int bytesRead = 0;
+            byte[] buffer = new byte[8192];
+            while ((bytesRead = ins.read(buffer, 0, 8192)) != -1) {
+                os.write(buffer, 0, bytesRead);
+            }
+            os.close();
+            ins.close();
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+}

+ 354 - 0
jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/psiWareHouse/controller/PsiWareHouseController.java

@@ -0,0 +1,354 @@
+package com.jeeplus.psimanage.psiWareHouse.controller;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.jeeplus.common.excel.EasyExcelUtils;
+import com.jeeplus.common.excel.ExcelOptions;
+import com.jeeplus.common.excel.annotation.ExportMode;
+import com.jeeplus.common.utils.ResponseUtil;
+import com.jeeplus.logging.annotation.ApiLog;
+import com.jeeplus.logging.constant.enums.LogTypeEnum;
+import com.jeeplus.psimanage.psiWareHouse.service.dto.PsiWareSummaryExportDto;
+import com.jeeplus.psimanage.purchase.service.PsiMaterialService;
+import com.jeeplus.psimanage.purchase.service.dto.PsiMaterialInfoDto;
+import com.jeeplus.psimanage.psiWareHouse.domain.PsiWareHouseDetailed;
+import com.jeeplus.psimanage.psiWareHouse.domain.PsiWarehouseUpHi;
+import com.jeeplus.psimanage.psiWareHouse.service.PsiWareHouseBasicService;
+import com.jeeplus.psimanage.psiWareHouse.service.dto.PsiWareHouseDto;
+import com.jeeplus.psimanage.psiWareHouse.service.dto.PsiWareHouseExportDto;
+import com.jeeplus.utils.StringUtils;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletResponse;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+/**
+ * @author: 王强
+ * @create: 2022-12-29 14:13
+ **/
+@RestController
+@Api(tags ="进销存-入库")
+@RequestMapping(value = "/psi/management/wareHouse")
+public class PsiWareHouseController {
+
+    @Resource
+    private PsiMaterialService service;
+
+    @Resource
+    private PsiWareHouseBasicService basicService;
+
+    /**
+     * 根据id修改状态值status
+     * @param dto
+     * @return
+     */
+    @ApiOperation(value = "根据id修改状态值status")
+    @PostMapping(value = "/updateStatusById")
+    public ResponseEntity<String> updateStatusById(@RequestBody PsiWareHouseDto dto) {
+        String s = basicService.updateStatusById(dto);
+        return ResponseEntity.ok(s);
+    }
+
+    /**
+     * 删除
+     * @param id
+     * @return
+     */
+    @ApiOperation(value = "删除")
+    @GetMapping("/remove")
+    public ResponseEntity<String> remove(@RequestParam String id){
+        String s = basicService.remove(id);
+        return ResponseEntity.ok(s);
+    }
+
+    /**
+     * 采购编号列表查询
+     * @param dto
+     * @return
+     */
+    @ApiOperation(value = "采购编号列表查询")
+    @GetMapping("/list")
+    public ResponseEntity<IPage<PsiMaterialInfoDto>> list(Page<PsiMaterialInfoDto> page, PsiMaterialInfoDto dto) throws Exception{
+        IPage<PsiMaterialInfoDto> iPage = service.list(page, dto);
+        return ResponseEntity.ok(iPage);
+    }
+
+    /**
+     * 采购编号列表查询
+     * @param dto
+     * @return
+     */
+    @ApiOperation(value = "采购编号列表查询(报销使用)")
+    @GetMapping("/reimbursementList")
+    public ResponseEntity<IPage<PsiMaterialInfoDto>> reimbursementList(Page<PsiMaterialInfoDto> page, PsiMaterialInfoDto dto) throws Exception{
+        IPage<PsiMaterialInfoDto> iPage = service.reimbursementList(page, dto);
+        return ResponseEntity.ok(iPage);
+    }
+
+
+    /**
+     * 入库列表查询
+     * @param dto
+     * @return
+     */
+    @ApiOperation(value = "入库列表查询")
+    @GetMapping("/wareHouseList")
+    public ResponseEntity<IPage<PsiWareHouseDto>> wareHouseList(Page<PsiWareHouseDto> page, PsiWareHouseDto dto) throws Exception{
+        IPage<PsiWareHouseDto> iPage = basicService.list(page, dto);
+        return ResponseEntity.ok(iPage);
+    }
+
+    @ApiLog(value = "导出入库数据", type = LogTypeEnum.EXPORT)
+    @ApiOperation(value = "导出入库数据")
+    @GetMapping("/exportFile")
+    public void exportFile(Page<PsiWareHouseDto> page, PsiWareHouseDto dto, ExcelOptions options, HttpServletResponse response) throws Exception{
+        String fileName = options.getFilename();
+        String sheetName = options.getSheetName();
+        List<PsiWareHouseExportDto> result;
+        if (ExportMode.current.equals(options.getMode())) {
+            result = basicService.exportList(page, dto);
+        } else if (ExportMode.selected.equals(options.getMode())) {
+            result = basicService.exportList(page, dto).stream().filter(item ->
+                    options.getSelectIds().contains(item.getId())
+            ).collect(Collectors.toList());
+        } else {
+            page.setSize(-1);
+            page.setCurrent(0);
+            result = basicService.exportList(page, dto);
+        }
+        EasyExcelUtils.newInstance().exportExcel(result, sheetName, PsiWareHouseExportDto.class, fileName, null, response);
+    }
+
+    /**
+     * 入库记录查询
+     * @param dto
+     * @return
+     */
+    @ApiOperation(value = "入库记录查询")
+    @GetMapping("/wareHouseHistoryList")
+    public ResponseEntity<IPage<PsiWareHouseDto>> wareHouseHistoryList(Page<PsiWareHouseDto> page, PsiWareHouseDto dto) throws Exception{
+        IPage<PsiWareHouseDto> iPage = basicService.wareHouseHistoryList(page, dto);
+        return ResponseEntity.ok(iPage);
+    }
+
+    /**
+     * 领用记录查询
+     * @param dto
+     * @return
+     */
+    @ApiOperation(value = "领用记录查询")
+    @GetMapping("/collectHistoryList")
+    public ResponseEntity<IPage<PsiWareHouseDto>> collectHistoryList(Page<PsiWareHouseDto> page, PsiWareHouseDto dto) throws Exception{
+        IPage<PsiWareHouseDto> iPage = basicService.collectHistoryList(page, dto);
+        return ResponseEntity.ok(iPage);
+    }
+
+    /**
+     * 入库汇总列表查询
+     * @param dto
+     * @return
+     */
+    @ApiOperation(value = "入库汇总列表查询")
+    @GetMapping("/wareHouseSummaryList")
+    public ResponseEntity<IPage<PsiWareHouseDto>> wareHouseSummaryList(Page<PsiWareHouseDto> page, PsiWareHouseDto dto) throws Exception{
+        IPage<PsiWareHouseDto> iPage = basicService.summaryList(page, dto);
+        return ResponseEntity.ok(iPage);
+    }
+
+    /**
+     * 入库汇总列表查询只展示小于等于5的数据
+     * @param dto
+     * @return
+     */
+    @ApiOperation(value = "入库汇总列表查询只展示小于等于5的数据")
+    @GetMapping("/wareHouseSummaryList2")
+    public ResponseEntity<IPage<PsiWareHouseDto>> wareHouseSummaryList2(Page<PsiWareHouseDto> page, PsiWareHouseDto dto) throws Exception{
+        IPage<PsiWareHouseDto> iPage = basicService.summaryList2(page, dto);
+        return ResponseEntity.ok(iPage);
+    }
+
+    /**
+     * 根据商品名,分类,按照生产日期分组查询列表数据
+     * @param dto
+     * @return
+     */
+    @ApiOperation(value = "根据商品名,分类,按照生产日期分组查询列表数据")
+    @GetMapping("/getByProduceDateAndNameGroup")
+    public ResponseEntity<IPage<PsiWareHouseDto>> getByProduceDateAndNameGroup(Page<PsiWareHouseDto> page, PsiWareHouseDto dto) throws Exception{
+        IPage<PsiWareHouseDto> iPage = basicService.getByProduceDateAndName(page, dto);
+        return ResponseEntity.ok(iPage);
+    }
+
+
+    /**
+     * 根据商品名,分类,按照生产日期分组查询列表数据,不合并数据
+     * @param dto
+     * @return
+     */
+    @ApiOperation(value = "根据商品名,分类,按照生产日期分组查询列表数据,不合并数据")
+    @GetMapping("/getByProduceDateNotMerge")
+    public ResponseEntity<IPage<PsiWareHouseDto>> getByProduceDateNotMerge(Page<PsiWareHouseDto> page, PsiWareHouseDto dto) throws Exception{
+        IPage<PsiWareHouseDto> iPage = basicService.getByProduceDateNotMerge(page, dto);
+        return ResponseEntity.ok(iPage);
+    }
+
+
+
+    /**
+     * 新增/修改
+     * @param dto
+     * @return
+     */
+    @ApiOperation(value = "新增、修改")
+    @PostMapping("/save")
+    public ResponseEntity save(@RequestBody PsiWareHouseDto dto) throws Exception{
+        String id = basicService.save(dto);
+        return ResponseUtil.newInstance().add("businessTable", "psi_management_warehouse_basics").add("businessId", id).ok ("操作成功");
+    }
+
+
+    @ApiOperation(value = "流程终止、取消修改")
+    @GetMapping("/backSourceData")
+    public ResponseEntity<Map<String, String>> backSourceData(String id){
+        Map<String, String> map = basicService.backSourceData(id);
+        return ResponseEntity.ok(map);
+    }
+
+    /**
+     * 查询
+     * @param id
+     * @return
+     */
+    @ApiOperation(value = "查询")
+    @GetMapping("/findById")
+    public ResponseEntity<PsiWareHouseDto> findById(@RequestParam String id, @RequestParam(required = false) String status) throws Exception{
+        if (StringUtils.isBlank(status)) {
+            status = "false";
+        }
+        PsiWareHouseDto dto = basicService.findById(id,status);
+        return ResponseEntity.ok(dto);
+    }
+
+    /**
+     * 查询采购明细表id
+     * @param purchaseNo
+     * @return
+     */
+    @ApiOperation(value = "查询采购明细表id")
+    @GetMapping("/findRequestId")
+    public ResponseEntity<String> findRequestId(@RequestParam String purchaseNo) throws Exception{
+        String id = basicService.findRequestId(purchaseNo);
+        return ResponseEntity.ok(id);
+    }
+
+    /**
+     * 根据入库表id查询其全部历史修改数据
+     * @return
+     */
+    @ApiOperation(value = "查询历史修改表数据")
+    @GetMapping("/findHiById")
+    public ResponseEntity findHiById(@RequestParam String id) {
+        List<PsiWarehouseUpHi> list = basicService.findHiById(id);
+        return ResponseEntity.ok(list);
+    }
+
+    /**
+     * 根据历史表id查询历史表数据
+     * @param id
+     * @return
+     */
+    @ApiOperation(value = "根据id查询历史修改表数据")
+    @GetMapping("/findHiByHiId")
+    public ResponseEntity findHiByHiId(@RequestParam String id) {
+        PsiWareHouseDto hi = basicService.findHiByHiId(id);
+        return ResponseEntity.ok(hi);
+    }
+
+    /**
+     * 根据入库表id查询最近的一个修改历史
+     * @param id
+     * @return
+     */
+    @ApiOperation(value = "根据入库表id查询最近的一个修改历史")
+    @GetMapping("/findLastHiByid")
+    public ResponseEntity findLastHiByid(@RequestParam String id) {
+        PsiWareHouseDto hi = basicService.findLastHiByid(id);
+        return ResponseEntity.ok(hi);
+    }
+
+    /**
+     * 库存提醒状态 启用/停用
+     * @return
+     */
+    @ApiLog(value = "库存提醒状态启用/停用", type = LogTypeEnum.SAVE)
+    @PostMapping("updateWarnFlagByTradeNameAndType")
+    public ResponseEntity updateWarnFlagByTradeNameAndType(@RequestBody PsiWareHouseDto wareHouseDto) {
+        return basicService.updateWarnFlagByTradeNameAndType(wareHouseDto);
+    }
+
+    /**
+     * 库存提醒数量修改
+     * @param wareHouseDto
+     * @return
+     */
+    @ApiLog(value = "库存提醒数量修改", type = LogTypeEnum.SAVE)
+    @PostMapping("updateWarnNumByTradeNameAndType")
+    public ResponseEntity updateWarnNumByTradeNameAndType(@RequestBody PsiWareHouseDto wareHouseDto) {
+        return basicService.updateWarnNumByTradeNameAndType(wareHouseDto);
+    }
+
+    /**
+     * 根据商品名称修改
+     * @param wareHouseDto
+     * @return
+     */
+    @ApiLog(value = "根据商品名称修改", type = LogTypeEnum.SAVE)
+    @PostMapping("saveTradeName")
+    public ResponseEntity saveTradeName(@RequestBody PsiWareHouseDto wareHouseDto) {
+        basicService.saveTradeName(wareHouseDto);
+        return ResponseEntity.ok("修改成功");
+    }
+
+    /**
+     * 根据入库类型查询商品
+     * @param typeId
+     * @return
+     */
+    @ApiOperation(value = "根据入库类型查询商品")
+    @GetMapping("/findTradeByTypeId")
+    public ResponseEntity findTradeByTypeId(@RequestParam String typeId) {
+        List<PsiWareHouseDetailed> res = basicService.findTradeByTypeId(typeId);
+        return ResponseEntity.ok(res);
+    }
+
+
+    @ApiLog(value = "导出入库数据", type = LogTypeEnum.EXPORT)
+    @ApiOperation(value = "导出入库数据")
+    @GetMapping("/exportSummaryFile")
+    public void exportSummaryFile(Page<PsiWareHouseDto> page, PsiWareHouseDto dto, ExcelOptions options, HttpServletResponse response) throws Exception{
+        String fileName = options.getFilename();
+        String sheetName = options.getSheetName();
+        List<PsiWareSummaryExportDto> result;
+        if (ExportMode.current.equals(options.getMode())) {
+            result = basicService.exportSummaryList(page, dto).getRecords();
+        } else if (ExportMode.selected.equals(options.getMode())) {
+            result = basicService.exportSummaryList(page, dto).getRecords().stream().filter(item ->
+                    options.getSelectIds().contains(item.getId())
+            ).collect(Collectors.toList());
+        } else {
+            page.setSize(-1);
+            page.setCurrent(0);
+            result = basicService.exportSummaryList(page, dto).getRecords();
+        }
+
+        EasyExcelUtils.newInstance().exportExcel(result, sheetName, PsiWareSummaryExportDto.class, fileName, null, response);
+    }
+
+
+}

+ 85 - 0
jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/psiWareHouse/domain/PsiWareHouseBasic.java

@@ -0,0 +1,85 @@
+package com.jeeplus.psimanage.psiWareHouse.domain;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.jeeplus.core.domain.BaseEntity;
+import lombok.Data;
+
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 物资管理-入库基础表
+ * @author: 王强
+ * @create: 2022-12-29 15:37
+ **/
+@Data
+@TableName("psi_management_warehouse_basics")
+public class PsiWareHouseBasic extends BaseEntity {
+    //入库编号(字典值)
+    public static final String BIZ_CODE = "153";
+
+    private String procInsId;
+
+    private String processDefinitionId;
+
+    private String status;
+
+    /**
+     * 备注
+     */
+    private String remarks;
+
+    /**
+     * 入库编号
+     */
+    private String wareHouseNumber;
+
+    /**
+     * 入库名称
+     */
+    private String wareHouseName;
+
+    /**
+     * 入库时间
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    private Date wareHouseDate;
+
+    /**
+     * 采购编号
+     */
+    private String purchaseNo;
+
+    /**
+     * 入库明细数据
+     */
+    @TableField(exist = false)
+    List<PsiWareHouseDetailed> detailInfos;
+
+    /**
+     * 经办人
+     */
+    private String handledBy;
+
+    /**
+     * 合同编号
+     */
+    private String contractNo;
+
+    /**
+     * 经办人部门
+     */
+    private String handledByOffice;
+
+    /**
+     * 修改人
+     */
+    private String updateUser;
+
+    /**
+     * 修改原因
+     */
+    private String updateCause;
+}

+ 173 - 0
jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/psiWareHouse/domain/PsiWareHouseDetailed.java

@@ -0,0 +1,173 @@
+package com.jeeplus.psimanage.psiWareHouse.domain;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.jeeplus.core.domain.BaseEntity;
+import com.jeeplus.psimanage.oss.service.dto.WorkAttachmentDto;
+import lombok.Data;
+
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 入库明细表
+ * @author: 王强
+ * @create: 2022-12-29 15:53
+ **/
+@Data
+@TableName("psi_management_warehouse_detailed")
+public class PsiWareHouseDetailed extends BaseEntity {
+
+    /**
+     * 当前库存
+     */
+    private String currentInventory;
+
+    /**
+     * 入库基础表id
+     */
+    private String basicId;
+
+    /**
+     * 入库人
+     */
+    private String wareHouseMan;
+
+    /**
+     * 入库人id
+     */
+    @TableField(exist = false)
+    private String wareHouseManId;
+
+    /**
+     * 入库人部门
+     */
+    @TableField(exist = false)
+    private String wareHouseManOffice;
+
+    /**
+     * 入库类型
+     */
+    private String wareHouseType;
+
+    /**
+     * 入库类型id
+     */
+    @TableField(exist = false)
+    private String wareHouseTypeId;
+
+    /**
+     * 商品名称
+     */
+    private String tradeName;
+
+    /**
+     * 商品单价
+     */
+    private String tradePrice;
+
+    /**
+     * 商品数量
+     */
+    private String tradeNumber;
+
+    /**
+     * 单位
+     */
+    private String company;
+
+    /**
+     * 商品总价
+     */
+    private String tradeTotalPrice;
+
+    /**
+     * 实际价格
+     */
+    private String actualPrice;
+
+    //附件信息
+    @TableField(exist = false)
+    List<WorkAttachmentDto> fileInfoLost;
+
+    /**
+     * 备注
+     */
+    private String remarks;
+
+    /**
+     * 修改标记  0未修改  1已修改  2已删除
+     */
+    private String upFlag;
+
+    /**
+     * 入库详情数据id
+     */
+    private String sourceId;
+
+    /**
+     * 警告数量
+     */
+    private String warnNum;
+
+    /**
+     * 警告标记  0不警告  1警告
+     */
+    private String warnFlag;
+
+    /**
+     * 供应商id
+     */
+    private String supplierId;
+
+    /**
+     * 供应商名称
+     */
+    private String supplierName;
+
+    /**
+     * 1手填供应商  2选择供应商
+     */
+    private String isSupplier;
+
+
+    /**
+     * 包装规格
+     */
+    private String spec;
+
+    /**
+     * 生产日期
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
+    private Date produceDate;
+
+    /**
+     * 保质期
+     */
+    private String shelfLife;
+    /**
+     * 保质期单位
+     */
+    private String shelfLifeUnit;
+
+
+
+    @TableField(exist = false)
+    private List<PsiWareHouseDetailed> psiWareHouseDetailed;
+
+    /**
+     * 剩余数量
+     */
+    @TableField(exist = false)
+    private String surplusNumber;
+
+
+    /**
+     * 领用数量
+     */
+    @TableField(exist = false)
+    private String collectNumber;
+
+}

+ 35 - 0
jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/psiWareHouse/domain/PsiWareHouseSummary.java

@@ -0,0 +1,35 @@
+package com.jeeplus.psimanage.psiWareHouse.domain;
+
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.jeeplus.core.domain.BaseEntity;
+import lombok.Data;
+
+/**
+ * 物资管理-入库汇总表
+ * @author: 王强
+ * @create: 2022-12-29 16:33
+ **/
+@Data
+@TableName("psi_management_warehouse_summary")
+public class PsiWareHouseSummary extends BaseEntity {
+
+    /**
+     * 入库基础表id
+     */
+    private String detailedId;
+
+    /**
+     * 入库类型
+     */
+    private String wareHouseType;
+
+    /**
+     * 商品名称
+     */
+    private String tradeName;
+
+    /**
+     * 商品数量
+     */
+    private String tradeNumber;
+}

+ 59 - 0
jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/psiWareHouse/domain/PsiWarehouseUpHi.java

@@ -0,0 +1,59 @@
+package com.jeeplus.psimanage.psiWareHouse.domain;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.jeeplus.core.domain.BaseEntity;
+import lombok.Data;
+
+/**
+ * 入库数据修改历史表
+ * @TableName material_management_warehouse_up_hi
+ */
+@TableName(value ="psi_management_warehouse_up_hi")
+@Data
+public class PsiWarehouseUpHi extends BaseEntity {
+
+    /**
+     * 备注
+     */
+    private String remarks;
+
+    /**
+     * 入库id
+     */
+    private String warehouseId;
+
+    /**
+     * json数据
+     */
+    private String jsonData;
+
+    /**
+     * 标记  0为原数据 1为已完成数据
+     */
+    private String endflag;
+
+    /**
+     * 修改申请人
+     */
+    private String updateUser;
+
+    /**
+     * 修改数据的商品名称
+     */
+    private String updateTradeName;
+
+    /**
+     * 修改数据的商品类型
+     */
+    private String updateTradeType;
+
+    /**
+     * 创建人姓名
+     */
+    @TableField(exist = false)
+    private String createName;
+
+    @TableField(exist = false)
+    private static final long serialVersionUID = 1L;
+}

+ 119 - 0
jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/psiWareHouse/mapper/PsiWareHouseBasicMapper.java

@@ -0,0 +1,119 @@
+package com.jeeplus.psimanage.psiWareHouse.mapper;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.core.toolkit.Constants;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.jeeplus.psimanage.psiWareHouse.domain.PsiWareHouseBasic;
+import com.jeeplus.psimanage.psiWareHouse.service.dto.PsiWareHouseDto;
+import com.jeeplus.psimanage.psiWareHouse.service.dto.PsiWareSummaryExportDto;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.Date;
+import java.util.List;
+
+/**
+ * @author: 王强
+ * @create: 2022-12-29 16:39
+ **/
+public interface PsiWareHouseBasicMapper extends BaseMapper<PsiWareHouseBasic> {
+
+    /**
+     * 根据类型及物品名称查领用数量
+     * @param wareHouseType
+     * @param tradeName
+     * @return
+     */
+    String getCollectNumByType(@Param("wareHouseType") String wareHouseType,@Param("tradeName") String tradeName);
+
+    /**
+     * 根据时间查询库存数量
+     * @param tradeName
+     * @param wareHouseType
+     * @param produceDate
+     * @return
+     */
+    String getWareHouseInfoByTime(@Param("tradeName") String tradeName,@Param("wareHouseType")String wareHouseType,
+                                  @Param("produceDate")Date produceDate);
+
+    /**
+     * 根据时间查询库存数量
+     * @param tradeName
+     * @param wareHouseType
+     * @param createDate
+     * @return
+     */
+    String getCollectInfoByTime(@Param("tradeName") String tradeName,@Param("wareHouseType")String wareHouseType,
+                                  @Param("createDate")String createDate);
+
+    IPage<PsiWareHouseDto> findList(Page<PsiWareHouseDto> page, @Param(Constants.WRAPPER) QueryWrapper<PsiWareHouseDto> queryWrapper);
+
+    String getUserNameByUserId(String id);
+
+    IPage<PsiWareHouseDto> summaryList(Page<PsiWareHouseDto> page,@Param(Constants.WRAPPER) QueryWrapper<PsiWareHouseDto> queryWrapper);
+
+    IPage<PsiWareSummaryExportDto> exportSummaryList(Page<PsiWareHouseDto> page, @Param(Constants.WRAPPER) QueryWrapper<PsiWareHouseDto> queryWrapper);
+
+    IPage<PsiWareHouseDto> summaryList2(Page<PsiWareHouseDto> page,@Param(Constants.WRAPPER) QueryWrapper<PsiWareHouseDto> queryWrapper);
+
+    IPage<PsiWareHouseDto> getByProduceDateAndName(Page<PsiWareHouseDto> page,@Param(Constants.WRAPPER) QueryWrapper<PsiWareHouseDto> queryWrapper);
+
+
+    IPage<PsiWareHouseDto> getByProduceDateNotMerge(Page<PsiWareHouseDto> page,@Param(Constants.WRAPPER) QueryWrapper<PsiWareHouseDto> queryWrapper);
+
+    IPage<PsiWareHouseDto> wareHouseHistoryList(Page<PsiWareHouseDto> page,@Param(Constants.WRAPPER) QueryWrapper<PsiWareHouseDto> queryWrapper);
+
+    IPage<PsiWareHouseDto> collectHistoryList(Page<PsiWareHouseDto> page,@Param(Constants.WRAPPER) QueryWrapper<PsiWareHouseDto> queryWrapper);
+
+    String findRequestId(String purchaseNo);
+
+    /**
+     * 根据领用类型和商品名称获取库存数量
+     * @param collectTypeId
+     * @param goodsName
+     */
+    PsiWareHouseDto getByTypeAndGoodsName(@Param("goodsName")String goodsName,
+                               @Param("collectTypeId")String collectTypeId);
+
+    /**
+     * 根据领用类型和商品名称获取库存数量
+     * @param collectTypeId
+     * @param goodsName
+     */
+    PsiWareHouseDto getByTypeAndGoodsNameByProduceDate(@Param("goodsName")String goodsName,
+                                          @Param("collectTypeId")String collectTypeId,@Param("produceDate")Date produceDate);
+
+
+    /**
+     * 根据领用类型和商品名称获取库存数量
+     * @param collectTypeId
+     * @param goodsName
+     */
+    List<PsiWareHouseDto> getByTypeAndGoodsNameOrderByProduceDate(@Param("goodsName")String goodsName,
+                                          @Param("collectTypeId")String collectTypeId);
+
+    // 保存当前修改申请人
+    void saveUpdateUser(@Param("basicId")String basicId, @Param("userId")String userId);
+
+    // 根据入库数据id获取修改申请人
+    String getUpdateUser(String basicId);
+
+    // 根据入库数据id删除修改申请人
+    void deleteUpdateUser(String basicId);
+
+    // 根据商品名称和入库类型查询数据的 ‘提醒数量’ 以及 ‘是否提醒标记’
+    List<PsiWareHouseDto> getByTypeAndTradeName(@Param("tradeName")String tradeName,
+                                                @Param("typeId")String typeId);
+
+    void updateWarnFlagByTradeNameAndType(@Param("warnFlag")String warnFlag,
+                                            @Param("tradeName")String tradeName,
+                                            @Param("typeId")String typeId);
+
+    void updateWarnNumByTradeNameAndType(@Param("warnNum")String warnNum,
+                                         @Param("tradeName")String tradeName,
+                                         @Param("typeId")String typeId);
+
+    // 根据id清除修改原因
+    void clearUpdateCause(String id);
+}

+ 62 - 0
jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/psiWareHouse/mapper/PsiWareHouseDetailedMapper.java

@@ -0,0 +1,62 @@
+package com.jeeplus.psimanage.psiWareHouse.mapper;
+
+import com.baomidou.mybatisplus.annotation.InterceptorIgnore;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.jeeplus.psimanage.psiWareHouse.domain.PsiWareHouseDetailed;
+import com.jeeplus.psimanage.oss.service.dto.WorkAttachmentDto;
+import com.jeeplus.psimanage.psiWareHouse.service.dto.PsiWareHouseDto;
+import com.jeeplus.sys.service.dto.UserDTO;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+/**
+ * @author: 王强
+ * @create: 2022-12-30 09:27
+ **/
+public interface PsiWareHouseDetailedMapper extends BaseMapper<PsiWareHouseDetailed> {
+    /**
+     * 根据入库基础表的id查入库明细相关数据(upFlag = '0')
+     * @param id
+     * @return
+     */
+    List<PsiWareHouseDetailed> getByBasicId(String id);
+    // 根据入库基础表的id查入库明细相关数据(upFlag 全部)
+    List<PsiWareHouseDetailed> getByBasicIdAll(String id);
+
+    //查出附件信息
+    List<WorkAttachmentDto> getByAttachmentId(String id);
+
+    List<String> getIdByBasicId(String id);
+
+    /**
+     * 根据登陆名称查去用户信息
+     * @param
+     * @return
+     */
+    @InterceptorIgnore(tenantLine = "true")
+    List<UserDTO> getUsersInfo();
+
+    // 根据id置空sourceId
+    void upSourceIdEmpty(String id);
+
+    // 根据入库id删除详情  物理删除
+    void deleteByBasicId(String basicId);
+
+    // 根据入库id删除关联附件  物理删除
+    void deleteFilesByIdList(@Param("attachmentIdList")List<String> attachmentIdList);
+
+    // 修改入库详情商品名称
+    void saveTradeName(@Param("oldTradeName") String oldTradeName, @Param("tradeName") String tradeName, @Param("wareHouseType") String wareHouseType);
+
+    // 修改领用详情商品名称
+    void saveGoodsName(@Param("oldTradeName") String oldTradeName, @Param("tradeName") String tradeName, @Param("wareHouseType") String wareHouseType);
+
+    // 根据入库类型查询商品
+    List<PsiWareHouseDetailed> getByTypeId(String typeId);
+
+    void updateBatchById(@Param("list") List<PsiWareHouseDetailed> list);
+
+    PsiWareHouseDetailed getCurrentInventoryById(@Param("id") String id);
+
+}

+ 47 - 0
jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/psiWareHouse/mapper/PsiWareHouseSummaryMapper.java

@@ -0,0 +1,47 @@
+package com.jeeplus.psimanage.psiWareHouse.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.jeeplus.psimanage.collect.domain.PsiCollectDetailed;
+import com.jeeplus.psimanage.psiWareHouse.domain.PsiWareHouseDetailed;
+import com.jeeplus.psimanage.psiWareHouse.domain.PsiWareHouseSummary;
+import com.jeeplus.psimanage.psiWareHouse.service.dto.PsiWareHouseDto;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+/**
+ * @author: 王强
+ * @create: 2022-12-30 10:07
+ **/
+public interface PsiWareHouseSummaryMapper extends BaseMapper<PsiWareHouseSummary> {
+    /**
+     * 根据入库类型和商品名称查询库存数量
+     * @param tradeName
+     * @param wareHouseType
+     * @return
+     */
+    Double getInfoByTradeName(@Param("tradeName") String tradeName,
+                                            @Param("wareHouseType") String wareHouseType);
+
+
+    /**
+     * 根据日期排序查询不同生产日期的列表数据
+     * @param tradeName
+     * @param wareHouseType
+     * @return
+     */
+    List<PsiWareHouseDetailed>   getInfoByProduceDateDesc(@Param("tradeName") String tradeName,
+                              @Param("wareHouseType") String wareHouseType);
+
+
+
+
+    /**
+     * 根据入库基础表id查出汇总表数据
+     * @param id
+     * @return
+     */
+    List<PsiWareHouseSummary> getInfoByBasicId(String id);
+
+    void deleteByDetailedId(String id);
+}

+ 27 - 0
jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/psiWareHouse/mapper/PsiWarehouseUpHiMapper.java

@@ -0,0 +1,27 @@
+package com.jeeplus.psimanage.psiWareHouse.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.jeeplus.psimanage.psiWareHouse.domain.PsiWarehouseUpHi;
+import org.apache.ibatis.annotations.Mapper;
+
+import java.util.List;
+
+@Mapper
+public interface PsiWarehouseUpHiMapper extends BaseMapper<PsiWarehouseUpHi> {
+
+    // 根据入库表id获取原数据 endFlag = '0'
+    String getSourceData(String warehouseId);
+
+    // 根据入库表id查询其全部历史修改数据
+    List<PsiWarehouseUpHi> findHiById(String warehouseId);
+
+    // 根据历史表id查询历史表数据
+    PsiWarehouseUpHi findHiByHiId(String hiId);
+
+    // 根据入库表id查询最近的一个修改历史
+    PsiWarehouseUpHi findLastHiByid(String warehouseId);
+}
+
+
+
+

+ 468 - 0
jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/psiWareHouse/mapper/xml/PsiWareHouseBasicMapper.xml

@@ -0,0 +1,468 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.jeeplus.psimanage.psiWareHouse.mapper.PsiWareHouseBasicMapper">
+    <select id="findList" resultType="com.jeeplus.psimanage.psiWareHouse.service.dto.PsiWareHouseDto">
+		SELECT
+			b.id as purchaseId,
+			a.id,
+			a.create_by_id as createBy,
+			a.create_time as createDate,
+			a.ware_house_number,
+			a.ware_house_name,
+			a.ware_house_date,
+			a.handled_by,
+			a.handled_by_office,
+			so.name as handledByOfficeName,
+			sy.name as handleByName,
+			a.proc_ins_id,
+			a.process_definition_id,
+			ifnull(a.status,'0') as status,
+			art.ID_ as task_id
+		FROM
+			psi_management_warehouse_basics a
+			left join psi_management_pruchase_request_basics b on a.purchase_no = b.purchase_no and b.del_flag = 0
+			left join sys_office so on a.handled_by_office = so.id
+			left join sys_user sy on sy.id = a.handled_by
+			left join act_ru_task art ON a.proc_ins_id = art.PROC_INST_ID_
+			${ew.customSqlSegment}
+		ORDER BY a.update_time DESC
+    </select>
+	<select id="getUserNameByUserId" resultType="java.lang.String">
+		select name from sys_user where id = #{id}
+	</select>
+	<select id="summaryList2"
+			resultType="com.jeeplus.psimanage.psiWareHouse.service.dto.PsiWareHouseDto">
+			SELECT
+				a.id,
+				a.create_by_id as createBy,
+				a.create_time as createDate,
+				a.ware_house_type,
+				a.trade_name,
+				a.company,
+				b.NAME AS wareHouseTypeName,
+				sum( trade_number ) AS allNumber,
+				b.collect_number AS borrowNumber,
+				a.current_inventory AS tradeNumber,
+				b.mmcId as mmcId
+			FROM
+				psi_management_warehouse_detailed a
+				LEFT JOIN (
+				SELECT
+					sum( g.collect_number ) AS collect_number,
+					e.goods_name,
+					c.NAME as name,
+					e.basic_id as mmcId,
+				STATUS
+				FROM
+					psi_management_collect_detailed e
+					LEFT JOIN psi_management_collect_basics f ON e.basic_id = f.id
+					AND f.del_flag = 0
+					LEFT JOIN psi_management_type c ON e.collect_type = c.id
+					left join psi_management_collect_detailed g on e.goods_name = g.goods_name and g.del_flag = 0
+				WHERE
+					f.`status` = 5 AND e.del_flag = 0
+				GROUP BY
+					e.id
+				) b ON a.trade_name = b.goods_name
+				LEFT JOIN psi_management_type c ON a.ware_house_type = c.id
+				${ew.customSqlSegment}
+				GROUP BY a.trade_name,a.ware_house_type
+				HAVING sum( trade_number ) - IFNULL(collect_number,0) &lt;= 5
+				ORDER BY a.update_time DESC
+	</select>
+    <select id="summaryList"
+            resultType="com.jeeplus.psimanage.psiWareHouse.service.dto.PsiWareHouseDto">
+		SELECT
+			a.id,
+			a.create_by_id as createBy,
+			a.create_time as createDate,
+			a.ware_house_type,
+			a.trade_name,
+			a.company,
+			c.name as wareHouseTypeName,
+			sum( trade_number ) AS allNumber,
+			b.collect_number AS borrowNumber,
+			loss.loss_number AS lossNumber,
+			sum(a.current_inventory) AS tradeNumber,
+			a.warn_num,
+			a.warn_flag,
+			a.produce_date,
+			a.shelf_life,
+			a.shelf_life_unit
+		FROM
+			psi_management_warehouse_detailed a
+			left join
+			(
+			select
+			    sum(collect_number) as collect_number,
+			    goods_name,
+			    status
+			 from psi_management_collect_detailed e
+			left join psi_management_collect_basics f on e.basic_id = f.id and f.del_flag = 0
+			WHERE f.`status` = 5 and e.del_flag = 0 and e.is_return = '0'
+			GROUP BY e.goods_name
+			) b
+			on a.trade_name = b.goods_name
+			left join
+			(
+				select
+					sum(loss_number) as loss_number,
+					goods_name,
+					status
+				from psi_management_loss_detailed e
+						 left join psi_management_loss_basics f on e.basic_id = f.id and f.del_flag = 0
+				WHERE f.`status` = 5 and e.del_flag = 0
+				GROUP BY e.goods_name
+			) loss
+			on a.trade_name = loss.goods_name
+			LEFT JOIN psi_management_warehouse_basics bas on a.basic_id = bas.id
+			left join psi_management_type c on a.ware_house_type = c.id
+			${ew.customSqlSegment}
+			GROUP BY a.trade_name,a.ware_house_type
+			ORDER BY a.ware_house_type DESC,a.trade_name
+	</select>
+
+	<select id="exportSummaryList"
+			resultType="com.jeeplus.psimanage.psiWareHouse.service.dto.PsiWareSummaryExportDto">
+		SELECT
+			a.id,
+			a.create_by_id as createBy,
+			a.create_time as createDate,
+			a.ware_house_type,
+			a.trade_name,
+			a.company,
+			c.name as wareHouseTypeName,
+			sum( trade_number ) AS allNumber,
+			b.collect_number AS borrowNumber,
+			loss.loss_number AS lossNumber,
+			a.current_inventory AS tradeNumber,
+			a.warn_num,
+			a.warn_flag,
+			a.produce_date,
+			a.shelf_life,
+			a.shelf_life_unit
+		FROM
+			psi_management_warehouse_detailed a
+				left join
+			(
+				select
+					sum(collect_number) as collect_number,
+					goods_name,
+					status
+				from psi_management_collect_detailed e
+						 left join psi_management_collect_basics f on e.basic_id = f.id and f.del_flag = 0
+				WHERE f.`status` = 5 and e.del_flag = 0
+				GROUP BY e.goods_name
+			) b
+			on a.trade_name = b.goods_name
+				left join
+			(
+				select
+					sum(loss_number) as loss_number,
+					goods_name,
+					status
+				from psi_management_loss_detailed e
+						 left join psi_management_loss_basics f on e.basic_id = f.id and f.del_flag = 0
+				WHERE f.`status` = 5 and e.del_flag = 0
+				GROUP BY e.goods_name
+			) loss
+			on a.trade_name = loss.goods_name
+				LEFT JOIN psi_management_warehouse_basics bas on a.basic_id = bas.id
+				left join psi_management_type c on a.ware_house_type = c.id
+			${ew.customSqlSegment}
+		GROUP BY a.trade_name,a.ware_house_type
+		ORDER BY a.ware_house_type DESC,a.trade_name
+	</select>
+
+
+	<select id="getByProduceDateAndName"
+			resultType="com.jeeplus.psimanage.psiWareHouse.service.dto.PsiWareHouseDto">
+		SELECT
+			a.id,
+			a.create_by_id as createBy,
+			a.create_time as createDate,
+			a.ware_house_type,
+			a.trade_name,
+			a.company,
+			c.name as wareHouseTypeName,
+			sum( trade_number ) AS allNumber,
+			b.collect_number AS borrowNumber,
+			sum(a.current_inventory) AS tradeNumber,
+			a.warn_num,
+			a.warn_flag,
+			min(a.produce_date) as produce_date,
+			a.shelf_life,
+			a.shelf_life_unit,
+			a.spec
+		FROM
+			psi_management_warehouse_detailed a
+				left join
+			(
+				select
+					sum(collect_number) as collect_number,
+					goods_name,
+					status
+				from psi_management_collect_detailed e
+						 left join psi_management_collect_basics f on e.basic_id = f.id and f.del_flag = 0
+				WHERE f.`status` = 5 and e.del_flag = 0
+				GROUP BY e.goods_name
+			) b
+			on a.trade_name = b.goods_name
+				LEFT JOIN psi_management_warehouse_basics bas on a.basic_id = bas.id
+				left join psi_management_type c on a.ware_house_type = c.id
+			${ew.customSqlSegment}
+		GROUP BY a.trade_name,a.ware_house_type
+		ORDER BY a.ware_house_type DESC,a.trade_name
+	</select>
+
+	<select id="getByProduceDateNotMerge"
+			resultType="com.jeeplus.psimanage.psiWareHouse.service.dto.PsiWareHouseDto">
+		SELECT
+			a.id,
+			a.produce_date as produce_date,
+			a.trade_name,
+			a.spec,
+			a.company,
+			a.current_inventory,
+			pmwd.warn_num,
+			pmwd.warn_flag
+		FROM
+			psi_management_warehouse_detailed a
+				LEFT JOIN psi_management_warehouse_basics bas on a.basic_id = bas.id
+				LEFT JOIN psi_management_warehouse_detailed pmwd on bas.id = pmwd.basic_id
+				left join psi_management_type c on a.ware_house_type = c.id
+			${ew.customSqlSegment}
+
+		GROUP BY a.trade_name,a.ware_house_type,a.produce_date
+		ORDER BY a.produce_date asc
+	</select>
+
+    <select id="findRequestId" resultType="java.lang.String">
+		select id from psi_management_pruchase_request_basics where purchase_no = #{purchaseNo} and del_flag = 0
+	</select>
+	<select id="wareHouseHistoryList"
+			resultType="com.jeeplus.psimanage.psiWareHouse.service.dto.PsiWareHouseDto">
+		SELECT
+			b.create_time as dateTest,
+			a.id as wareHouseId,
+			a.ware_house_number,
+			a.ware_house_name,
+			a.ware_house_date,
+			sy.name as wareHouseHandledBy,
+			so.name as wareHouseHandledByOff,
+			b.trade_name,
+			b.trade_number,
+			b.current_inventory,
+			b.ware_house_type,
+			b.produce_date,
+			b.shelf_life,
+			b.spec,
+			b.shelf_life_unit
+		FROM
+			psi_management_warehouse_basics a
+			LEFT JOIN
+			psi_management_warehouse_detailed b on a.id = b.basic_id and b.del_flag = 0
+
+			left join sys_user sy on sy.id = a.handled_by
+			left join sys_office so on sy.office_id = so.id
+
+			${ew.customSqlSegment}
+		ORDER BY a.create_time DESC
+	</select>
+	<select id="collectHistoryList"
+			resultType="com.jeeplus.psimanage.psiWareHouse.service.dto.PsiWareHouseDto">
+		SELECT
+			b.create_time as dateTest2,
+			a.id as collectId,
+			a.collect_no,
+			sy.name as collectHandleBy,
+			so.name as collectHandleByOff,
+			a.collect_date,
+			b.goods_name,
+			b.collect_number,
+			b.current_inventory,
+			b.collect_type as collectType
+		FROM
+			psi_management_collect_basics a
+			LEFT JOIN
+			psi_management_collect_detailed b on a.id = b.basic_id and b.del_flag = 0
+
+			left join sys_user sy on sy.id = a.handled_by
+			left join sys_office so on sy.office_id = so.id
+
+			${ew.customSqlSegment}
+		ORDER BY a.update_time DESC
+	</select>
+	<select id="getByTypeAndGoodsName"
+			resultType="com.jeeplus.psimanage.psiWareHouse.service.dto.PsiWareHouseDto">
+		SELECT
+			a.id,
+			a.create_by_id as createBy,
+			a.create_time as createDate,
+			a.ware_house_type,
+			a.trade_name,
+			a.company,
+			c.name as wareHouseTypeName,
+			sum(trade_number) as allNumber,
+			b.collect_number as borrowNumber,
+			a.current_inventory as tradeNumber,
+			a.warn_num,
+			a.warn_flag
+		FROM
+			psi_management_warehouse_detailed a
+			left join
+			(select sum(collect_number) as collect_number,goods_name,status from psi_management_collect_detailed e
+			left join psi_management_collect_basics f on e.basic_id = f.id and f.del_flag = 0
+			WHERE f.`status` = 5 and e.collect_type = #{collectTypeId}
+			GROUP BY e.goods_name) b
+			on a.trade_name = b.goods_name
+			LEFT JOIN psi_management_warehouse_basics bas on a.basic_id = bas.id
+			left join psi_management_type c on a.ware_house_type = c.id
+			where a.trade_name = #{goodsName}
+			  and a.ware_house_type = #{collectTypeId}
+			  and a.del_flag = 0
+			GROUP BY a.trade_name
+			ORDER BY a.update_time DESC
+	</select>
+	<select id="getByTypeAndGoodsNameByProduceDate"
+			resultType="com.jeeplus.psimanage.psiWareHouse.service.dto.PsiWareHouseDto">
+		SELECT
+			a.id,
+			a.create_by_id as createBy,
+			a.create_time as createDate,
+			a.ware_house_type,
+			a.trade_name,
+			a.company,
+			c.name as wareHouseTypeName,
+			sum(trade_number) as allNumber,
+			b.collect_number as borrowNumber,
+			IFNULL((sum(trade_number) - collect_number),sum(trade_number)) as tradeNumber
+		FROM
+			psi_management_warehouse_detailed a
+				left join
+			(select sum(collect_number) as collect_number,goods_name,status from psi_management_collect_detailed e
+																					 left join psi_management_collect_basics f on e.basic_id = f.id and f.del_flag = 0
+			 WHERE f.`status` = 5 and e.collect_type = #{collectTypeId}
+			 GROUP BY e.goods_name) b
+			on a.trade_name = b.goods_name
+
+				LEFT JOIN psi_management_warehouse_basics bas on a.basic_id = bas.id
+				left join psi_management_type c on a.ware_house_type = c.id
+		where a.trade_name = #{goodsName}
+		  and a.ware_house_type = #{collectTypeId}
+		  and a.produce_date = #{produceDate}
+		  and a.del_flag = 0
+		GROUP BY a.trade_name
+		ORDER BY a.produce_date asc
+	</select>
+
+	<select id="getByTypeAndGoodsNameOrderByProduceDate"
+			resultType="com.jeeplus.psimanage.psiWareHouse.service.dto.PsiWareHouseDto">
+		SELECT
+			a.id,
+			a.create_by_id as createBy,
+			a.create_time as createDate,
+			a.ware_house_type,
+			a.trade_name,
+			a.company,
+			c.name as wareHouseTypeName,
+			a.trade_number,
+			a.current_inventory
+		FROM
+			psi_management_warehouse_detailed a
+				left join
+			(select sum(collect_number) as collect_number,goods_name,status from psi_management_collect_detailed e
+																					 left join psi_management_collect_basics f on e.basic_id = f.id and f.del_flag = 0
+			 WHERE f.`status` = 5 and e.collect_type = #{collectTypeId}
+			 GROUP BY e.goods_name) b
+			on a.trade_name = b.goods_name
+				LEFT JOIN psi_management_warehouse_basics bas on a.basic_id = bas.id
+				left join psi_management_type c on a.ware_house_type = c.id
+		where a.trade_name = #{goodsName}
+		  and a.ware_house_type = #{collectTypeId}
+		  and a.del_flag = 0
+		ORDER BY a.produce_date asc
+	</select>
+
+	<update id="saveUpdateUser">
+		update psi_management_warehouse_basics set update_user = #{userId} where id = #{basicId}
+	</update>
+	<select id="getUpdateUser" resultType="string">
+		select update_user from psi_management_warehouse_basics where id = #{basicId}
+	</select>
+	<update id="deleteUpdateUser">
+		update psi_management_warehouse_basics set update_user = null where id = #{basicId}
+	</update>
+	<select id="getByTypeAndTradeName" resultType="com.jeeplus.psimanage.psiWareHouse.service.dto.PsiWareHouseDto">
+		select
+			warn_num,
+			warn_flag
+		from psi_management_warehouse_detailed
+		where trade_name = #{tradeName} and ware_house_type = #{typeId} and del_flag = '0'
+	</select>
+	<select id="getWareHouseInfoByTime" resultType="java.lang.String">
+		SELECT
+		IFNULL((sum(trade_number) - collect_number),sum(trade_number)) as tradeNumber
+		FROM
+		psi_management_warehouse_detailed a
+		left join psi_management_type c on a.ware_house_type = c.id
+
+		left join
+		(select sum(collect_number) as collect_number,goods_name,status from psi_management_collect_detailed e
+		left join psi_management_collect_basics f on e.basic_id = f.id and f.del_flag = 0
+		WHERE f.`status` = 5 and e.del_flag = 0 and e.produce_date &lt;= #{produceDate} and e.collect_type = #{wareHouseType} and e.goods_name = #{tradeName}) b
+		on a.trade_name = b.goods_name
+
+		WHERE a.ware_house_type = #{wareHouseType}
+		and a.del_flag = 0
+		and a.trade_name = #{tradeName}
+		and a.produce_date &lt;= #{produceDate}
+		GROUP BY a.trade_name,a.ware_house_type
+		ORDER BY a.ware_house_type DESC
+	</select>
+	<select id="getCollectInfoByTime" resultType="java.lang.String">
+		SELECT
+		IFNULL((sum(trade_number) - collect_number),sum(trade_number)) as tradeNumber
+		FROM
+		psi_management_warehouse_detailed a
+		left join psi_management_type c on a.ware_house_type = c.id
+
+		left join
+		(select sum(collect_number) as collect_number,goods_name,status from psi_management_collect_detailed e
+		left join psi_management_collect_basics f on e.basic_id = f.id and f.del_flag = 0
+		WHERE f.`status` = 5 and e.del_flag = 0 and e.create_time &lt;= #{createDate} and e.collect_type = #{wareHouseType} and e.goods_name = #{tradeName}) b
+		on a.trade_name = b.goods_name
+
+		WHERE a.ware_house_type = #{wareHouseType}
+		and a.del_flag = 0
+		and a.trade_name = #{tradeName}
+		and a.create_time &lt;= #{createDate}
+		GROUP BY a.trade_name,a.ware_house_type
+		ORDER BY a.ware_house_type DESC
+	</select>
+	<select id="getCollectNumByType" resultType="java.lang.String">
+		SELECT
+		sum( collect_number ) AS collect_number
+	FROM
+		psi_management_collect_detailed e
+		LEFT JOIN psi_management_collect_basics f ON e.basic_id = f.id
+		AND f.del_flag = 0
+	WHERE
+		f.`status` = 5
+		AND e.del_flag = 0
+		and e.collect_type = #{wareHouseType} and e.goods_name = #{tradeName}
+	</select>
+	<update id="updateWarnFlagByTradeNameAndType">
+		update psi_management_warehouse_detailed
+		set warn_flag = #{warnFlag}
+		where trade_name = #{tradeName} and ware_house_type = #{typeId}
+	</update>
+	<update id="updateWarnNumByTradeNameAndType">
+		update psi_management_warehouse_detailed
+		set warn_num = #{warnNum}
+		where trade_name = #{tradeName} and ware_house_type = #{typeId}
+	</update>
+	<update id="clearUpdateCause">
+		update psi_management_warehouse_basics set update_cause = null where id = #{id}
+	</update>
+</mapper>

+ 105 - 0
jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/psiWareHouse/mapper/xml/PsiWareHouseDetailedMapper.xml

@@ -0,0 +1,105 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.jeeplus.psimanage.psiWareHouse.mapper.PsiWareHouseDetailedMapper">
+    <select id="getByBasicId"
+            resultType="com.jeeplus.psimanage.psiWareHouse.domain.PsiWareHouseDetailed">
+        select a.*,b.name as wareHouseMan,b.id as wareHouseManId,c.name as wareHouseManOffice,
+        d.id as wareHouseTypeId, d.name as wareHouseType
+        from psi_management_warehouse_detailed a
+        left join sys_user b on a.ware_house_man = b.id and b.del_flag = '0'
+        left join sys_office c on b.office_id = c.id
+        left join psi_management_type d on a.ware_house_type = d.id
+        where a.basic_id = #{id} and a.del_flag = '0' and a.up_flag = '0'
+        ORDER BY a.create_time desc
+    </select>
+    <select id="getByBasicIdAll"
+            resultType="com.jeeplus.psimanage.psiWareHouse.domain.PsiWareHouseDetailed">
+        select a.*,b.name as wareHouseMan,b.id as wareHouseManId,c.name as wareHouseManOffice,
+        d.id as wareHouseTypeId, d.name as wareHouseType
+        from psi_management_warehouse_detailed a
+        left join sys_user b on a.ware_house_man = b.id and b.del_flag = '0'
+        left join sys_office c on b.office_id = c.id
+        left join psi_management_type d on a.ware_house_type = d.id
+        where a.basic_id = #{id} and a.del_flag = '0' and (a.up_flag = '1' or a.up_flag = '2')
+        ORDER BY a.create_time desc
+    </select>
+    <select id="getByAttachmentId" resultType="com.jeeplus.psimanage.oss.service.dto.WorkAttachmentDto">
+        SELECT
+			id,
+			url,
+			attachment_name AS `name`,
+			create_by_id AS `by`,
+			create_time
+		FROM
+			work_attachment
+		WHERE
+			del_flag = 0
+			AND attachment_id = #{id}
+    </select>
+    <select id="getIdByBasicId" resultType="java.lang.String">
+        select a.id from psi_management_warehouse_detailed a where a.basic_id = #{id} and a.del_flag = 0
+    </select>
+    <select id="getUsersInfo" resultType="com.jeeplus.sys.service.dto.UserDTO">
+        select a.user_id as id,a.user_name as loginName  from psi_user a
+    </select>
+    <update id="upSourceIdEmpty">
+        update psi_management_warehouse_detailed set source_id = null where id = #{id}
+    </update>
+    <delete id="deleteByBasicId">
+        delete from psi_management_warehouse_detailed where basic_id = #{basicId}
+    </delete>
+    <delete id="deleteFilesByIdList">
+        delete from work_attachment where attachment_id in
+        <foreach collection="attachmentIdList" item="attachmentId" open="(" separator="," close=")">
+            #{attachmentId}
+        </foreach>
+    </delete>
+    <update id="saveTradeName">
+        update psi_management_warehouse_detailed set
+        trade_name = #{tradeName}
+        where trade_name = #{oldTradeName} and ware_house_type = #{wareHouseType} and del_flag = '0'
+    </update>
+    <update id="saveGoodsName">
+        update psi_management_collect_detailed set
+        goods_name = #{tradeName}
+        where goods_name = #{oldTradeName} and collect_type = #{wareHouseType} and del_flag = '0'
+    </update>
+    <select id="getByTypeId" resultType="com.jeeplus.psimanage.psiWareHouse.domain.PsiWareHouseDetailed">
+        SELECT
+            id,
+            trade_name
+        FROM
+            psi_management_warehouse_detailed
+        WHERE
+            del_flag = '0'
+            AND ware_house_type = #{typeId}
+        GROUP BY
+            trade_name
+        ORDER BY
+            create_time DESC
+    </select>
+
+    <update id="updateBatchById">
+        <foreach collection="list" item="item" separator=";">
+            update psi_management_warehouse_detailed
+            <set>
+                current_inventory = #{item.currentInventory}
+            </set>
+            where id = #{item.id}
+            and del_flag = '0'
+        </foreach>
+    </update>
+
+    <select id="getCurrentInventoryById" resultType="com.jeeplus.psimanage.psiWareHouse.domain.PsiWareHouseDetailed">
+        SELECT
+            id,
+            current_inventory,
+            spec
+        FROM
+            psi_management_warehouse_detailed
+        WHERE
+            del_flag = '0'
+          AND id = #{id}
+    </select>
+
+</mapper>

+ 82 - 0
jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/psiWareHouse/mapper/xml/PsiWareHouseSummaryMapper.xml

@@ -0,0 +1,82 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.jeeplus.psimanage.psiWareHouse.mapper.PsiWareHouseSummaryMapper">
+    <delete id="deleteByDetailedId">
+        update psi_management_warehouse_summary set del_flag = 1
+    </delete>
+    <select id="getInfoByTradeName"
+            resultType="java.lang.Double">
+        SELECT
+            ( sum( a.trade_number )- c.num2 ) AS num1
+        FROM
+            psi_management_warehouse_detailed a
+            LEFT JOIN (
+            SELECT
+                sum( b.collect_number ) AS num2,
+                b.collect_type,
+                b.goods_name
+            FROM
+                psi_management_collect_detailed b
+                LEFT JOIN psi_management_collect_basics c ON b.basic_id = c.id
+                AND c.del_flag = 0
+            WHERE
+                b.collect_type = #{wareHouseType}
+                AND b.goods_name = #{tradeName}
+
+            AND b.del_flag = 0
+            AND c.`status` = 5
+            ) AS c ON a.ware_house_type = c.collect_type
+            AND a.trade_name = c.goods_name
+        WHERE
+            a.ware_house_type = #{wareHouseType}
+            AND a.trade_name = #{tradeName}
+            AND a.del_flag = 0
+    </select>
+    <select id="getInfoByBasicId"
+            resultType="com.jeeplus.psimanage.psiWareHouse.domain.PsiWareHouseSummary">
+        select * from psi_management_warehouse_summary where basic_id = #{id}
+    </select>
+
+    <select id="getInfoByProduceDateDesc"
+            resultType="com.jeeplus.psimanage.psiWareHouse.domain.PsiWareHouseDetailed">
+        SELECT
+            a.id,
+            a.trade_name,
+            a.produce_date,
+            a.spec,
+            a.trade_number,
+--             (a.trade_number - IFNULL(c.num2, 0)) AS currentInventory
+            a.current_inventory,
+            a.warn_num,
+            a.warn_flag
+        FROM
+            psi_management_warehouse_detailed a
+            -- 只查当前批次、当前生产日期对应的领用数量
+                LEFT JOIN (
+                SELECT
+                    b.goods_name,
+                    b.produce_date,  -- 必须加上生产日期
+                    sum(b.collect_number) AS num2
+                FROM
+                    psi_management_collect_detailed b
+                        LEFT JOIN psi_management_collect_basics c
+                                  ON b.basic_id = c.id AND c.del_flag = 0
+                WHERE
+                    b.collect_type = #{wareHouseType}
+                  AND b.goods_name = #{tradeName}
+                  AND b.del_flag = 0
+                  AND c.`status` = 5
+                -- 按商品  生产日期分组
+                GROUP BY b.goods_name, b.produce_date
+            ) c
+                          ON a.trade_name = c.goods_name
+                              AND a.produce_date = c.produce_date  -- 关键:按生产日期匹配
+        WHERE
+            a.ware_house_type = #{wareHouseType}
+          AND a.trade_name = #{tradeName}
+          AND a.del_flag = 0
+
+        GROUP BY a.id  -- 按库存分组
+        ORDER BY a.produce_date asc  -- 按生产日期排序
+    </select>
+</mapper>

+ 67 - 0
jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/psiWareHouse/mapper/xml/PsiWarehouseUpHiMapper.xml

@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper
+        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.jeeplus.psimanage.psiWareHouse.mapper.PsiWarehouseUpHiMapper">
+
+    <resultMap id="BaseResultMap" type="com.jeeplus.psimanage.psiWareHouse.domain.PsiWarehouseUpHi">
+            <id property="id" column="id" jdbcType="VARCHAR"/>
+            <result property="createById" column="create_by_id" jdbcType="VARCHAR"/>
+            <result property="createTime" column="create_time" jdbcType="TIMESTAMP"/>
+            <result property="updateById" column="update_by_id" jdbcType="VARCHAR"/>
+            <result property="updateTime" column="update_time" jdbcType="TIMESTAMP"/>
+            <result property="delFlag" column="del_flag" jdbcType="INTEGER"/>
+            <result property="remarks" column="remarks" jdbcType="VARCHAR"/>
+            <result property="warehouseId" column="warehouse_id" jdbcType="VARCHAR"/>
+            <result property="jsonData" column="json_data" jdbcType="VARCHAR"/>
+            <result property="endflag" column="endFlag" jdbcType="VARCHAR"/>
+    </resultMap>
+
+    <sql id="HI_Column_List">
+        hi.id,
+        hi.create_by_id,
+        hi.create_time,
+        hi.update_by_id,
+        hi.update_time,
+        hi.del_flag,
+        hi.remarks,
+        hi.warehouse_id,
+        hi.json_data,
+        hi.endFlag,
+        hi.update_user,
+        hi.update_trade_name,
+        hi.update_trade_type
+    </sql>
+
+    <select id="getSourceData" resultType="java.lang.String">
+        select
+            hi.json_data
+        from psi_management_warehouse_up_hi hi
+        where hi.del_flag = '0' and hi.warehouse_id = #{warehouseId} and hi.endFlag = '0'
+    </select>
+
+    <select id="findHiById" resultType="com.jeeplus.psimanage.psiWareHouse.domain.PsiWarehouseUpHi">
+        select
+        <include refid="HI_Column_List"></include>,
+        su.name as updateUser
+        from psi_management_warehouse_up_hi hi
+        left join sys_user su on su.id = hi.update_user
+        where hi.del_flag = '0' and hi.warehouse_id = #{id} and (hi.endFlag = '1' or hi.endFlag = '2')
+        order by hi.create_time desc
+    </select>
+    <select id="findHiByHiId" resultType="com.jeeplus.psimanage.psiWareHouse.domain.PsiWarehouseUpHi">
+        select
+        <include refid="HI_Column_List"></include>
+        from psi_management_warehouse_up_hi hi
+        where hi.del_flag = '0' and hi.id = #{hiId}
+    </select>
+
+    <select id="findLastHiByid" resultType="com.jeeplus.psimanage.psiWareHouse.domain.PsiWarehouseUpHi">
+        select
+        <include refid="HI_Column_List"></include>
+        from psi_management_warehouse_up_hi hi
+        where hi.del_flag = '0' and hi.warehouse_id = #{warehouseId}
+        order by hi.create_time desc
+        limit 1
+    </select>
+</mapper>

Plik diff jest za duży
+ 1283 - 0
jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/psiWareHouse/service/PsiWareHouseBasicService.java


+ 359 - 0
jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/psiWareHouse/service/dto/PsiWareHouseDto.java

@@ -0,0 +1,359 @@
+package com.jeeplus.psimanage.psiWareHouse.service.dto;
+
+import com.alibaba.excel.annotation.ExcelProperty;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.jeeplus.psimanage.purchase.domain.PsiMaterialDetailed;
+import com.jeeplus.psimanage.psiWareHouse.domain.PsiWareHouseDetailed;
+import com.jeeplus.psimanage.oss.service.dto.WorkAttachmentDto;
+import lombok.Data;
+
+import java.util.Date;
+import java.util.List;
+
+/**
+ * @author: 王强
+ * @create: 2022-12-29 16:37
+ **/
+@Data
+public class PsiWareHouseDto {
+
+    private String dateTest;
+
+    private String dateTest2;
+
+    /**
+     * 当前库存
+     */
+    private String currentInventory;
+
+    /**
+     * 采购申请查看入库记录所需
+     */
+    private String[] statusTwo;
+
+    //入库编号(字典值)
+    public static final String BIZ_CODE = "153";
+
+    private String procInsId;
+
+    private String processDefinitionId;
+
+    private String status;
+
+    /**
+     * 创建人
+     */
+    private String createBy;
+
+    /**
+     *创建时间
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    private Date createDate;
+
+    /**
+     * 基础表主键值
+     */
+    private String id;
+
+    /**
+     * 入库基础表id
+     */
+    private String basicId;
+
+    /**
+     * 入库类型
+     */
+    private String wareHouseType;
+
+    /**
+     * 领用类型
+     */
+    private String collectType;
+
+    /**
+     * 入库类型名称
+     */
+    private String wareHouseTypeName;
+
+    /**
+     * 商品名称
+     */
+    private String tradeName;
+
+    /**
+     * 商品单价
+     */
+    private String tradePrice;
+
+    /**
+     * 商品数量
+     */
+    private String tradeNumber;
+
+    /**
+     * 领用数量
+     */
+    private String collectNumber;
+
+    /**
+     * 单位
+     */
+    private String company;
+
+
+
+    /**
+     * 入库商品总价
+     */
+    private String wareHouseTotalPrice;
+
+    /**
+     * 入库商品实际价格
+     */
+    private String wareHouseActualPrice;
+
+    /**
+     * 实际价格
+     */
+    private String actualPrice;
+
+    /**
+     * 入库编号
+     */
+    private String wareHouseNumber;
+
+    /**
+     * 入库名称
+     */
+    private String wareHouseName;
+
+    /**
+     * 入库时间
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    private Date wareHouseDate;
+
+    /**
+     * 采购编号
+     */
+    private String purchaseNo;
+
+    /**
+     * 入库明细数据
+     */
+    @TableField(exist = false)
+    List<PsiWareHouseDetailed> wareHouse;
+
+    //采购明细信息
+    List<PsiMaterialDetailed> detailInfos;
+
+    /**
+     * 经办人
+     */
+    private String handledBy;
+
+    /**
+     * 经办人id
+     */
+    private String handledById;
+
+    /**
+     * 经办人名称
+     */
+    private String handleByName;
+
+    /**
+     * 经办人部门
+     */
+    private String handledByOffice;
+
+    /**
+     * 经办人部门名称
+     */
+    private String handledByOfficeName;
+
+    /**
+     * 入库时间
+     */
+    @TableField(exist = false)
+    private String[] wareHouseDates;
+
+    /**
+     * 领用时间
+     */
+    @TableField(exist = false)
+    private String[] collectDates;
+
+    private List<WorkAttachmentDto> files;
+
+    /**
+     * 入库人
+     */
+    private String wareHouseMan;
+
+    /**
+     * 入库人名称
+     */
+    private String wareHouseManName;
+
+    /**
+     * 入库人部门
+     */
+    private String wareHouseManOffice;
+
+    /**
+     * 入库人部门名称
+     */
+    private String wareHouseManOfficeName;
+
+    /**
+     * 采购申请id
+     */
+    private String purchaseId;
+
+    /**
+     * 备注
+     */
+    private String remarks;
+
+    /**
+     * 总量
+     */
+    private String allNumber;
+
+    /**
+     * 领用量
+     */
+    private String borrowNumber;
+
+    /**
+     * 入库id
+     */
+    private String wareHouseId;
+
+    /**
+     * 入库经办人
+     */
+    private String wareHouseHandledBy;
+
+    /**
+     * 入库经办人部门
+     */
+    private String wareHouseHandledByOff;
+
+    /**
+     * 领用id
+     */
+    private String collectId;
+
+    /**
+     * 领用经办人
+     */
+    private String collectHandleBy;
+
+    /**
+     * 领用经办人部门
+     */
+    private String collectHandleByOff;
+
+    /**
+     * 领用物品名称
+     */
+    private String goodsName;
+
+    /**
+     * 领用编号
+     */
+    private String collectNo;
+
+    /**
+     * 领用时间
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    private Date collectDate;
+
+    /**
+     * 合同编号
+     */
+    private String contractNo;
+
+    /**
+     * 入库 修改申请  taskId
+     */
+    private String taskId;
+
+    /**
+     * 数据审核人  入库 修改申请
+     */
+    private List<String> auditUserIds;
+
+    /**
+     * 当前所处节点执行的方法(送审、审核等..)
+     */
+    private String functionFlag;
+
+    /**
+     * 修改人
+     */
+    private String updateUser;
+
+    /**
+     * 修改原因
+     */
+    private String updateCause;
+
+    /**
+     * 警告数量
+     */
+    private String warnNum;
+
+    /**
+     * 警告标记  0不警告  1警告
+     */
+    private String warnFlag;
+
+    /**
+     * 供应商id
+     */
+    private String supplierId;
+
+    /**
+     * 入库详情id
+     */
+    private String detailId;
+
+    /**
+     * 旧 商品名称 (用于库存修改商品名称)
+     */
+    private String oldTradeName;
+
+    /**
+     * 包装规格
+     */
+    private String spec;
+
+    /**
+     * 生产日期
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
+    private Date produceDate;
+
+    /**
+     * 保质期
+     */
+    private String shelfLife;
+
+    /**
+     * 保质期单位
+     */
+    private String shelfLifeUnit;
+
+
+    /**
+     * 报损量
+     */
+    private String lossNumber;
+
+}

+ 57 - 0
jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/psiWareHouse/service/dto/PsiWareHouseExportDto.java

@@ -0,0 +1,57 @@
+package com.jeeplus.psimanage.psiWareHouse.service.dto;
+
+import com.alibaba.excel.annotation.ExcelIgnore;
+import com.alibaba.excel.annotation.ExcelProperty;
+import lombok.Data;
+
+@Data
+public class PsiWareHouseExportDto {
+
+    @ExcelIgnore
+    private String id;
+
+    @ExcelProperty("入库编号")
+    private String wareHouseNumber;
+
+    @ExcelProperty("入库人")
+    private String wareHouseMan;
+
+    @ExcelProperty("入库部门")
+    private String wareHouseManOffice;
+
+    @ExcelProperty("入库类型")
+    private String wareHouseType;
+
+    @ExcelProperty("商品名称")
+    private String tradeName;
+
+    @ExcelProperty("供应商")
+    private String supplierName;
+
+    @ExcelProperty("商品数量")
+    private String tradeNumber;
+
+    @ExcelProperty("单位")
+    private String company;
+
+    @ExcelProperty("包装规格")
+    private String spec;
+
+    @ExcelProperty("商品单价(元)")
+    private String tradePrice;
+
+    @ExcelProperty("商品总价")
+    private String priceSum;
+
+    @ExcelProperty("生产日期")
+    private String produceDate;
+
+    @ExcelProperty("保质期")
+    private String shelfLife;
+
+    @ExcelProperty("实际价格")
+    private String actualPrice;
+
+    @ExcelProperty("备注")
+    private String remarks;
+}

+ 38 - 0
jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/psiWareHouse/service/dto/PsiWareSummaryExportDto.java

@@ -0,0 +1,38 @@
+package com.jeeplus.psimanage.psiWareHouse.service.dto;
+
+import com.alibaba.excel.annotation.ExcelIgnore;
+import com.alibaba.excel.annotation.ExcelProperty;
+import lombok.Data;
+
+@Data
+public class PsiWareSummaryExportDto {
+
+    @ExcelIgnore
+    private String id;
+
+    @ExcelProperty("商品名称")
+    private String tradeName;
+
+    @ExcelProperty("总量")
+    private String allNumber;
+
+    @ExcelProperty("领用量")
+    private String borrowNumber;
+
+    @ExcelProperty("报损量")
+    private String lossNumber;
+
+    @ExcelProperty("剩余量")
+    private String tradeNumber;
+
+    @ExcelProperty("单位")
+    private String company;
+
+    @ExcelProperty("提醒数量")
+    private String warnNum;
+
+    @ExcelProperty("是否提醒")
+    private String warnFlag;
+
+
+}

+ 94 - 0
jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/purchase/controller/PsiMaterialController.java

@@ -0,0 +1,94 @@
+package com.jeeplus.psimanage.purchase.controller;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.jeeplus.common.excel.EasyExcelUtils;
+import com.jeeplus.common.excel.ExcelOptions;
+import com.jeeplus.common.excel.annotation.ExportMode;
+import com.jeeplus.common.utils.ResponseUtil;
+import com.jeeplus.logging.annotation.ApiLog;
+import com.jeeplus.logging.constant.enums.LogTypeEnum;
+import com.jeeplus.psimanage.purchase.domain.PsiMaterialDetailed;
+import com.jeeplus.psimanage.purchase.service.PsiMaterialService;
+import com.jeeplus.psimanage.purchase.service.dto.PsiMaterialExportDto;
+import com.jeeplus.psimanage.purchase.service.dto.PsiMaterialInfoDto;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletResponse;
+import java.util.List;
+import java.util.stream.Collectors;
+
+@RestController
+@Api(tags = "物资管理-采购申请")
+@RequestMapping(value = "/psi/management")
+public class PsiMaterialController {
+
+    @Resource
+    private PsiMaterialService service;
+
+    @ApiOperation(value = "列表查询")
+    @GetMapping("/list")
+    public ResponseEntity<IPage<PsiMaterialInfoDto>> list(Page<PsiMaterialInfoDto> page, PsiMaterialInfoDto dto) throws Exception {
+        IPage<PsiMaterialInfoDto> iPage = service.list(page, dto);
+        return ResponseEntity.ok(iPage);
+    }
+
+    @ApiLog(value = "导出采购申请数据", type = LogTypeEnum.EXPORT)
+    @ApiOperation(value = "导出采购申请数据")
+    @GetMapping("/exportFile")
+    public void exportFile(Page<PsiMaterialInfoDto> page, PsiMaterialInfoDto dto, ExcelOptions options, HttpServletResponse response) throws Exception {
+        String fileName = options.getFilename();
+        String sheetName = options.getSheetName();
+        List<PsiMaterialExportDto> result;
+        if (ExportMode.current.equals(options.getMode())) {
+            result = service.exportList(page, dto);
+        } else if (ExportMode.selected.equals(options.getMode())) {
+            result = service.exportList(page, dto).stream().filter(item ->
+                    options.getSelectIds().contains(item.getId())
+            ).collect(Collectors.toList());
+        } else {
+            page.setSize(-1);
+            page.setCurrent(0);
+            result = service.exportList(page, dto);
+        }
+        EasyExcelUtils.newInstance().exportExcel(result, sheetName, PsiMaterialExportDto.class, fileName, null, response);
+    }
+
+    @ApiOperation(value = "新增、修改")
+    @PostMapping("/save")
+    public ResponseEntity<String> save(@RequestBody PsiMaterialInfoDto dto) throws Exception {
+        String s = service.save(dto);
+        return ResponseUtil.newInstance().add("businessTable", "psi_management_pruchase_request_basics").add("businessId", s).ok("操作成功");
+    }
+
+    @ApiOperation(value = "查询")
+    @GetMapping("/findById")
+    public ResponseEntity<PsiMaterialInfoDto> findById(@RequestParam String id) throws Exception {
+        PsiMaterialInfoDto dto = service.findById(id);
+        return ResponseEntity.ok(dto);
+    }
+
+    @ApiOperation(value = "删除")
+    @GetMapping("/remove")
+    public ResponseEntity<String> remove(@RequestParam String id) {
+        String s = service.remove(id);
+        return ResponseEntity.ok(s);
+    }
+
+    @ApiOperation(value = "根据id修改状态status")
+    @PostMapping(value = "updateStatusById")
+    public void updateStatusById(@RequestBody PsiMaterialInfoDto dto) {
+        service.updateStatusById(dto);
+    }
+
+    @ApiOperation(value = "根据采购类型查询商品")
+    @GetMapping("/findTradeByTypeId")
+    public ResponseEntity<List<PsiMaterialDetailed>> findTradeByTypeId(@RequestParam String typeId) {
+        List<PsiMaterialDetailed> res = service.findTradeByTypeId(typeId);
+        return ResponseEntity.ok(res);
+    }
+}

+ 74 - 0
jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/purchase/domain/PsiMaterialBasic.java

@@ -0,0 +1,74 @@
+package com.jeeplus.psimanage.purchase.domain;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.jeeplus.core.domain.BaseEntity;
+import lombok.Data;
+
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 物资管理-采购基础表
+ * @author: 王强
+ * @create: 2022-12-02 16:40
+ **/
+@Data
+@TableName("psi_management_pruchase_request_basics")
+public class PsiMaterialBasic extends BaseEntity {
+
+    //采购编号(字典值)
+    public static final String BIZ_CODE = "150";
+
+    /**
+     * 流程id
+     */
+    private String procInsId;
+
+    /**
+     * 状态
+     */
+    private String status;
+
+    private String processDefinitionId;
+
+    /**
+     * 采购编号
+     */
+    private String purchaseNo;
+
+    /**
+     * 采购简述
+     */
+    private String purchaseSketch;
+
+    /**
+     * 经办人
+     */
+    private String handledBy;
+
+    /**
+     * 经办人部门
+     */
+    private String handledByOffice;
+
+    /**
+     * 经办人部门
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    private Date purchaseDate;
+
+    /**
+     * 采购方式
+     */
+    private String purchaseMode;
+
+    /**
+     * 备注
+     */
+    private String remarks;
+
+    @TableField(exist = false)
+    List<PsiMaterialDetailed> detailInfos;
+}

+ 124 - 0
jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/purchase/domain/PsiMaterialDetailed.java

@@ -0,0 +1,124 @@
+package com.jeeplus.psimanage.purchase.domain;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.jeeplus.core.domain.BaseEntity;
+import com.jeeplus.psimanage.oss.service.dto.WorkAttachmentDto;
+import lombok.Data;
+
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 采购明细表
+ * @author: 王强
+ * @create: 2022-12-02 16:46
+ **/
+@Data
+@TableName("psi_management_pruchase_request_detailed")
+public class PsiMaterialDetailed extends BaseEntity {
+
+    /**
+     * 采购基础表id
+     */
+    private String basicId;
+
+    /**
+     * 采购人
+     */
+    private String purchaserAgent;
+
+    /**
+     * 采购人id
+     */
+    @TableField(exist = false)
+    private String purchaserAgentId;
+
+    /**
+     * 采购部门
+     */
+    @TableField(exist = false)
+    private String procurementOffice;
+
+    /**
+     * 采购类型
+     */
+    private String procurementType;
+
+    /**
+     * 采购类型id
+     */
+    @TableField(exist = false)
+    private String procurementTypeId;
+
+    /**
+     * 商品名称
+     */
+    private String tradeName;
+
+    /**
+     * 商品单价
+     */
+    private String tradePrice;
+
+    /**
+     * 商品数量
+     */
+    private String tradeNumber;
+
+    /**
+     * 单位
+     */
+    private String company;
+
+    /**
+     * 商品总价
+     */
+    private String tradeTotalPrice;
+
+    //附件信息
+    @TableField(exist = false)
+    List<WorkAttachmentDto> fileInfoLost;
+
+    /**
+     * 备注
+     */
+    private String remarks;
+
+    /**
+     * 供应商id
+     */
+    private String supplierId;
+
+    /**
+     * 供应商名称
+     */
+    private String supplierName;
+
+    /**
+     * 1手填供应商  2选择供应商
+     */
+    private String isSupplier;
+
+    /**
+     * 包装规格
+     */
+    private String spec;
+
+    /**
+     * 生产日期
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
+    private Date produceDate;
+
+    /**
+     * 保质期
+     */
+    private String shelfLife;
+
+    /**
+     * 保质期单位
+     */
+    private String shelfLifeUnit;
+}

+ 43 - 0
jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/purchase/mapper/PsiMaterialBasicMapper.java

@@ -0,0 +1,43 @@
+package com.jeeplus.psimanage.purchase.mapper;
+
+import com.baomidou.mybatisplus.annotation.InterceptorIgnore;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.core.toolkit.Constants;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.jeeplus.psimanage.oss.domain.PsiWorkAttachment;
+import com.jeeplus.psimanage.purchase.domain.PsiMaterialBasic;
+import com.jeeplus.psimanage.purchase.service.dto.PsiMaterialInfoDto;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+/**
+ * @author: 王强
+ * @create: 2022-12-02 16:57
+ **/
+public interface PsiMaterialBasicMapper extends BaseMapper<PsiMaterialBasic> {
+
+    Integer findIsExit(@Param("id") String id, @Param("name")String name);
+
+    List<PsiWorkAttachment> findFileList(@Param("id") String id);
+
+    List<String> findChildIds(String department);
+
+    IPage<PsiMaterialInfoDto> findList(Page<PsiMaterialInfoDto> page, @Param(Constants.WRAPPER) QueryWrapper<PsiMaterialInfoDto> queryWrapper);
+
+    void updateStatusById(@Param("id") String id, @Param("type") String type);
+
+    String getHandledName(String handledBy);
+
+    /**
+     * 根据采购编号查相关数据
+     * @param purchaseNo
+     * @return
+     */
+    PsiMaterialBasic getInfoByPurchaseNo(String purchaseNo);
+
+    @InterceptorIgnore(tenantLine = "true")
+    PsiMaterialInfoDto getUserNameByUserId(String handledBy);
+}

+ 24 - 0
jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/purchase/mapper/PsiMaterialDetailedMapper.java

@@ -0,0 +1,24 @@
+package com.jeeplus.psimanage.purchase.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.jeeplus.psimanage.purchase.domain.PsiMaterialDetailed;
+import com.jeeplus.psimanage.oss.service.dto.WorkAttachmentDto;
+
+import java.util.List;
+
+/**
+ * @author: 王强
+ * @create: 2022-12-02 17:26
+ **/
+public interface PsiMaterialDetailedMapper extends BaseMapper<PsiMaterialDetailed> {
+    //根据基础表id查出详情数据
+    List<PsiMaterialDetailed> getByBasicId(String basicId);
+
+    //查出附件信息
+    List<WorkAttachmentDto> getByAttachmentId(String id);
+
+    List<String> getIdByBasicId(String id);
+
+    // 根据采购类型查询商品
+    List<PsiMaterialDetailed> getByTypeId(String typeId);
+}

+ 71 - 0
jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/purchase/mapper/xml/PsiMaterialBasicMapper.xml

@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.jeeplus.psimanage.purchase.mapper.PsiMaterialBasicMapper">
+    <update id="updateStatusById">
+		UPDATE psi_management_pruchase_request_basics SET status = #{type}
+		WHERE id = #{id}
+	</update>
+    <select id="findList" resultType="com.jeeplus.psimanage.purchase.service.dto.PsiMaterialInfoDto">
+        SELECT
+        	DISTINCT
+			a.id,
+			a.create_by_id as createBy,
+			a.create_time as createDate,
+			a.purchase_no,
+			a.purchase_sketch,
+			a.handled_by,
+			a.handled_by_office,
+			a.purchase_date,
+			a.purchase_mode as purchaseModeType,
+			(case a.purchase_mode
+				when 1 then '办公室采购'
+				when 2 then '自行采购'
+				end
+			) as purchase_mode,
+			a.status,
+			a.proc_ins_id,
+			a.process_definition_id,
+			b.trade_total_price,
+			so.name as handledByOfficeName,
+			su.name as handledByName,
+			art.ID_ as task_id
+		FROM
+			psi_management_pruchase_request_basics a
+			left join sys_user su on a.handled_by = su.id
+			left join sys_office so on a.handled_by_office = so.id
+			left join psi_management_pruchase_request_detailed b
+			on a.id = b.basic_id and b.del_flag = '0'
+			left join act_ru_task art ON a.proc_ins_id = art.PROC_INST_ID_
+			left join sys_user_manage_office sumo on sumo.office_id = su.office_id
+			${ew.customSqlSegment}
+		ORDER BY a.update_time DESC
+    </select>
+	<select id="findChildIds" resultType="java.lang.String">
+		select id from sys_office where parent_id = #{department}
+	</select>
+	<select id="getHandledName" resultType="java.lang.String">
+		select name from sys_user where id = #{handledBy}
+	</select>
+    <select id="getInfoByPurchaseNo"
+            resultType="com.jeeplus.psimanage.purchase.domain.PsiMaterialBasic">
+		select * from psi_management_pruchase_request_basics where purchase_no = #{purchaseNo}
+	</select>
+    <select id="getUserNameByUserId" resultType="com.jeeplus.psimanage.purchase.service.dto.PsiMaterialInfoDto">
+		select su.name as handledBy,so.name as handledByOfficeName from sys_user su
+		left join sys_office so on su.office_id = so.id
+		where su.id = #{id}
+	</select>
+    <select id="findFileList" resultType="com.jeeplus.psimanage.oss.domain.PsiWorkAttachment">
+		SELECT * FROM work_attachment WHERE del_flag = 0 AND attachment_id = #{id}
+	</select>
+	<select id="findIsExit" resultType="java.lang.Integer">
+		SELECT
+			COUNT( 0 )
+		FROM
+			work_attachment
+		WHERE
+			del_flag = 0
+			AND attachment_id = #{id}
+			AND attachment_name = #{name}
+	</select>
+</mapper>

+ 44 - 0
jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/purchase/mapper/xml/PsiMaterialDetailedMapper.xml

@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.jeeplus.psimanage.purchase.mapper.PsiMaterialDetailedMapper">
+    <select id="getByBasicId" resultType="com.jeeplus.psimanage.purchase.domain.PsiMaterialDetailed">
+        select a.*,su.name as purchaserAgent,su.id as purchaserAgentId,
+        so.name as procurementOffice,d.id as procurementTypeId, d.name as procurementType
+        from psi_management_pruchase_request_detailed a
+        left join sys_user su on a.purchaser_agent = su.id
+        left join sys_office so on su.office_id = so.id
+        left join psi_management_type d on a.procurement_type = d.id
+        where a.basic_id = #{basicId} and a.del_flag = '0'
+    </select>
+    <select id="getByAttachmentId" resultType="com.jeeplus.psimanage.oss.service.dto.WorkAttachmentDto">
+        SELECT
+			id,
+			url,
+			attachment_name AS `name`,
+			create_by_id AS `by`,
+			create_time
+		FROM
+			work_attachment
+		WHERE
+			del_flag = 0
+			AND attachment_id = #{id}
+    </select>
+    <select id="getIdByBasicId" resultType="java.lang.String">
+        select a.id from psi_management_pruchase_request_detailed a where a.basic_id = #{id} and a.del_flag = 0
+    </select>
+
+    <select id="getByTypeId" resultType="com.jeeplus.psimanage.purchase.domain.PsiMaterialDetailed">
+        SELECT
+            id,
+            trade_name
+        FROM
+            psi_management_warehouse_detailed
+        WHERE
+            del_flag = '0'
+            AND ware_house_type = #{typeId}
+        GROUP BY
+            trade_name
+        ORDER BY
+            create_time DESC
+    </select>
+</mapper>

+ 577 - 0
jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/purchase/service/PsiMaterialService.java

@@ -0,0 +1,577 @@
+package com.jeeplus.psimanage.purchase.service;
+
+import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.extra.spring.SpringUtil;
+import com.alibaba.fastjson.JSON;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.jeeplus.common.TokenProvider;
+import com.jeeplus.core.query.QueryWrapperGenerator;
+import com.jeeplus.flowable.feign.IFlowableApi;
+import com.jeeplus.psimanage.oss.domain.PsiWorkAttachment;
+import com.jeeplus.psimanage.purchase.domain.PsiMaterialBasic;
+import com.jeeplus.psimanage.purchase.domain.PsiMaterialDetailed;
+import com.jeeplus.psimanage.purchase.mapper.PsiMaterialBasicMapper;
+import com.jeeplus.psimanage.purchase.mapper.PsiMaterialDetailedMapper;
+import com.jeeplus.psimanage.purchase.service.dto.PsiMaterialExportDto;
+import com.jeeplus.psimanage.purchase.service.dto.PsiMaterialInfoDto;
+import com.jeeplus.psimanage.supplier.domain.PsiMaterialSupplier;
+import com.jeeplus.psimanage.supplier.mapper.PsiMaterialSupplierMapper;
+import com.jeeplus.psimanage.oss.service.dto.WorkAttachmentDto;
+import com.jeeplus.psimanage.serialNumTpl.service.PsiSerialnumTplService;
+import com.jeeplus.sys.feign.IDictApi;
+import com.jeeplus.sys.feign.IUserApi;
+import com.jeeplus.sys.feign.IWorkAttachmentApi;
+import com.jeeplus.sys.service.dto.UserDTO;
+import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
+import com.jeeplus.utils.StringUtils;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.stereotype.Service;
+
+import org.springframework.beans.BeanUtils;
+import org.springframework.transaction.annotation.Transactional;
+
+import javax.annotation.Resource;
+import java.math.BigDecimal;
+import java.text.SimpleDateFormat;
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * @author: 王强
+ * @create: 2022-12-02 16:26
+ **/
+@Service
+public class PsiMaterialService {
+
+    @Resource
+    private PsiMaterialBasicMapper basicMapper;
+
+    @Resource
+    private PsiSerialnumTplService psiSerialnumTplService;
+
+    @Resource
+    private PsiMaterialDetailedMapper psiDetailedMapper;
+
+//    @Resource
+//    private OssServiceMapper ossServiceMapper;
+
+    @Resource
+    private IFlowableApi flowTaskService;
+
+    @Resource
+    private PsiMaterialSupplierMapper psiMaterialSupplierMapper;
+
+    /**
+     * 列表查询
+     */
+    public IPage<PsiMaterialInfoDto> list(Page<PsiMaterialInfoDto> page , PsiMaterialInfoDto dto) throws Exception{
+        QueryWrapper<PsiMaterialInfoDto> queryWrapper = QueryWrapperGenerator.buildQueryCondition(dto, PsiMaterialInfoDto.class);
+
+        queryWrapper.eq("a.del_flag", "0");
+        if (StringUtils.isNotEmpty(dto.getPurchaseSketch())) {
+            queryWrapper.like("a.purchase_sketch", dto.getPurchaseSketch());
+        }
+        if (StringUtils.isNotEmpty(dto.getHandledByOffice())) {
+            //先根据id查出是否是父节点,是父节点则查出所有的子节点信息
+            List<String> childIds = basicMapper.findChildIds(dto.getHandledByOffice());
+            if ( null != childIds & childIds.size()>0){
+                childIds.add(dto.getHandledByOffice());
+                queryWrapper.in("a.handled_by_office",childIds);
+            }else {
+                queryWrapper.eq("a.handled_by_office", dto.getHandledByOffice());
+            }
+        }
+        if (StringUtils.isNotEmpty(dto.getStatus())) {
+            queryWrapper.like("a.status", dto.getStatus());
+        }
+        //采购类别
+        if (StringUtils.isNotEmpty(dto.getProcurementType())) {
+            queryWrapper.like("b.procurement_type", dto.getProcurementType());
+        }
+        //经办人
+        if (StringUtils.isNotEmpty(dto.getHandledBy())) {
+            //根据经办人id查出经办人名称
+//            String name = basicMapper.getHandledName(dto.getHandledBy());
+//            dto.setHandledBy(name);
+            queryWrapper.eq("su.id", dto.getHandledBy());
+        }
+        //合同金额
+        //3、合同金额(区间)
+        String[] contractAmounts = dto.getContractAmounts();
+        if (contractAmounts != null) {
+            if (StringUtils.isNotEmpty(contractAmounts[0])) {
+                queryWrapper.ge("b.trade_total_price",contractAmounts[0]);
+            }
+            if (contractAmounts.length>1 && StringUtils.isNotEmpty(contractAmounts[1])) {
+                queryWrapper.le("b.trade_total_price", contractAmounts[1]);
+            }
+        }
+        String[] contractDates = dto.getContractDates();
+        if (contractDates != null) {
+
+            queryWrapper.between("a.create_time", contractDates[0], contractDates[1]);
+        }
+        if (ObjectUtil.isNotEmpty(dto)) {
+            if (StringUtils.isNotBlank(dto.getSupplierId())) {
+                List<PsiMaterialDetailed> materialDetailedList = psiDetailedMapper.selectList(new LambdaQueryWrapper<PsiMaterialDetailed>().eq(PsiMaterialDetailed::getSupplierId, dto.getSupplierId()));
+                if (CollectionUtil.isNotEmpty(materialDetailedList)) {
+                    List<String> containsIds = materialDetailedList.stream().map(PsiMaterialDetailed::getBasicId).collect(Collectors.toList());
+                    if (CollectionUtil.isNotEmpty(containsIds)) {
+                        queryWrapper.in("a.id", containsIds);
+                    } else {
+                        return new Page<>();
+                    }
+                } else {
+                    return new Page<>();
+                }
+            }
+        }
+        IPage<PsiMaterialInfoDto> list = basicMapper.findList(page, queryWrapper);
+        list.getRecords().stream().forEach(item -> {
+            // 采购申请
+            if (StringUtils.isNotBlank(item.getTaskId()) && StringUtils.isNotBlank(item.getStatus())) {
+                if ("2".equals(item.getStatus())) { // “审核中”的数据要获取数据审核人
+                    item.setAuditUserIds(flowTaskService.getTaskAuditUsers(item.getTaskId()));  // 获取数据审核人
+                }
+            }
+        });
+        return list;
+    }
+
+    /**
+     * 列表查询(报销使用)
+     */
+    public IPage<PsiMaterialInfoDto> reimbursementList(Page<PsiMaterialInfoDto> page , PsiMaterialInfoDto dto) throws Exception{
+        QueryWrapper<PsiMaterialInfoDto> queryWrapper = QueryWrapperGenerator.buildQueryCondition(dto, PsiMaterialInfoDto.class);
+
+        queryWrapper.eq("a.del_flag", "0");
+        queryWrapper.eq("a.create_by_id", SpringUtil.getBean ( IUserApi.class ).getByToken (TokenProvider.getCurrentToken ( )).getId());
+        if (StringUtils.isNotEmpty(dto.getPurchaseSketch())) {
+            queryWrapper.like("a.purchase_sketch", dto.getPurchaseSketch());
+        }
+        if (StringUtils.isNotEmpty(dto.getHandledByOffice())) {
+            //先根据id查出是否是父节点,是父节点则查出所有的子节点信息
+            List<String> childIds = basicMapper.findChildIds(dto.getHandledByOffice());
+            if ( null != childIds & childIds.size()>0){
+                childIds.add(dto.getHandledByOffice());
+                queryWrapper.in("a.handled_by_office",childIds);
+            }else {
+                queryWrapper.eq("a.handled_by_office", dto.getHandledByOffice());
+            }
+        }
+        if (StringUtils.isNotEmpty(dto.getStatus())) {
+            queryWrapper.like("a.status", dto.getStatus());
+        }
+        //采购类别
+        if (StringUtils.isNotEmpty(dto.getProcurementType())) {
+            queryWrapper.like("b.procurement_type", dto.getProcurementType());
+        }
+        //经办人
+        if (StringUtils.isNotEmpty(dto.getHandledBy())) {
+            //根据经办人id查出经办人名称
+//            String name = basicMapper.getHandledName(dto.getHandledBy());
+//            dto.setHandledBy(name);
+            queryWrapper.eq("su.name", dto.getHandledBy());
+        }
+        //合同金额
+        //3、合同金额(区间)
+        String[] contractAmounts = dto.getContractAmounts();
+        if (contractAmounts != null) {
+            if (StringUtils.isNotEmpty(contractAmounts[0])) {
+                queryWrapper.ge("b.trade_total_price",contractAmounts[0]);
+            }
+            if (StringUtils.isNotEmpty(contractAmounts[1])) {
+                queryWrapper.le("b.trade_total_price", contractAmounts[1]);
+            }
+        }
+        String[] contractDates = dto.getContractDates();
+        if (contractDates != null) {
+
+            queryWrapper.between("a.create_time", contractDates[0], contractDates[1]);
+        }
+        IPage<PsiMaterialInfoDto> list = basicMapper.findList(page, queryWrapper);
+        list.getRecords().stream().forEach(item -> {
+            // 采购申请
+            if (StringUtils.isNotBlank(item.getTaskId()) && StringUtils.isNotBlank(item.getStatus())) {
+                if ("2".equals(item.getStatus())) { // “审核中”的数据要获取数据审核人
+                    item.setAuditUserIds(flowTaskService.getTaskAuditUsers(item.getTaskId()));  // 获取数据审核人
+                }
+            }
+        });
+        return list;
+    }
+
+    public List<PsiMaterialExportDto> exportList(Page<PsiMaterialInfoDto> page , PsiMaterialInfoDto dto) throws Exception{
+        List<PsiMaterialInfoDto> records = this.list(page, dto).getRecords();
+        List<PsiMaterialExportDto> result = new ArrayList<>();
+        if (CollectionUtils.isEmpty(records)) {
+            return result;
+        }
+        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
+        records.forEach(item -> {
+            PsiMaterialExportDto exportDto = new PsiMaterialExportDto();
+            exportDto.setId(item.getId());
+            exportDto.setPurchaseNo(item.getPurchaseNo());
+            exportDto.setPurchaseSketch(item.getPurchaseSketch());
+            exportDto.setPurchaseMode(item.getPurchaseMode());
+            exportDto.setTradeTotalPrice(formatExportNumber(item.getTradeTotalPrice()));
+            exportDto.setHandledByName(item.getHandledByName());
+            exportDto.setHandledByOfficeName(item.getHandledByOfficeName());
+            exportDto.setCreateDate(item.getCreateDate() == null ? "" : dateFormat.format(item.getCreateDate()));
+            exportDto.setStatus(StringUtils.isBlank(item.getStatus()) ? "" : SpringUtil.getBean(IDictApi.class).getDictLabel(item.getStatus(), "cw_status", ""));
+            result.add(exportDto);
+        });
+        return result;
+    }
+
+    private String formatExportNumber(String value) {
+        if (StringUtils.isBlank(value)) {
+            return "";
+        }
+        try {
+            return new BigDecimal(value).stripTrailingZeros().toPlainString();
+        } catch (Exception e) {
+            return value;
+        }
+    }
+
+    public String save(PsiMaterialInfoDto dto) throws Exception{
+        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
+        String bearerToken = authentication.getCredentials().toString();
+        // 获取当前登录人信息
+        UserDTO userDTO = SpringUtil.getBean ( IUserApi.class ).getByToken (TokenProvider.getCurrentToken ( ));
+        if (StringUtils.isNotEmpty(dto.getId()) && !dto.getId().equals("false")) {
+            return update(dto, userDTO);
+        } else {
+            return add(dto, userDTO);
+        }
+    }
+
+    public String add(PsiMaterialInfoDto dto, UserDTO userDTO) throws Exception{
+        // 生成id
+        String id = UUID.randomUUID().toString().replace("-", "");
+        // 生成编号
+        String no = psiSerialnumTplService.genSerialNum(userDTO.getCompanyDTO().getId(), dto.BIZ_CODE,TokenProvider.getCurrentToken());
+        // 保存基础信息表信息
+        PsiMaterialBasic info = new PsiMaterialBasic();
+        BeanUtils.copyProperties(dto, info);
+        info.setId(id);
+//        info.setNo(no);
+        info.setPurchaseNo(no);
+        info.setHandledBy(dto.getHandledById());
+        info.setCreateById(userDTO.getId());
+        info.setCreateTime(new Date());
+        info.setUpdateById(userDTO.getId());
+        info.setUpdateTime(new Date());
+        info.setDelFlag(0);
+        basicMapper.insert(info);
+        // 保存详情列表信息
+        if (CollectionUtils.isNotEmpty(dto.getDetailInfos())) {
+            for (PsiMaterialDetailed detailed : dto.getDetailInfos()) {
+                // 生成id
+                String detailId = UUID.randomUUID().toString().replace("-", "");
+                detailed.setId(detailId);
+                detailed.setPurchaserAgent(detailed.getPurchaserAgentId());
+                detailed.setProcurementType(detailed.getProcurementTypeId());
+                detailed.setCreateById(userDTO.getId());
+                detailed.setCreateTime(new Date());
+                detailed.setUpdateById(userDTO.getId());
+                detailed.setUpdateTime(new Date());
+                detailed.setDelFlag(0);
+                // 保存基础表信息主键值
+                detailed.setBasicId(id);
+                detailed.setTradeTotalPrice(dto.getTradeTotalPrice());
+                psiDetailedMapper.insert(detailed);
+                //保存详情列表附件信息
+                if (CollectionUtils.isNotEmpty(detailed.getFileInfoLost())){
+                    saveFiles(detailed.getFileInfoLost(), userDTO, detailId);
+                }
+
+            }
+        }
+        // 保存附件列表信息
+        if (CollectionUtils.isNotEmpty(dto.getFiles())) {
+            saveFiles(dto.getFiles(), userDTO, id);
+        }
+        return id;
+    }
+
+    public String update(PsiMaterialInfoDto dto, UserDTO userDTO) {
+        // 修改基础信息
+        PsiMaterialBasic info = new PsiMaterialBasic();
+        BeanUtils.copyProperties(dto, info);
+        info.setUpdateById(userDTO.getId());
+        info.setHandledBy(dto.getHandledById());
+        info.setUpdateTime(new Date());
+        basicMapper.updateById(info);
+        // 修改报销详情列表信息
+        // 删除原有数据
+//        LambdaQueryWrapper<MaterialDetailed> detailWrapper = new LambdaQueryWrapper<>();
+//        detailWrapper.eq(MaterialDetailed::getBasicId, dto.getId());
+//        psiDetailedMapper.delete(detailWrapper);
+        if (CollectionUtils.isNotEmpty(dto.getDetailInfos())) {
+
+            List<String> idList = psiDetailedMapper.getIdByBasicId(info.getId());
+            for (PsiMaterialDetailed detailInfo : dto.getDetailInfos()) {
+                //删除多余的领用详情
+                //根据基础表id获取所有的详情表id
+                if (null != idList) {
+                    if (idList.contains(detailInfo.getId())){
+                        idList.remove(detailInfo.getId());
+                    }
+                }
+            }
+            if (null != idList & idList.size()>0) {
+                idList.forEach(id->{
+                    psiDetailedMapper.deleteById(id);
+                });
+            }
+
+            for (PsiMaterialDetailed detailInfo : dto.getDetailInfos()) {
+                PsiMaterialDetailed materialDetailed = psiDetailedMapper.selectById(detailInfo.getId());
+                if ( null == materialDetailed) {
+                    // 生成id
+                    String detailId = UUID.randomUUID().toString().replace("-", "");
+                    detailInfo.setId(detailId);
+                    detailInfo.setPurchaserAgent(detailInfo.getPurchaserAgentId());
+                    detailInfo.setProcurementType(detailInfo.getProcurementTypeId());
+                    detailInfo.setCreateById(userDTO.getId());
+                    detailInfo.setCreateTime(new Date());
+                    detailInfo.setUpdateById(userDTO.getId());
+                    detailInfo.setUpdateTime(new Date());
+                    detailInfo.setDelFlag(0);
+                    // 保存基础表信息主键值
+                    detailInfo.setBasicId(dto.getId());
+                    detailInfo.setTradeTotalPrice(dto.getTradeTotalPrice());
+                    psiDetailedMapper.insert(detailInfo);
+                    // 修改附件信息列表
+                    if (CollectionUtils.isNotEmpty(detailInfo.getFileInfoLost())) {
+                        saveFiles(detailInfo.getFileInfoLost(), userDTO, detailInfo.getId());
+                    }
+                } else {
+                    detailInfo.setPurchaserAgent(detailInfo.getPurchaserAgentId());
+                    detailInfo.setProcurementType(detailInfo.getProcurementTypeId());
+                    detailInfo.setUpdateById(userDTO.getId());
+                    detailInfo.setUpdateTime(new Date());
+                    detailInfo.setBasicId(dto.getId());
+                    detailInfo.setTradeTotalPrice(dto.getTradeTotalPrice());
+                    psiDetailedMapper.updateById(detailInfo);
+                    if (CollectionUtils.isNotEmpty(detailInfo.getFileInfoLost())) {
+                        updateFiles(detailInfo.getFileInfoLost(), userDTO, detailInfo.getId());
+                    }
+                }
+
+            }
+        }
+        // 修改附件信息列表
+        if (CollectionUtils.isNotEmpty(dto.getFiles())) {
+            updateFiles(dto.getFiles(), userDTO, dto.getId());
+        }
+        return dto.getId();
+    }
+
+    public PsiMaterialInfoDto findById(String id) {
+        PsiMaterialInfoDto dto = new PsiMaterialInfoDto();
+        // 查询基础信息表
+        PsiMaterialBasic info = basicMapper.selectById(id);
+        if (ObjectUtils.isNotEmpty(info)) {
+            BeanUtils.copyProperties(info, dto);
+            //将采购详情数据查出
+            List<PsiMaterialDetailed> detailedList = psiDetailedMapper.getByBasicId(id);
+            if (CollectionUtils.isNotEmpty(detailedList)){
+                detailedList.forEach(detailed->{
+                    // 供应商查询
+                    if (StringUtils.isNotBlank(detailed.getIsSupplier()) && "2".equals(detailed.getIsSupplier()) &&
+                            StringUtils.isNotBlank(detailed.getSupplierId())) {
+                        PsiMaterialSupplier materialSupplier = psiMaterialSupplierMapper.selectById(detailed.getSupplierId()); // 供应商信息
+                        if (ObjectUtil.isNotEmpty(materialSupplier)) {
+                            detailed.setSupplierName(materialSupplier.getName());
+                        }
+                    }
+                    //附件信息
+                    List<WorkAttachmentDto> acList = psiDetailedMapper.getByAttachmentId(detailed.getId());
+                    if (CollectionUtils.isNotEmpty(acList)) {
+                        for (WorkAttachmentDto i : acList) {
+                            i.setCreateBy(SpringUtil.getBean ( IUserApi.class ).getById(i.getBy()));
+                        }
+                    }
+                    detailed.setFileInfoLost(acList);
+                });
+            }
+            dto.setDetailInfos(detailedList);
+            //附件信息
+            List<WorkAttachmentDto> files = psiDetailedMapper.getByAttachmentId(info.getId());
+            if (CollectionUtils.isNotEmpty(files)) {
+                for (WorkAttachmentDto i : files) {
+                    i.setCreateBy(SpringUtil.getBean ( IUserApi.class ).getById(i.getBy()));
+                }
+            }
+            //根据经办人id查出经办人的名称
+            PsiMaterialInfoDto infoDto = basicMapper.getUserNameByUserId(info.getHandledBy());
+            dto.setHandledBy(infoDto.getHandledBy());
+            dto.setHandledById(info.getHandledBy());
+            //设置经办人部门名称
+
+            dto.setHandledByOfficeName(infoDto.getHandledByOfficeName());
+            dto.setFiles(files);
+        }
+        return dto;
+    }
+
+    public String remove(String id) {
+        // 删除基础信息表
+        basicMapper.deleteById(id);
+        // 删除详情列表 及对应附件信息
+        List<PsiMaterialDetailed> detailedList = psiDetailedMapper.getByBasicId(id);
+        if (null != detailedList){
+            detailedList.forEach(de->{
+                //附件
+                List<WorkAttachmentDto> fileList = psiDetailedMapper.getByAttachmentId(de.getId());
+                if ( null != fileList ){
+                    fileList.forEach(f->{
+//                        ossServiceMapper.deleteById(f.getId());
+                        SpringUtil.getBean ( IWorkAttachmentApi.class ).deleteById(f.getId());
+                    });
+                }
+                psiDetailedMapper.deleteById(de.getId());
+            });
+        }
+        // 删除附件信息
+        SpringUtil.getBean ( IWorkAttachmentApi.class ).deleteByAttachmentId(id);
+//        LambdaQueryWrapper<WorkAttachment> wrapper = new LambdaQueryWrapper<>();
+//        wrapper.eq(WorkAttachment::getAttachmentId, id);
+//        ossServiceMapper.delete(wrapper);
+        return "操作成功";
+    }
+
+    public void updateStatusById(PsiMaterialInfoDto dto) {
+        basicMapper.updateStatusById(dto.getId(), dto.getStatus());
+    }
+
+    public List<PsiMaterialDetailed> findTradeByTypeId (String typeId) {
+        if (StringUtils.isNotBlank(typeId)) {
+            List<PsiMaterialDetailed> materialDetailedList = psiDetailedMapper.getByTypeId(typeId);
+            return materialDetailedList;
+        } else {
+            return new ArrayList<>();
+        }
+    }
+
+    /**
+     * 保存附件信息
+     * @param list 待保存的附件列表
+     * @param userDTO 当前登录用户
+     * @param id 关联id
+     */
+    @Transactional(rollbackFor = Exception.class)
+    public void saveFiles(List<WorkAttachmentDto> list, UserDTO userDTO, String id) {
+        int j = 1;
+        for (WorkAttachmentDto dto : list) {
+            PsiWorkAttachment i = new PsiWorkAttachment();
+            //包含了url、size、name
+            i.setId(UUID.randomUUID().toString().replace("-", ""));
+//            i.getCreateBy().setId(userDTO.getId());
+            i.setCreateTime(new Date());
+//            i.getUpdateBy().setId(userDTO.getId());
+            i.setUpdateTime(new Date());
+            i.setDelFlag(0);
+            i.setUrl(dto.getUrl());
+            //文件类型处理
+            String fileName = dto.getName();
+            List<String> strings = Arrays.asList(fileName.split("\\."));
+            // 检查文件名是否有后缀
+            if (CollectionUtil.isNotEmpty(strings) && strings.size() > 1) {
+                // 获取最后一个部分作为文件类型
+                i.setType(strings.get(strings.size() - 1));
+            } else {
+                // 如果没有后缀或文件名无效,设置一个默认类型或空
+                i.setType("");
+            }
+            i.setAttachmentId(id);
+            i.setAttachmentName(dto.getName());
+            i.setAttachmentFlag("cwWorkContract");
+            i.setFileSize(dto.getSize());
+            i.setSort(j);
+            Map<String,String> map = new HashMap<>();
+            String workAttachment = JSON.toJSONString((i));
+            String userDTOInfo = JSON.toJSONString((userDTO));
+            map.put("workAttachment",workAttachment);
+            map.put("userDTO",userDTOInfo);
+            SpringUtil.getBean ( IWorkAttachmentApi.class ).insertWorkAttachment(map);
+//            ossServiceMapper.insertWorkAttachment(i, userDTO);
+            j++;
+        }
+    }
+
+    /**
+     * 修改附件信息
+     * @param list 待修改的附件列表
+     * @param userDTO 当前登录用户
+     * @param id 关联id
+     */
+    @Transactional(rollbackFor = Exception.class)
+    public void updateFiles(List<WorkAttachmentDto> list, UserDTO userDTO, String id) {
+        int j = 1;
+        String names = new String();
+        //表中存在,但是传过来不存在,说明已删除,表中数据也要删除
+        for (WorkAttachmentDto dto : list) {
+            names = names + "," +dto.getUrl();
+        }
+        //查询保存的附件信息
+        List<PsiWorkAttachment> infoList = basicMapper.findFileList(id);
+        if (org.flowable.editor.language.json.converter.util.CollectionUtils.isNotEmpty(infoList)) {
+            for (PsiWorkAttachment i : infoList) {
+                if (!names.contains(i.getUrl())) {
+//                    ossServiceMapper.deleteById(i.getId());
+                    SpringUtil.getBean ( IWorkAttachmentApi.class ).deleteById(i.getId());
+                }
+            }
+        }
+        //保存信息
+        for (WorkAttachmentDto dto : list) {
+            //判断是否存在
+            Integer isExit = basicMapper.findIsExit(id, dto.getName());
+            if (isExit == 0) {
+                PsiWorkAttachment i = new PsiWorkAttachment();
+                //包含了url、size、name
+                i.setId(UUID.randomUUID().toString().replace("-", ""));
+//                i.getCreateBy().setId(userDTO.getId());
+                i.setCreateTime(new Date());
+//                i.getUpdateBy().setId(userDTO.getId());
+                i.setUpdateTime(new Date());
+                i.setDelFlag(0);
+                i.setUrl(dto.getUrl());
+                //文件类型处理
+                String fileName = dto.getName();
+                List<String> strings = Arrays.asList(fileName.split("\\."));
+                // 检查文件名是否有后缀
+                if (CollectionUtil.isNotEmpty(strings) && strings.size() > 1) {
+                    // 获取最后一个部分作为文件类型
+                    i.setType(strings.get(strings.size() - 1));
+                } else {
+                    // 如果没有后缀或文件名无效,设置一个默认类型或空
+                    i.setType("");
+                }
+                i.setAttachmentId(id);
+                i.setAttachmentName(dto.getName());
+                i.setAttachmentFlag("cwWorkContract");
+                i.setFileSize(dto.getSize());
+                i.setSort(j);
+                Map<String,String> map = new HashMap<>();
+                String workAttachment = JSON.toJSONString((i));
+                String userDTOInfo = JSON.toJSONString((userDTO));
+                map.put("workAttachment",workAttachment);
+                map.put("userDTO",userDTOInfo);
+                SpringUtil.getBean ( IWorkAttachmentApi.class ).insertWorkAttachment(map);
+//                ossServiceMapper.insertWorkAttachment(i, userDTO);
+                j++;
+            }
+        }
+    }
+}

+ 36 - 0
jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/purchase/service/dto/PsiMaterialExportDto.java

@@ -0,0 +1,36 @@
+package com.jeeplus.psimanage.purchase.service.dto;
+
+import com.alibaba.excel.annotation.ExcelIgnore;
+import com.alibaba.excel.annotation.ExcelProperty;
+import lombok.Data;
+
+@Data
+public class PsiMaterialExportDto {
+
+    @ExcelIgnore
+    private String id;
+
+    @ExcelProperty("采购申请编号")
+    private String purchaseNo;
+
+    @ExcelProperty("采购名称")
+    private String purchaseSketch;
+
+    @ExcelProperty("采购方式")
+    private String purchaseMode;
+
+    @ExcelProperty("采购金额(元)")
+    private String tradeTotalPrice;
+
+    @ExcelProperty("经办人")
+    private String handledByName;
+
+    @ExcelProperty("经办人部门")
+    private String handledByOfficeName;
+
+    @ExcelProperty("申请时间")
+    private String createDate;
+
+    @ExcelProperty("状态")
+    private String status;
+}

+ 152 - 0
jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/purchase/service/dto/PsiMaterialInfoDto.java

@@ -0,0 +1,152 @@
+package com.jeeplus.psimanage.purchase.service.dto;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.jeeplus.psimanage.oss.domain.PsiWorkAttachment;
+import com.jeeplus.psimanage.purchase.domain.PsiMaterialDetailed;
+import com.jeeplus.psimanage.oss.service.dto.WorkAttachmentDto;
+import lombok.Data;
+
+import java.util.Date;
+import java.util.List;
+
+/**
+ * @author: 王强
+ * @create: 2022-12-02 16:29
+ **/
+@Data
+public class PsiMaterialInfoDto {
+
+    private String createBy;
+
+    //采购编号(字典值)
+    public static final String BIZ_CODE = "150";
+
+    /**
+     * 基础表主键值
+     */
+    private String id;
+
+    /**
+     * 经办人id
+     */
+    private String handledById;
+
+    /**
+     * 采购编号
+     */
+    private String purchaseNo;
+
+    /**
+     * 采购简述
+     */
+    private String purchaseSketch;
+
+    /**
+     *采购类型
+     */
+    private String procurementType;
+
+    /**
+     *采购方式
+     */
+    private String purchaseMode;
+
+    /**
+     *采购方式(判断是否展示入库记录及入库)
+     */
+    private String purchaseModeType;
+
+    /**
+     *采购金额(元)
+     */
+    private String tradeTotalPrice;
+
+    /**
+     *经办人
+     */
+    private String handledBy;
+
+    /**
+     * 经办人名称
+     */
+    private String handledByName;
+
+    /**
+     *经办人部门
+     */
+    private String handledByOfficeName;
+
+    @TableField(exist = false)
+    private String[] contractAmounts;
+
+    @TableField(exist = false)
+    private String[] contractDates;
+
+    /**
+     *经办人部门
+     */
+    private String handledByOffice;
+
+    /**
+     *申请时间
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    private Date createDate;
+
+    /**
+     * 状态
+     */
+    private String status;
+
+    /**
+     *采购时间
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    private Date purchaseDate;
+
+    /**
+     * 备注
+     */
+    private String remarks;
+
+    //新增信息
+    List<PsiMaterialDetailed> detailInfos;
+
+    //附件信息
+    List<PsiWorkAttachment> fileInfoLost;
+
+    /**
+     * 流程id
+     */
+    private String procInsId;
+
+    /**
+     *
+     */
+    private String processInstanceId;
+
+    private String processDefinitionId;
+
+    private List<WorkAttachmentDto> files;
+
+    /**
+     * 采购申请  taskId
+     */
+    private String taskId;
+
+    /**
+     * 数据审核人  采购申请
+     */
+    private List<String> auditUserIds;
+
+    /**
+     * 供应商id
+     */
+    private String supplierId;
+
+    /**
+     * 供应商名称
+     */
+    private String supplierName;
+}

+ 61 - 0
jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/serialNumTpl/controller/PsiSerialnumTplController.java

@@ -0,0 +1,61 @@
+package com.jeeplus.psimanage.serialNumTpl.controller;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.jeeplus.core.query.QueryWrapperGenerator;
+import com.jeeplus.psimanage.serialNumTpl.domain.PsiSysSerialnumTpl;
+import com.jeeplus.psimanage.serialNumTpl.service.PsiSerialnumTplService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+
+@Api(tags ="template")
+@RestController
+@RequestMapping(value = "/psi/template")
+public class PsiSerialnumTplController {
+
+    @Resource
+    private PsiSerialnumTplService psiSerialnumTplService;
+
+    /**
+     * 编号模板列表
+     */
+    @ApiOperation(value = "编号模板列表")
+    @GetMapping(value = "/list")
+    public ResponseEntity<IPage<PsiSysSerialnumTpl>> list(Page<PsiSysSerialnumTpl> page, PsiSysSerialnumTpl psiSysSerialnumTpl) throws Exception{
+        QueryWrapper<PsiSysSerialnumTpl> sysSerialnumTplQueryWrapper = QueryWrapperGenerator.buildQueryCondition(psiSysSerialnumTpl, PsiSysSerialnumTpl.class);
+        IPage<PsiSysSerialnumTpl> list = psiSerialnumTplService.list(page, sysSerialnumTplQueryWrapper);
+        return ResponseEntity.ok (list);
+    }
+
+    /**
+     * 编号模板删除
+     */
+    @ApiOperation(value = "编号模板列表")
+    @GetMapping(value = "/remove")
+    public String remove(@RequestParam String id){
+        return psiSerialnumTplService.remove(id);
+    }
+
+    /**
+     * 编号模板查询
+     */
+    @ApiOperation(value = "编号模板列表")
+    @GetMapping(value = "/findById")
+    public PsiSysSerialnumTpl findById(@RequestParam String id){
+        return psiSerialnumTplService.findById(id);
+    }
+
+    /**
+     * 编号模板保存、修改
+     */
+    @ApiOperation(value = "编号模板保存、修改")
+    @PostMapping(value = "/save")
+    public String save(@RequestBody PsiSysSerialnumTpl psiSysSerialnumTpl){
+        return psiSerialnumTplService.save(psiSysSerialnumTpl);
+    }
+}

+ 64 - 0
jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/serialNumTpl/domain/PsiSysSerialnumTpl.java

@@ -0,0 +1,64 @@
+package com.jeeplus.psimanage.serialNumTpl.domain;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.jeeplus.core.domain.BaseEntity;
+import com.jeeplus.core.query.Query;
+import lombok.Data;
+
+@Data
+@TableName(value = "sys_serialnum_tpl")
+public class PsiSysSerialnumTpl extends BaseEntity {
+
+    /**
+     * 公司id
+     */
+    @TableField(value = "company_id")
+    private String companyId;
+
+    /**
+     * 业务标识
+     */
+    @TableField(value = "biz_code")
+    private String bizCode;
+
+    /**
+     * 年度
+     */
+    @TableField(value = "year_built")
+    private String yearBuilt;
+
+    /**
+     * 序列号
+     */
+    @TableField(value = "serial_num")
+    private Integer serialNum;
+
+    /**
+     * 编号模板
+     */
+    @TableField(value = "serial_tpl")
+    private String serialTpl;
+
+    /**
+     * 序列号长度
+     */
+    @TableField(value = "serial_num_len")
+    private Integer serialNumLen;
+
+    /**
+     * 模板名称
+     */
+    @Query
+    @TableField(value = "tpl_name")
+    private String tplName;
+
+    /**
+     * 模板示例
+     */
+    @TableField(value = "serial_tpl_ex")
+    private String serialTplEx;
+
+    @TableField(exist = false)
+    private String companyName;
+}

+ 23 - 0
jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/serialNumTpl/mapper/PsiSerialnumTplMapper.java

@@ -0,0 +1,23 @@
+package com.jeeplus.psimanage.serialNumTpl.mapper;
+
+import com.baomidou.mybatisplus.annotation.InterceptorIgnore;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.core.toolkit.Constants;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.jeeplus.psimanage.serialNumTpl.domain.PsiSysSerialnumTpl;
+import org.apache.ibatis.annotations.Param;
+
+public interface PsiSerialnumTplMapper extends BaseMapper<PsiSysSerialnumTpl> {
+
+    IPage<PsiSysSerialnumTpl> pageList(Page<PsiSysSerialnumTpl> page, @Param(Constants.WRAPPER) QueryWrapper queryWrapper);
+
+    @InterceptorIgnore(tenantLine = "true")
+    PsiSysSerialnumTpl queryByComAndBizCode(@Param("id")String id, @Param("bizCode")String bizCode);
+
+    void resetSerialNum(@Param("id")String id,@Param("yearBuilt")String yearBuilt,@Param("newYear")String newYear);
+
+    @InterceptorIgnore(tenantLine = "true")
+    int updateSerialNum(PsiSysSerialnumTpl numTpl);
+}

+ 0 - 0
jeeplus-modules/jeeplus-psi-management/src/main/java/com/jeeplus/psimanage/serialNumTpl/mapper/xml/PsiSerialnumTplMapper.xml


Niektóre pliki nie zostały wyświetlone z powodu dużej ilości zmienionych plików