Browse Source

同步合并代码 V2.4.0 同步至2025/1/4提交处

rayson 6 months ago
parent
commit
7103c8f33a
63 changed files with 443 additions and 123 deletions
  1. 16 7
      citu-dependencies/pom.xml
  2. 11 2
      citu-framework/citu-common/src/main/java/com/citu/framework/common/pojo/CommonResult.java
  3. 1 0
      citu-framework/citu-spring-boot-starter-biz-tenant/src/main/java/com/citu/framework/tenant/core/db/TenantDatabaseInterceptor.java
  4. 4 0
      citu-framework/citu-spring-boot-starter-mybatis/pom.xml
  5. 1 0
      citu-framework/citu-spring-boot-starter-mybatis/src/main/java/com/citu/framework/mybatis/config/CituMybatisAutoConfiguration.java
  6. 2 2
      citu-framework/citu-spring-boot-starter-websocket/src/main/java/com/citu/framework/websocket/core/sender/kafka/KafkaWebSocketMessageConsumer.java
  7. 4 2
      citu-module-bpm/citu-module-bpm-biz/src/main/java/com/citu/module/bpm/controller/admin/definition/BpmModelController.java
  8. 7 3
      citu-module-bpm/citu-module-bpm-biz/src/main/java/com/citu/module/bpm/controller/admin/definition/vo/model/BpmModelRespVO.java
  9. 9 0
      citu-module-bpm/citu-module-bpm-biz/src/main/java/com/citu/module/bpm/controller/admin/definition/vo/model/BpmModelSaveReqVO.java
  10. 4 1
      citu-module-bpm/citu-module-bpm-biz/src/main/java/com/citu/module/bpm/controller/admin/task/vo/task/BpmTaskPageReqVO.java
  11. 3 1
      citu-module-bpm/citu-module-bpm-biz/src/main/java/com/citu/module/bpm/convert/definition/BpmModelConvert.java
  12. 8 2
      citu-module-bpm/citu-module-bpm-biz/src/main/java/com/citu/module/bpm/convert/task/BpmTaskConvert.java
  13. 1 1
      citu-module-bpm/citu-module-bpm-biz/src/main/java/com/citu/module/bpm/framework/flowable/core/behavior/BpmParallelMultiInstanceBehavior.java
  14. 3 2
      citu-module-bpm/citu-module-bpm-biz/src/main/java/com/citu/module/bpm/framework/flowable/core/behavior/BpmSequentialMultiInstanceBehavior.java
  15. 15 2
      citu-module-bpm/citu-module-bpm-biz/src/main/java/com/citu/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateExpressionStrategy.java
  16. 1 1
      citu-module-bpm/citu-module-bpm-biz/src/main/java/com/citu/module/bpm/framework/flowable/core/candidate/strategy/form/BpmTaskCandidateFormDeptLeaderStrategy.java
  17. 10 11
      citu-module-bpm/citu-module-bpm-biz/src/main/java/com/citu/module/bpm/framework/flowable/core/util/BpmnModelUtils.java
  18. 12 0
      citu-module-bpm/citu-module-bpm-biz/src/main/java/com/citu/module/bpm/framework/flowable/core/util/FlowableUtils.java
  19. 7 7
      citu-module-bpm/citu-module-bpm-biz/src/main/java/com/citu/module/bpm/framework/flowable/core/util/SimpleModelUtils.java
  20. 46 12
      citu-module-bpm/citu-module-bpm-biz/src/main/java/com/citu/module/bpm/service/definition/BpmModelServiceImpl.java
  21. 0 0
      citu-module-bpm/citu-module-bpm-biz/src/main/java/com/citu/module/bpm/service/task/BpmProcessInstanceServiceImpl.java
  22. 67 21
      citu-module-bpm/citu-module-bpm-biz/src/main/java/com/citu/module/bpm/service/task/BpmTaskServiceImpl.java
  23. 5 4
      citu-module-crm/citu-module-crm-biz/src/main/java/com/citu/module/crm/dal/mysql/receivable/CrmReceivablePlanMapper.java
  24. 1 1
      citu-module-crm/citu-module-crm-biz/src/main/java/com/citu/module/crm/service/contract/CrmContractServiceImpl.java
  25. 2 1
      citu-module-crm/citu-module-crm-biz/src/main/java/com/citu/module/crm/util/CrmPermissionUtils.java
  26. 2 0
      citu-module-erp/citu-module-erp-biz/src/main/java/com/citu/module/erp/controller/admin/finance/vo/payment/ErpFinancePaymentRespVO.java
  27. 2 0
      citu-module-erp/citu-module-erp-biz/src/main/java/com/citu/module/erp/controller/admin/finance/vo/receipt/ErpFinanceReceiptRespVO.java
  28. 2 2
      citu-module-mall/citu-module-product-api/src/main/java/com/citu/module/product/enums/comment/ProductCommentAuditStatusEnum.java
  29. 19 0
      citu-module-mall/citu-module-product-api/src/main/java/com/citu/module/product/enums/spu/ProductSpuTypeEnum.java
  30. 3 0
      citu-module-mall/citu-module-product-biz/src/main/java/com/citu/module/product/controller/admin/spu/vo/ProductSpuPageReqVO.java
  31. 5 0
      citu-module-mall/citu-module-product-biz/src/main/java/com/citu/module/product/controller/admin/spu/vo/ProductSpuRespVO.java
  32. 5 1
      citu-module-mall/citu-module-product-biz/src/main/java/com/citu/module/product/controller/admin/spu/vo/ProductSpuSaveReqVO.java
  33. 3 0
      citu-module-mall/citu-module-product-biz/src/main/java/com/citu/module/product/controller/admin/spu/vo/ProductSpuSimpleRespVO.java
  34. 3 0
      citu-module-mall/citu-module-product-biz/src/main/java/com/citu/module/product/controller/app/spu/vo/AppProductSpuDetailRespVO.java
  35. 9 0
      citu-module-mall/citu-module-product-biz/src/main/java/com/citu/module/product/controller/app/spu/vo/AppProductSpuRespVO.java
  36. 7 0
      citu-module-mall/citu-module-product-biz/src/main/java/com/citu/module/product/dal/dataobject/spu/ProductSpuDO.java
  37. 1 0
      citu-module-mall/citu-module-product-biz/src/main/java/com/citu/module/product/dal/mysql/spu/ProductSpuMapper.java
  38. 6 4
      citu-module-mall/citu-module-product-biz/src/main/java/com/citu/module/product/service/spu/ProductSpuServiceImpl.java
  39. 0 6
      citu-module-mall/citu-module-promotion-biz/src/main/java/com/citu/module/promotion/dal/mysql/discount/DiscountProductMapper.java
  40. 2 2
      citu-module-mall/citu-module-promotion-biz/src/main/java/com/citu/module/promotion/service/coupon/CouponServiceImpl.java
  41. 6 0
      citu-module-mall/citu-module-promotion-biz/src/main/java/com/citu/module/promotion/service/discount/DiscountActivityServiceImpl.java
  42. 1 0
      citu-module-mall/citu-module-trade-api/src/main/java/com/citu/module/trade/enums/ErrorCodeConstants.java
  43. 7 0
      citu-module-mall/citu-module-trade-biz/src/main/java/com/citu/module/trade/controller/admin/brokerage/BrokerageUserController.java
  44. 19 0
      citu-module-mall/citu-module-trade-biz/src/main/java/com/citu/module/trade/controller/admin/brokerage/vo/user/BrokerageUserCreateReqVO.java
  45. 1 1
      citu-module-mall/citu-module-trade-biz/src/main/java/com/citu/module/trade/controller/app/aftersale/AppAfterSaleLogController.java
  46. 3 0
      citu-module-mall/citu-module-trade-biz/src/main/java/com/citu/module/trade/convert/brokerage/BrokerageUserConvert.java
  47. 1 1
      citu-module-mall/citu-module-trade-biz/src/main/java/com/citu/module/trade/dal/dataobject/order/TradeOrderDO.java
  48. 1 1
      citu-module-mall/citu-module-trade-biz/src/main/java/com/citu/module/trade/service/brokerage/BrokerageRecordServiceImpl.java
  49. 10 0
      citu-module-mall/citu-module-trade-biz/src/main/java/com/citu/module/trade/service/brokerage/BrokerageUserService.java
  50. 21 1
      citu-module-mall/citu-module-trade-biz/src/main/java/com/citu/module/trade/service/brokerage/BrokerageUserServiceImpl.java
  51. 2 2
      citu-module-mall/citu-module-trade-biz/src/main/java/com/citu/module/trade/service/cart/CartServiceImpl.java
  52. 6 5
      citu-module-mall/citu-module-trade-biz/src/main/java/com/citu/module/trade/service/order/TradeOrderUpdateServiceImpl.java
  53. 10 4
      citu-module-mall/citu-module-trade-biz/src/main/java/com/citu/module/trade/service/order/handler/TradeCouponOrderHandler.java
  54. 8 4
      citu-module-mall/citu-module-trade-biz/src/main/java/com/citu/module/trade/service/price/calculator/TradeDeliveryPriceCalculator.java
  55. 1 1
      citu-module-member/citu-module-member-biz/src/main/java/com/citu/module/member/controller/app/signin/AppMemberSignInRecordController.java
  56. 3 1
      citu-module-member/citu-module-member-biz/src/main/java/com/citu/module/member/service/point/MemberPointRecordServiceImpl.java
  57. 1 0
      citu-module-system/citu-module-system-api/src/main/java/com/citu/module/system/enums/ErrorCodeConstants.java
  58. 1 1
      citu-module-system/citu-module-system-biz/src/main/java/com/citu/module/system/controller/admin/user/vo/user/UserSaveReqVO.java
  59. 4 0
      citu-module-system/citu-module-system-biz/src/main/java/com/citu/module/system/dal/mysql/tenant/TenantPackageMapper.java
  60. 25 0
      citu-module-system/citu-module-system-biz/src/main/java/com/citu/module/system/service/tenant/TenantPackageServiceImpl.java
  61. 0 1
      menduner/menduner-system-biz/src/main/java/com/citu/module/menduner/system/controller/app/jobhunt/person/AppPersonResumeController.java
  62. 1 0
      menduner/menduner-system-biz/src/main/resources/i18n/messages_zh_CN.properties
  63. 2 2
      pom.xml

+ 16 - 7
citu-dependencies/pom.xml

@@ -14,7 +14,7 @@
     <url>https://github.com/YunaiV/ruoyi-vue-pro</url>
     <url>https://github.com/YunaiV/ruoyi-vue-pro</url>
 
 
     <properties>
     <properties>
-        <revision>2.3.0-snapshot</revision>
+        <revision>2.4.0-SNAPSHOT</revision>
         <flatten-maven-plugin.version>1.6.0</flatten-maven-plugin.version>
         <flatten-maven-plugin.version>1.6.0</flatten-maven-plugin.version>
         <!-- 统一依赖管理 -->
         <!-- 统一依赖管理 -->
         <spring.framework.version>5.3.39</spring.framework.version>
         <spring.framework.version>5.3.39</spring.framework.version>
@@ -27,9 +27,9 @@
         <springdoc.version>1.6.15</springdoc.version>
         <springdoc.version>1.6.15</springdoc.version>
         <knife4j.version>4.3.0</knife4j.version>
         <knife4j.version>4.3.0</knife4j.version>
         <!-- DB 相关 -->
         <!-- DB 相关 -->
-        <druid.version>1.2.23</druid.version>
-        <mybatis.version>3.5.16</mybatis.version>
-        <mybatis-plus.version>3.5.7</mybatis-plus.version>
+        <druid.version>1.2.24</druid.version>
+        <mybatis.version>3.5.17</mybatis.version>
+        <mybatis-plus.version>3.5.9</mybatis-plus.version>
         <dynamic-datasource.version>4.3.1</dynamic-datasource.version>
         <dynamic-datasource.version>4.3.1</dynamic-datasource.version>
         <mybatis-plus-join.version>1.4.13</mybatis-plus-join.version>
         <mybatis-plus-join.version>1.4.13</mybatis-plus-join.version>
         <easy-trans.version>3.0.6</easy-trans.version>
         <easy-trans.version>3.0.6</easy-trans.version>
@@ -65,7 +65,7 @@
         <velocity.version>2.4</velocity.version>
         <velocity.version>2.4</velocity.version>
         <screw.version>1.0.5</screw.version>
         <screw.version>1.0.5</screw.version>
         <fastjson.version>2.0.53</fastjson.version>
         <fastjson.version>2.0.53</fastjson.version>
-        <guava.version>33.2.1-jre</guava.version>
+        <guava.version>33.4.0-jre</guava.version>
         <transmittable-thread-local.version>2.14.5</transmittable-thread-local.version>
         <transmittable-thread-local.version>2.14.5</transmittable-thread-local.version>
         <commons-net.version>3.11.1</commons-net.version>
         <commons-net.version>3.11.1</commons-net.version>
         <jsch.version>0.1.55</jsch.version>
         <jsch.version>0.1.55</jsch.version>
@@ -73,7 +73,7 @@
         <ip2region.version>2.7.0</ip2region.version>
         <ip2region.version>2.7.0</ip2region.version>
         <bizlog-sdk.version>3.0.6</bizlog-sdk.version>
         <bizlog-sdk.version>3.0.6</bizlog-sdk.version>
         <reflections.version>0.10.2</reflections.version>
         <reflections.version>0.10.2</reflections.version>
-        <netty.version>4.1.113.Final</netty.version>
+        <netty.version>4.1.116.Final</netty.version>
         <!-- 三方云服务相关 -->
         <!-- 三方云服务相关 -->
         <commons-io.version>2.17.0</commons-io.version>
         <commons-io.version>2.17.0</commons-io.version>
         <commons-compress.version>1.27.1</commons-compress.version>
         <commons-compress.version>1.27.1</commons-compress.version>
@@ -238,6 +238,11 @@
                 <artifactId>mybatis-plus-boot-starter</artifactId>
                 <artifactId>mybatis-plus-boot-starter</artifactId>
                 <version>${mybatis-plus.version}</version>
                 <version>${mybatis-plus.version}</version>
             </dependency>
             </dependency>
+            <dependency>
+                <groupId>com.baomidou</groupId>
+                <artifactId>mybatis-plus-jsqlparser-4.9</artifactId>
+                <version>${mybatis-plus.version}</version>
+            </dependency>
             <dependency>
             <dependency>
                 <groupId>com.baomidou</groupId>
                 <groupId>com.baomidou</groupId>
                 <artifactId>mybatis-plus-generator</artifactId> <!-- 代码生成器,使用它解析表结构 -->
                 <artifactId>mybatis-plus-generator</artifactId> <!-- 代码生成器,使用它解析表结构 -->
@@ -291,10 +296,14 @@
                 <artifactId>redisson-spring-boot-starter</artifactId>
                 <artifactId>redisson-spring-boot-starter</artifactId>
                 <version>${redisson.version}</version>
                 <version>${redisson.version}</version>
                 <exclusions>
                 <exclusions>
+                    <exclusion>
+                        <groupId>org.springframework.boot</groupId>
+                        <artifactId>spring-boot-starter-actuator</artifactId>
+                    </exclusion>
                     <exclusion>
                     <exclusion>
                         <groupId>org.redisson</groupId>
                         <groupId>org.redisson</groupId>
                         <!-- 使用 redisson-spring-data-27 替代,解决 Tuple NoClassDefFoundError 报错 -->
                         <!-- 使用 redisson-spring-data-27 替代,解决 Tuple NoClassDefFoundError 报错 -->
-                        <artifactId>redisson-spring-data-33</artifactId>
+                        <artifactId>redisson-spring-data-34</artifactId>
                     </exclusion>
                     </exclusion>
                 </exclusions>
                 </exclusions>
             </dependency>
             </dependency>

+ 11 - 2
citu-framework/citu-common/src/main/java/com/citu/framework/common/pojo/CommonResult.java

@@ -1,11 +1,12 @@
 package com.citu.framework.common.pojo;
 package com.citu.framework.common.pojo;
 
 
+import cn.hutool.core.lang.Assert;
 import com.citu.framework.common.exception.ErrorCode;
 import com.citu.framework.common.exception.ErrorCode;
 import com.citu.framework.common.exception.ServiceException;
 import com.citu.framework.common.exception.ServiceException;
 import com.citu.framework.common.exception.enums.GlobalErrorCodeConstants;
 import com.citu.framework.common.exception.enums.GlobalErrorCodeConstants;
+import com.citu.framework.common.exception.util.ServiceExceptionUtil;
 import com.fasterxml.jackson.annotation.JsonIgnore;
 import com.fasterxml.jackson.annotation.JsonIgnore;
 import lombok.Data;
 import lombok.Data;
-import org.springframework.util.Assert;
 
 
 import java.io.Serializable;
 import java.io.Serializable;
 import java.util.Objects;
 import java.util.Objects;
@@ -49,13 +50,21 @@ public class CommonResult<T> implements Serializable {
     }
     }
 
 
     public static <T> CommonResult<T> error(Integer code, String message) {
     public static <T> CommonResult<T> error(Integer code, String message) {
-        Assert.isTrue(!GlobalErrorCodeConstants.SUCCESS.getCode().equals(code), "code 必须是错误的!");
+        Assert.notEquals(GlobalErrorCodeConstants.SUCCESS.getCode(), code, "code 必须是错误的!");
         CommonResult<T> result = new CommonResult<>();
         CommonResult<T> result = new CommonResult<>();
         result.code = code;
         result.code = code;
         result.msg = message;
         result.msg = message;
         return result;
         return result;
     }
     }
 
 
+    public static <T> CommonResult<T> error(ErrorCode errorCode, Object... params) {
+        Assert.notEquals(GlobalErrorCodeConstants.SUCCESS.getCode(), errorCode.getCode(), "code 必须是错误的!");
+        CommonResult<T> result = new CommonResult<>();
+        result.code = errorCode.getCode();
+        result.msg = ServiceExceptionUtil.doFormat(errorCode.getCode(), errorCode.getMsg(), params);
+        return result;
+    }
+
     public static <T> CommonResult<T> error(ErrorCode errorCode) {
     public static <T> CommonResult<T> error(ErrorCode errorCode) {
         return error(errorCode.getCode(), errorCode.getMsg());
         return error(errorCode.getCode(), errorCode.getMsg());
     }
     }

+ 1 - 0
citu-framework/citu-spring-boot-starter-biz-tenant/src/main/java/com/citu/framework/tenant/core/db/TenantDatabaseInterceptor.java

@@ -5,6 +5,7 @@ import com.baomidou.mybatisplus.extension.toolkit.SqlParserUtils;
 import com.citu.framework.tenant.config.TenantProperties;
 import com.citu.framework.tenant.config.TenantProperties;
 import com.citu.framework.tenant.core.context.TenantContextHolder;
 import com.citu.framework.tenant.core.context.TenantContextHolder;
 import com.baomidou.mybatisplus.extension.plugins.handler.TenantLineHandler;
 import com.baomidou.mybatisplus.extension.plugins.handler.TenantLineHandler;
+import com.baomidou.mybatisplus.extension.toolkit.SqlParserUtils;
 import net.sf.jsqlparser.expression.Expression;
 import net.sf.jsqlparser.expression.Expression;
 import net.sf.jsqlparser.expression.LongValue;
 import net.sf.jsqlparser.expression.LongValue;
 
 

+ 4 - 0
citu-framework/citu-spring-boot-starter-mybatis/pom.xml

@@ -62,6 +62,10 @@
             <groupId>com.baomidou</groupId>
             <groupId>com.baomidou</groupId>
             <artifactId>mybatis-plus-boot-starter</artifactId>
             <artifactId>mybatis-plus-boot-starter</artifactId>
         </dependency>
         </dependency>
+        <dependency>
+            <groupId>com.baomidou</groupId>
+            <artifactId>mybatis-plus-jsqlparser-4.9</artifactId>
+        </dependency>
         <dependency>
         <dependency>
             <groupId>com.baomidou</groupId>
             <groupId>com.baomidou</groupId>
             <artifactId>dynamic-datasource-spring-boot-starter</artifactId> <!-- 多数据源 -->
             <artifactId>dynamic-datasource-spring-boot-starter</artifactId> <!-- 多数据源 -->

+ 1 - 0
citu-framework/citu-spring-boot-starter-mybatis/src/main/java/com/citu/framework/mybatis/config/CituMybatisAutoConfiguration.java

@@ -9,6 +9,7 @@ import com.baomidou.mybatisplus.extension.incrementer.*;
 import com.baomidou.mybatisplus.extension.parser.JsqlParserGlobal;
 import com.baomidou.mybatisplus.extension.parser.JsqlParserGlobal;
 import com.baomidou.mybatisplus.extension.parser.cache.JdkSerialCaffeineJsqlParseCache;
 import com.baomidou.mybatisplus.extension.parser.cache.JdkSerialCaffeineJsqlParseCache;
 import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
 import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
+
 import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
 import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
 import com.citu.framework.mybatis.core.handler.DefaultDBFieldHandler;
 import com.citu.framework.mybatis.core.handler.DefaultDBFieldHandler;
 import org.apache.ibatis.annotations.Mapper;
 import org.apache.ibatis.annotations.Mapper;

+ 2 - 2
citu-framework/citu-spring-boot-starter-websocket/src/main/java/com/citu/framework/websocket/core/sender/kafka/KafkaWebSocketMessageConsumer.java

@@ -12,7 +12,7 @@ import org.springframework.kafka.annotation.KafkaListener;
 @RequiredArgsConstructor
 @RequiredArgsConstructor
 public class KafkaWebSocketMessageConsumer {
 public class KafkaWebSocketMessageConsumer {
 
 
-    private final KafkaWebSocketMessageSender rabbitMQWebSocketMessageSender;
+    private final KafkaWebSocketMessageSender kafkaWebSocketMessageSender;
 
 
     @RabbitHandler
     @RabbitHandler
     @KafkaListener(
     @KafkaListener(
@@ -20,7 +20,7 @@ public class KafkaWebSocketMessageConsumer {
             // 在 Group 上,使用 UUID 生成其后缀。这样,启动的 Consumer 的 Group 不同,以达到广播消费的目的
             // 在 Group 上,使用 UUID 生成其后缀。这样,启动的 Consumer 的 Group 不同,以达到广播消费的目的
             groupId = "${citu.websocket.sender-kafka.consumer-group}" + "-" + "#{T(java.util.UUID).randomUUID()}")
             groupId = "${citu.websocket.sender-kafka.consumer-group}" + "-" + "#{T(java.util.UUID).randomUUID()}")
     public void onMessage(KafkaWebSocketMessage message) {
     public void onMessage(KafkaWebSocketMessage message) {
-        rabbitMQWebSocketMessageSender.send(message.getSessionId(),
+        kafkaWebSocketMessageSender.send(message.getSessionId(),
                 message.getUserType(), message.getUserId(),
                 message.getUserType(), message.getUserId(),
                 message.getMessageType(), message.getMessageContent());
                 message.getMessageType(), message.getMessageContent());
     }
     }

+ 4 - 2
citu-module-bpm/citu-module-bpm-biz/src/main/java/com/citu/module/bpm/controller/admin/definition/BpmModelController.java

@@ -99,7 +99,8 @@ public class BpmModelController {
             return null;
             return null;
         }
         }
         byte[] bpmnBytes = modelService.getModelBpmnXML(id);
         byte[] bpmnBytes = modelService.getModelBpmnXML(id);
-        return success(BpmModelConvert.INSTANCE.buildModel(model, bpmnBytes));
+        BpmSimpleModelNodeVO simpleModel = modelService.getSimpleModel(id);
+        return success(BpmModelConvert.INSTANCE.buildModel(model, bpmnBytes, simpleModel));
     }
     }
 
 
     @PostMapping("/create")
     @PostMapping("/create")
@@ -109,7 +110,6 @@ public class BpmModelController {
         return success(modelService.createModel(createRetVO));
         return success(modelService.createModel(createRetVO));
     }
     }
 
 
-
     @PutMapping("/update")
     @PutMapping("/update")
     @Operation(summary = "修改模型")
     @Operation(summary = "修改模型")
     @PreAuthorize("@ss.hasPermission('bpm:model:update')")
     @PreAuthorize("@ss.hasPermission('bpm:model:update')")
@@ -143,6 +143,7 @@ public class BpmModelController {
         return success(true);
         return success(true);
     }
     }
 
 
+    @Deprecated
     @PutMapping("/update-bpmn")
     @PutMapping("/update-bpmn")
     @Operation(summary = "修改模型的 BPMN")
     @Operation(summary = "修改模型的 BPMN")
     @PreAuthorize("@ss.hasPermission('bpm:model:update')")
     @PreAuthorize("@ss.hasPermission('bpm:model:update')")
@@ -169,6 +170,7 @@ public class BpmModelController {
         return success(modelService.getSimpleModel(modelId));
         return success(modelService.getSimpleModel(modelId));
     }
     }
 
 
+    @Deprecated
     @PostMapping("/simple/update")
     @PostMapping("/simple/update")
     @Operation(summary = "保存仿钉钉流程设计模型")
     @Operation(summary = "保存仿钉钉流程设计模型")
     @PreAuthorize("@ss.hasPermission('bpm:model:update')")
     @PreAuthorize("@ss.hasPermission('bpm:model:update')")

+ 7 - 3
citu-module-bpm/citu-module-bpm-biz/src/main/java/com/citu/module/bpm/controller/admin/definition/vo/model/BpmModelRespVO.java

@@ -1,6 +1,7 @@
 package com.citu.module.bpm.controller.admin.definition.vo.model;
 package com.citu.module.bpm.controller.admin.definition.vo.model;
 
 
 import com.citu.module.bpm.controller.admin.base.user.UserSimpleBaseVO;
 import com.citu.module.bpm.controller.admin.base.user.UserSimpleBaseVO;
+import com.citu.module.bpm.controller.admin.definition.vo.model.simple.BpmSimpleModelNodeVO;
 import com.citu.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionRespVO;
 import com.citu.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionRespVO;
 import io.swagger.v3.oas.annotations.media.Schema;
 import io.swagger.v3.oas.annotations.media.Schema;
 import lombok.Data;
 import lombok.Data;
@@ -35,12 +36,15 @@ public class BpmModelRespVO extends BpmModelMetaInfoVO {
     @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
     @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
     private LocalDateTime createTime;
     private LocalDateTime createTime;
 
 
-    @Schema(description = "BPMN XML", requiredMode = Schema.RequiredMode.REQUIRED)
-    private String bpmnXml;
-
     @Schema(description = "可发起的用户数组")
     @Schema(description = "可发起的用户数组")
     private List<UserSimpleBaseVO> startUsers;
     private List<UserSimpleBaseVO> startUsers;
 
 
+    @Schema(description = "BPMN XML")
+    private String bpmnXml;
+
+    @Schema(description = "仿钉钉流程设计模型对象")
+    private BpmSimpleModelNodeVO simpleModel;
+
     /**
     /**
      * 最新部署的流程定义
      * 最新部署的流程定义
      */
      */

+ 9 - 0
citu-module-bpm/citu-module-bpm-biz/src/main/java/com/citu/module/bpm/controller/admin/definition/vo/model/BpmModelSaveReqVO.java

@@ -1,8 +1,10 @@
 package com.citu.module.bpm.controller.admin.definition.vo.model;
 package com.citu.module.bpm.controller.admin.definition.vo.model;
 
 
+import com.citu.module.bpm.controller.admin.definition.vo.model.simple.BpmSimpleModelNodeVO;
 import io.swagger.v3.oas.annotations.media.Schema;
 import io.swagger.v3.oas.annotations.media.Schema;
 import lombok.Data;
 import lombok.Data;
 
 
+import javax.validation.Valid;
 import javax.validation.constraints.NotEmpty;
 import javax.validation.constraints.NotEmpty;
 
 
 @Schema(description = "管理后台 - 流程模型的保存 Request VO")
 @Schema(description = "管理后台 - 流程模型的保存 Request VO")
@@ -23,4 +25,11 @@ public class BpmModelSaveReqVO extends BpmModelMetaInfoVO {
     @Schema(description = "流程分类", example = "1")
     @Schema(description = "流程分类", example = "1")
     private String category;
     private String category;
 
 
+    @Schema(description = "BPMN XML")
+    private String bpmnXml;
+
+    @Schema(description = "仿钉钉流程设计模型对象")
+    @Valid
+    private BpmSimpleModelNodeVO simpleModel;
+
 }
 }

+ 4 - 1
citu-module-bpm/citu-module-bpm-biz/src/main/java/com/citu/module/bpm/controller/admin/task/vo/task/BpmTaskPageReqVO.java

@@ -15,8 +15,11 @@ public class BpmTaskPageReqVO extends PageParam {
     @Schema(description = "流程任务名", example = "芋道")
     @Schema(description = "流程任务名", example = "芋道")
     private String name;
     private String name;
 
 
+    @Schema(description = "流程分类", example = "1")
+    private String category;
+
     @Schema(description = "创建时间")
     @Schema(description = "创建时间")
     @DateTimeFormat(pattern = DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
     @DateTimeFormat(pattern = DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
     private LocalDateTime[] createTime;
     private LocalDateTime[] createTime;
 
 
-}
+}

+ 3 - 1
citu-module-bpm/citu-module-bpm-biz/src/main/java/com/citu/module/bpm/convert/definition/BpmModelConvert.java

@@ -8,6 +8,7 @@ import com.citu.module.bpm.controller.admin.base.user.UserSimpleBaseVO;
 import com.citu.module.bpm.controller.admin.definition.vo.model.BpmModelMetaInfoVO;
 import com.citu.module.bpm.controller.admin.definition.vo.model.BpmModelMetaInfoVO;
 import com.citu.module.bpm.controller.admin.definition.vo.model.BpmModelRespVO;
 import com.citu.module.bpm.controller.admin.definition.vo.model.BpmModelRespVO;
 import com.citu.module.bpm.controller.admin.definition.vo.model.BpmModelSaveReqVO;
 import com.citu.module.bpm.controller.admin.definition.vo.model.BpmModelSaveReqVO;
+import com.citu.module.bpm.controller.admin.definition.vo.model.simple.BpmSimpleModelNodeVO;
 import com.citu.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionRespVO;
 import com.citu.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionRespVO;
 import com.citu.module.bpm.dal.dataobject.definition.BpmCategoryDO;
 import com.citu.module.bpm.dal.dataobject.definition.BpmCategoryDO;
 import com.citu.module.bpm.dal.dataobject.definition.BpmFormDO;
 import com.citu.module.bpm.dal.dataobject.definition.BpmFormDO;
@@ -58,12 +59,13 @@ public interface BpmModelConvert {
         return result;
         return result;
     }
     }
 
 
-    default BpmModelRespVO buildModel(Model model, byte[] bpmnBytes) {
+    default BpmModelRespVO buildModel(Model model, byte[] bpmnBytes, BpmSimpleModelNodeVO simpleModel) {
         BpmModelMetaInfoVO metaInfo = parseMetaInfo(model);
         BpmModelMetaInfoVO metaInfo = parseMetaInfo(model);
         BpmModelRespVO modelVO = buildModel0(model, metaInfo, null, null, null, null, null);
         BpmModelRespVO modelVO = buildModel0(model, metaInfo, null, null, null, null, null);
         if (ArrayUtil.isNotEmpty(bpmnBytes)) {
         if (ArrayUtil.isNotEmpty(bpmnBytes)) {
             modelVO.setBpmnXml(BpmnModelUtils.getBpmnXml(bpmnBytes));
             modelVO.setBpmnXml(BpmnModelUtils.getBpmnXml(bpmnBytes));
         }
         }
+        modelVO.setSimpleModel(simpleModel);
         return modelVO;
         return modelVO;
     }
     }
 
 

+ 8 - 2
citu-module-bpm/citu-module-bpm-biz/src/main/java/com/citu/module/bpm/convert/task/BpmTaskConvert.java

@@ -124,12 +124,18 @@ public interface BpmTaskConvert {
     }
     }
 
 
     default BpmTaskRespVO buildTodoTask(Task todoTask, List<Task> childrenTasks,
     default BpmTaskRespVO buildTodoTask(Task todoTask, List<Task> childrenTasks,
-                                              Map<Integer, BpmTaskRespVO.OperationButtonSetting> buttonsSetting) {
-        return BeanUtils.toBean(todoTask, BpmTaskRespVO.class)
+                                        Map<Integer, BpmTaskRespVO.OperationButtonSetting> buttonsSetting,
+                                        BpmFormDO form) {
+        BpmTaskRespVO bpmTaskRespVO = BeanUtils.toBean(todoTask, BpmTaskRespVO.class)
                 .setStatus(FlowableUtils.getTaskStatus(todoTask)).setReason(FlowableUtils.getTaskReason(todoTask))
                 .setStatus(FlowableUtils.getTaskStatus(todoTask)).setReason(FlowableUtils.getTaskReason(todoTask))
                 .setButtonsSetting(buttonsSetting)
                 .setButtonsSetting(buttonsSetting)
                 .setChildren(convertList(childrenTasks, childTask -> BeanUtils.toBean(childTask, BpmTaskRespVO.class)
                 .setChildren(convertList(childrenTasks, childTask -> BeanUtils.toBean(childTask, BpmTaskRespVO.class)
                         .setStatus(FlowableUtils.getTaskStatus(childTask))));
                         .setStatus(FlowableUtils.getTaskStatus(childTask))));
+        if (form != null) {
+            bpmTaskRespVO.setFormId(form.getId()).setFormName(form.getName())
+                    .setFormConf(form.getConf()).setFormFields(form.getFields());
+        }
+        return bpmTaskRespVO;
     }
     }
 
 
     default BpmMessageSendWhenTaskCreatedReqDTO convert(ProcessInstance processInstance, AdminUserRespDTO startUser,
     default BpmMessageSendWhenTaskCreatedReqDTO convert(ProcessInstance processInstance, AdminUserRespDTO startUser,

+ 1 - 1
citu-module-bpm/citu-module-bpm-biz/src/main/java/com/citu/module/bpm/framework/flowable/core/behavior/BpmParallelMultiInstanceBehavior.java

@@ -54,13 +54,13 @@ public class BpmParallelMultiInstanceBehavior extends ParallelMultiInstanceBehav
         Set<Long> assigneeUserIds = (Set<Long>) execution.getVariable(super.collectionVariable, Set.class);
         Set<Long> assigneeUserIds = (Set<Long>) execution.getVariable(super.collectionVariable, Set.class);
         if (assigneeUserIds == null) {
         if (assigneeUserIds == null) {
             assigneeUserIds = taskCandidateInvoker.calculateUsersByTask(execution);
             assigneeUserIds = taskCandidateInvoker.calculateUsersByTask(execution);
-            execution.setVariable(super.collectionVariable, assigneeUserIds);
             if (CollUtil.isEmpty(assigneeUserIds)) {
             if (CollUtil.isEmpty(assigneeUserIds)) {
                 // 特殊:如果没有处理人的情况下,至少有一个 null 空元素,避免自动通过!
                 // 特殊:如果没有处理人的情况下,至少有一个 null 空元素,避免自动通过!
                 // 这样,保证在 BpmUserTaskActivityBehavior 至少创建出一个 Task 任务
                 // 这样,保证在 BpmUserTaskActivityBehavior 至少创建出一个 Task 任务
                 // 用途:1)审批人为空时;2)审批类型为自动通过、自动拒绝时
                 // 用途:1)审批人为空时;2)审批类型为自动通过、自动拒绝时
                 assigneeUserIds = SetUtils.asSet((Long) null);
                 assigneeUserIds = SetUtils.asSet((Long) null);
             }
             }
+            execution.setVariableLocal(super.collectionVariable, assigneeUserIds);
         }
         }
         return assigneeUserIds.size();
         return assigneeUserIds.size();
     }
     }

+ 3 - 2
citu-module-bpm/citu-module-bpm-biz/src/main/java/com/citu/module/bpm/framework/flowable/core/behavior/BpmSequentialMultiInstanceBehavior.java

@@ -43,17 +43,18 @@ public class BpmSequentialMultiInstanceBehavior extends SequentialMultiInstanceB
         super.collectionElementVariable = FlowableUtils.formatExecutionCollectionElementVariable(execution.getCurrentActivityId());
         super.collectionElementVariable = FlowableUtils.formatExecutionCollectionElementVariable(execution.getCurrentActivityId());
 
 
         // 第二步,获取任务的所有处理人
         // 第二步,获取任务的所有处理人
+        // 不使用 execution.getVariable 原因:目前依次审批任务回退后 collectionVariable 变量没有清理, 如果重新进入该任务不会重新分配审批人
         @SuppressWarnings("unchecked")
         @SuppressWarnings("unchecked")
-        Set<Long> assigneeUserIds = (Set<Long>) execution.getVariable(super.collectionVariable, Set.class);
+        Set<Long> assigneeUserIds = (Set<Long>) execution.getVariableLocal(super.collectionVariable, Set.class);
         if (assigneeUserIds == null) {
         if (assigneeUserIds == null) {
             assigneeUserIds = taskCandidateInvoker.calculateUsersByTask(execution);
             assigneeUserIds = taskCandidateInvoker.calculateUsersByTask(execution);
-            execution.setVariable(super.collectionVariable, assigneeUserIds);
             if (CollUtil.isEmpty(assigneeUserIds)) {
             if (CollUtil.isEmpty(assigneeUserIds)) {
                 // 特殊:如果没有处理人的情况下,至少有一个 null 空元素,避免自动通过!
                 // 特殊:如果没有处理人的情况下,至少有一个 null 空元素,避免自动通过!
                 // 这样,保证在 BpmUserTaskActivityBehavior 至少创建出一个 Task 任务
                 // 这样,保证在 BpmUserTaskActivityBehavior 至少创建出一个 Task 任务
                 // 用途:1)审批人为空时;2)审批类型为自动通过、自动拒绝时
                 // 用途:1)审批人为空时;2)审批类型为自动通过、自动拒绝时
                 assigneeUserIds = SetUtils.asSet((Long) null);
                 assigneeUserIds = SetUtils.asSet((Long) null);
             }
             }
+            execution.setVariableLocal(super.collectionVariable, assigneeUserIds);
         }
         }
         return assigneeUserIds.size();
         return assigneeUserIds.size();
     }
     }

+ 15 - 2
citu-module-bpm/citu-module-bpm-biz/src/main/java/com/citu/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateExpressionStrategy.java

@@ -4,10 +4,14 @@ import cn.hutool.core.convert.Convert;
 import com.citu.module.bpm.framework.flowable.core.candidate.BpmTaskCandidateStrategy;
 import com.citu.module.bpm.framework.flowable.core.candidate.BpmTaskCandidateStrategy;
 import com.citu.module.bpm.framework.flowable.core.enums.BpmTaskCandidateStrategyEnum;
 import com.citu.module.bpm.framework.flowable.core.enums.BpmTaskCandidateStrategyEnum;
 import com.citu.module.bpm.framework.flowable.core.util.FlowableUtils;
 import com.citu.module.bpm.framework.flowable.core.util.FlowableUtils;
+import com.google.common.collect.Sets;
+import lombok.extern.slf4j.Slf4j;
 import org.flowable.bpmn.model.BpmnModel;
 import org.flowable.bpmn.model.BpmnModel;
+import org.flowable.common.engine.api.FlowableException;
 import org.flowable.engine.delegate.DelegateExecution;
 import org.flowable.engine.delegate.DelegateExecution;
 import org.springframework.stereotype.Component;
 import org.springframework.stereotype.Component;
 
 
+import java.util.HashMap;
 import java.util.Map;
 import java.util.Map;
 import java.util.Set;
 import java.util.Set;
 
 
@@ -17,6 +21,7 @@ import java.util.Set;
  * @author Rayson
  * @author Rayson
  */
  */
 @Component
 @Component
+@Slf4j
 public class BpmTaskCandidateExpressionStrategy implements BpmTaskCandidateStrategy {
 public class BpmTaskCandidateExpressionStrategy implements BpmTaskCandidateStrategy {
 
 
     @Override
     @Override
@@ -38,8 +43,16 @@ public class BpmTaskCandidateExpressionStrategy implements BpmTaskCandidateStrat
     @Override
     @Override
     public Set<Long> calculateUsersByActivity(BpmnModel bpmnModel, String activityId, String param,
     public Set<Long> calculateUsersByActivity(BpmnModel bpmnModel, String activityId, String param,
                                               Long startUserId, String processDefinitionId, Map<String, Object> processVariables) {
                                               Long startUserId, String processDefinitionId, Map<String, Object> processVariables) {
-        Object result = FlowableUtils.getExpressionValue(processVariables, param);
-        return Convert.toSet(Long.class, result);
+        Map<String, Object> variables = processVariables == null ? new HashMap<>() : processVariables;
+        try {
+            Object result = FlowableUtils.getExpressionValue(variables, param);
+            return Convert.toSet(Long.class, result);
+        } catch (FlowableException ex) {
+            // 预测未运行的节点时候,表达式如果包含 execution 或者不存在的流程变量会抛异常,
+            log.warn("[calculateUsersByActivity][表达式({}) 变量({}) 解析报错", param, variables, ex);
+            // 不能预测候选人,返回空列表, 避免流程无法进行
+            return Sets.newHashSet();
+        }
     }
     }
 
 
 }
 }

+ 1 - 1
citu-module-bpm/citu-module-bpm-biz/src/main/java/com/citu/module/bpm/framework/flowable/core/candidate/strategy/form/BpmTaskCandidateFormSDeptLeaderStrategy.java → citu-module-bpm/citu-module-bpm-biz/src/main/java/com/citu/module/bpm/framework/flowable/core/candidate/strategy/form/BpmTaskCandidateFormDeptLeaderStrategy.java

@@ -18,7 +18,7 @@ import java.util.Set;
  * @author jason
  * @author jason
  */
  */
 @Component
 @Component
-public class BpmTaskCandidateFormSDeptLeaderStrategy extends AbstractBpmTaskCandidateDeptLeaderStrategy {
+public class BpmTaskCandidateFormDeptLeaderStrategy extends AbstractBpmTaskCandidateDeptLeaderStrategy {
 
 
     @Override
     @Override
     public BpmTaskCandidateStrategyEnum getStrategy() {
     public BpmTaskCandidateStrategyEnum getStrategy() {

+ 10 - 11
citu-module-bpm/citu-module-bpm-biz/src/main/java/com/citu/module/bpm/framework/flowable/core/util/BpmnModelUtils.java

@@ -73,7 +73,6 @@ public class BpmnModelUtils {
         extensionElement.setName(name);
         extensionElement.setName(name);
         attributes.forEach((key, value) -> {
         attributes.forEach((key, value) -> {
             ExtensionAttribute extensionAttribute = new ExtensionAttribute(key, value);
             ExtensionAttribute extensionAttribute = new ExtensionAttribute(key, value);
-            extensionAttribute.setNamespace(FLOWABLE_EXTENSIONS_NAMESPACE);
             extensionElement.addAttribute(extensionAttribute);
             extensionElement.addAttribute(extensionAttribute);
         });
         });
         element.addExtensionElement(extensionElement);
         element.addExtensionElement(extensionElement);
@@ -278,8 +277,8 @@ public class BpmnModelUtils {
         }
         }
         Map<String, String> fieldsPermission = MapUtil.newHashMap();
         Map<String, String> fieldsPermission = MapUtil.newHashMap();
         extensionElements.forEach(element -> {
         extensionElements.forEach(element -> {
-            String field = element.getAttributeValue(FLOWABLE_EXTENSIONS_NAMESPACE, FORM_FIELD_PERMISSION_ELEMENT_FIELD_ATTRIBUTE);
-            String permission = element.getAttributeValue(FLOWABLE_EXTENSIONS_NAMESPACE, FORM_FIELD_PERMISSION_ELEMENT_PERMISSION_ATTRIBUTE);
+            String field = element.getAttributeValue(null, FORM_FIELD_PERMISSION_ELEMENT_FIELD_ATTRIBUTE);
+            String permission = element.getAttributeValue(null, FORM_FIELD_PERMISSION_ELEMENT_PERMISSION_ATTRIBUTE);
             if (StrUtil.isNotEmpty(field) && StrUtil.isNotEmpty(permission)) {
             if (StrUtil.isNotEmpty(field) && StrUtil.isNotEmpty(permission)) {
                 fieldsPermission.put(field, permission);
                 fieldsPermission.put(field, permission);
             }
             }
@@ -321,9 +320,9 @@ public class BpmnModelUtils {
         }
         }
         Map<Integer, BpmTaskRespVO.OperationButtonSetting> buttonSettings = Maps.newHashMapWithExpectedSize(extensionElements.size());
         Map<Integer, BpmTaskRespVO.OperationButtonSetting> buttonSettings = Maps.newHashMapWithExpectedSize(extensionElements.size());
         extensionElements.forEach(element -> {
         extensionElements.forEach(element -> {
-            String id = element.getAttributeValue(FLOWABLE_EXTENSIONS_NAMESPACE, BUTTON_SETTING_ELEMENT_ID_ATTRIBUTE);
-            String displayName = element.getAttributeValue(FLOWABLE_EXTENSIONS_NAMESPACE, BUTTON_SETTING_ELEMENT_DISPLAY_NAME_ATTRIBUTE);
-            String enable = element.getAttributeValue(FLOWABLE_EXTENSIONS_NAMESPACE, BUTTON_SETTING_ELEMENT_ENABLE_ATTRIBUTE);
+            String id = element.getAttributeValue(null, BUTTON_SETTING_ELEMENT_ID_ATTRIBUTE);
+            String displayName = element.getAttributeValue(null, BUTTON_SETTING_ELEMENT_DISPLAY_NAME_ATTRIBUTE);
+            String enable = element.getAttributeValue(null, BUTTON_SETTING_ELEMENT_ENABLE_ATTRIBUTE);
             if (StrUtil.isNotEmpty(id)) {
             if (StrUtil.isNotEmpty(id)) {
                 BpmTaskRespVO.OperationButtonSetting setting = new BpmTaskRespVO.OperationButtonSetting();
                 BpmTaskRespVO.OperationButtonSetting setting = new BpmTaskRespVO.OperationButtonSetting();
                 buttonSettings.put(Integer.valueOf(id), setting.setDisplayName(displayName).setEnable(Boolean.parseBoolean(enable)));
                 buttonSettings.put(Integer.valueOf(id), setting.setDisplayName(displayName).setEnable(Boolean.parseBoolean(enable)));
@@ -699,9 +698,9 @@ public class BpmnModelUtils {
 
 
         // 情况:StartEvent/EndEvent/UserTask/ServiceTask
         // 情况:StartEvent/EndEvent/UserTask/ServiceTask
         if (currentElement instanceof StartEvent
         if (currentElement instanceof StartEvent
-            || currentElement instanceof EndEvent
-            || currentElement instanceof UserTask
-            || currentElement instanceof ServiceTask) {
+                || currentElement instanceof EndEvent
+                || currentElement instanceof UserTask
+                || currentElement instanceof ServiceTask) {
             // 添加元素
             // 添加元素
             FlowNode flowNode = (FlowNode) currentElement;
             FlowNode flowNode = (FlowNode) currentElement;
             resultElements.add(flowNode);
             resultElements.add(flowNode);
@@ -720,7 +719,7 @@ public class BpmnModelUtils {
                             && evalConditionExpress(variables, flow.getConditionExpression()));
                             && evalConditionExpress(variables, flow.getConditionExpression()));
             if (matchSequenceFlow == null) {
             if (matchSequenceFlow == null) {
                 matchSequenceFlow = CollUtil.findOne(gateway.getOutgoingFlows(),
                 matchSequenceFlow = CollUtil.findOne(gateway.getOutgoingFlows(),
-                        flow -> ObjUtil.notEqual(gateway.getDefaultFlow(), flow.getId()));
+                        flow -> ObjUtil.equal(gateway.getDefaultFlow(), flow.getId()));
                 // 特殊:没有默认的情况下,并且只有 1 个条件,则认为它是默认的
                 // 特殊:没有默认的情况下,并且只有 1 个条件,则认为它是默认的
                 if (matchSequenceFlow == null && gateway.getOutgoingFlows().size() == 1) {
                 if (matchSequenceFlow == null && gateway.getOutgoingFlows().size() == 1) {
                     matchSequenceFlow = gateway.getOutgoingFlows().get(0);
                     matchSequenceFlow = gateway.getOutgoingFlows().get(0);
@@ -742,7 +741,7 @@ public class BpmnModelUtils {
                             && evalConditionExpress(variables, flow.getConditionExpression()));
                             && evalConditionExpress(variables, flow.getConditionExpression()));
             if (CollUtil.isEmpty(matchSequenceFlows)) {
             if (CollUtil.isEmpty(matchSequenceFlows)) {
                 matchSequenceFlows = CollUtil.filterNew(gateway.getOutgoingFlows(),
                 matchSequenceFlows = CollUtil.filterNew(gateway.getOutgoingFlows(),
-                        flow -> ObjUtil.notEqual(gateway.getDefaultFlow(), flow.getId()));
+                        flow -> ObjUtil.equal(gateway.getDefaultFlow(), flow.getId()));
                 // 特殊:没有默认的情况下,并且只有 1 个条件,则认为它是默认的
                 // 特殊:没有默认的情况下,并且只有 1 个条件,则认为它是默认的
                 if (CollUtil.isEmpty(matchSequenceFlows) && gateway.getOutgoingFlows().size() == 1) {
                 if (CollUtil.isEmpty(matchSequenceFlows) && gateway.getOutgoingFlows().size() == 1) {
                     matchSequenceFlows = gateway.getOutgoingFlows();
                     matchSequenceFlows = gateway.getOutgoingFlows();

+ 12 - 0
citu-module-bpm/citu-module-bpm-biz/src/main/java/com/citu/module/bpm/framework/flowable/core/util/FlowableUtils.java

@@ -22,6 +22,7 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.List;
 import java.util.Map;
 import java.util.Map;
 import java.util.Objects;
 import java.util.Objects;
+import java.util.concurrent.Callable;
 
 
 /**
 /**
  * Flowable 相关的工具方法
  * Flowable 相关的工具方法
@@ -40,6 +41,17 @@ public class FlowableUtils {
         Authentication.setAuthenticatedUserId(null);
         Authentication.setAuthenticatedUserId(null);
     }
     }
 
 
+    public static <V> V executeAuthenticatedUserId(Long userId, Callable<V> callable) {
+        setAuthenticatedUserId(userId);
+        try {
+            return callable.call();
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        } finally {
+            clearAuthenticatedUserId();
+        }
+    }
+
     public static String getTenantId() {
     public static String getTenantId() {
         Long tenantId = TenantContextHolder.getTenantId();
         Long tenantId = TenantContextHolder.getTenantId();
         return tenantId != null ? String.valueOf(tenantId) : ProcessEngineConfiguration.NO_TENANT_ID;
         return tenantId != null ? String.valueOf(tenantId) : ProcessEngineConfiguration.NO_TENANT_ID;

+ 7 - 7
citu-module-bpm/citu-module-bpm-biz/src/main/java/com/citu/module/bpm/framework/flowable/core/util/SimpleModelUtils.java

@@ -83,7 +83,7 @@ public class SimpleModelUtils {
 
 
     private static BpmSimpleModelNodeVO buildStartNode() {
     private static BpmSimpleModelNodeVO buildStartNode() {
         return new BpmSimpleModelNodeVO().setId(START_EVENT_NODE_ID)
         return new BpmSimpleModelNodeVO().setId(START_EVENT_NODE_ID)
-                .setName(BpmSimpleModelNodeType.START_USER_NODE.getName())
+                .setName(BpmSimpleModelNodeType.START_NODE.getName())
                 .setType(BpmSimpleModelNodeType.START_NODE.getType());
                 .setType(BpmSimpleModelNodeType.START_NODE.getType());
     }
     }
 
 
@@ -620,7 +620,7 @@ public class SimpleModelUtils {
     }
     }
 
 
     private static void simulateNextNode(BpmSimpleModelNodeVO currentNode, Map<String, Object> variables,
     private static void simulateNextNode(BpmSimpleModelNodeVO currentNode, Map<String, Object> variables,
-                                  List<BpmSimpleModelNodeVO> resultNodes) {
+                                         List<BpmSimpleModelNodeVO> resultNodes) {
         // 如果不合法(包括为空),则直接结束
         // 如果不合法(包括为空),则直接结束
         if (!isValidNode(currentNode)) {
         if (!isValidNode(currentNode)) {
             return;
             return;
@@ -630,10 +630,10 @@ public class SimpleModelUtils {
 
 
         // 情况:START_NODE/START_USER_NODE/APPROVE_NODE/COPY_NODE/END_NODE
         // 情况:START_NODE/START_USER_NODE/APPROVE_NODE/COPY_NODE/END_NODE
         if (nodeType == BpmSimpleModelNodeType.START_NODE
         if (nodeType == BpmSimpleModelNodeType.START_NODE
-            || nodeType == BpmSimpleModelNodeType.START_USER_NODE
-            || nodeType == BpmSimpleModelNodeType.APPROVE_NODE
-            || nodeType == BpmSimpleModelNodeType.COPY_NODE
-            || nodeType == BpmSimpleModelNodeType.END_NODE) {
+                || nodeType == BpmSimpleModelNodeType.START_USER_NODE
+                || nodeType == BpmSimpleModelNodeType.APPROVE_NODE
+                || nodeType == BpmSimpleModelNodeType.COPY_NODE
+                || nodeType == BpmSimpleModelNodeType.END_NODE) {
             // 添加元素
             // 添加元素
             resultNodes.add(currentNode);
             resultNodes.add(currentNode);
         }
         }
@@ -643,7 +643,7 @@ public class SimpleModelUtils {
             // 查找满足条件的 BpmSimpleModelNodeVO 节点
             // 查找满足条件的 BpmSimpleModelNodeVO 节点
             BpmSimpleModelNodeVO matchConditionNode = CollUtil.findOne(currentNode.getConditionNodes(),
             BpmSimpleModelNodeVO matchConditionNode = CollUtil.findOne(currentNode.getConditionNodes(),
                     conditionNode -> !BooleanUtil.isTrue(conditionNode.getDefaultFlow())
                     conditionNode -> !BooleanUtil.isTrue(conditionNode.getDefaultFlow())
-                        && evalConditionExpress(variables, conditionNode));
+                            && evalConditionExpress(variables, conditionNode));
             if (matchConditionNode == null) {
             if (matchConditionNode == null) {
                 matchConditionNode = CollUtil.findOne(currentNode.getConditionNodes(),
                 matchConditionNode = CollUtil.findOne(currentNode.getConditionNodes(),
                         conditionNode -> BooleanUtil.isTrue(conditionNode.getDefaultFlow()));
                         conditionNode -> BooleanUtil.isTrue(conditionNode.getDefaultFlow()));

+ 46 - 12
citu-module-bpm/citu-module-bpm-biz/src/main/java/com/citu/module/bpm/service/definition/BpmModelServiceImpl.java

@@ -2,6 +2,7 @@ package com.citu.module.bpm.service.definition;
 
 
 import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.util.ArrayUtil;
 import cn.hutool.core.util.ArrayUtil;
+import cn.hutool.core.util.ObjUtil;
 import cn.hutool.core.util.StrUtil;
 import cn.hutool.core.util.StrUtil;
 import com.citu.framework.common.util.json.JsonUtils;
 import com.citu.framework.common.util.json.JsonUtils;
 import com.citu.framework.common.util.validation.ValidationUtils;
 import com.citu.framework.common.util.validation.ValidationUtils;
@@ -12,6 +13,7 @@ import com.citu.module.bpm.controller.admin.definition.vo.model.simple.BpmSimple
 import com.citu.module.bpm.convert.definition.BpmModelConvert;
 import com.citu.module.bpm.convert.definition.BpmModelConvert;
 import com.citu.module.bpm.dal.dataobject.definition.BpmFormDO;
 import com.citu.module.bpm.dal.dataobject.definition.BpmFormDO;
 import com.citu.module.bpm.enums.definition.BpmModelFormTypeEnum;
 import com.citu.module.bpm.enums.definition.BpmModelFormTypeEnum;
+import com.citu.module.bpm.enums.definition.BpmModelTypeEnum;
 import com.citu.module.bpm.framework.flowable.core.candidate.BpmTaskCandidateInvoker;
 import com.citu.module.bpm.framework.flowable.core.candidate.BpmTaskCandidateInvoker;
 import com.citu.module.bpm.framework.flowable.core.util.BpmnModelUtils;
 import com.citu.module.bpm.framework.flowable.core.util.BpmnModelUtils;
 import com.citu.module.bpm.framework.flowable.core.util.FlowableUtils;
 import com.citu.module.bpm.framework.flowable.core.util.FlowableUtils;
@@ -65,7 +67,7 @@ public class BpmModelServiceImpl implements BpmModelService {
     public List<Model> getModelList(String name) {
     public List<Model> getModelList(String name) {
         ModelQuery modelQuery = repositoryService.createModelQuery();
         ModelQuery modelQuery = repositoryService.createModelQuery();
         if (StrUtil.isNotEmpty(name)) {
         if (StrUtil.isNotEmpty(name)) {
-            modelQuery.modelNameLike(name);
+            modelQuery.modelNameLike("%" + name + "%");
         }
         }
         return modelQuery.list();
         return modelQuery.list();
     }
     }
@@ -82,26 +84,54 @@ public class BpmModelServiceImpl implements BpmModelService {
             throw exception(MODEL_KEY_EXISTS, createReqVO.getKey());
             throw exception(MODEL_KEY_EXISTS, createReqVO.getKey());
         }
         }
 
 
-        // 2.1 创建流程定义
+        // 2. 创建 Model 对象
         createReqVO.setSort(System.currentTimeMillis()); // 使用当前时间,作为排序
         createReqVO.setSort(System.currentTimeMillis()); // 使用当前时间,作为排序
         Model model = repositoryService.newModel();
         Model model = repositoryService.newModel();
         BpmModelConvert.INSTANCE.copyToModel(model, createReqVO);
         BpmModelConvert.INSTANCE.copyToModel(model, createReqVO);
         model.setTenantId(FlowableUtils.getTenantId());
         model.setTenantId(FlowableUtils.getTenantId());
-        // 2.2 保存流程定义
-        repositoryService.saveModel(model);
+
+        // 3. 保存模型
+        saveModel(model, createReqVO);
         return model.getId();
         return model.getId();
     }
     }
 
 
     @Override
     @Override
     @Transactional(rollbackFor = Exception.class) // 因为进行多个操作,所以开启事务
     @Transactional(rollbackFor = Exception.class) // 因为进行多个操作,所以开启事务
-    public void updateModel(Long userId, @Valid BpmModelSaveReqVO updateReqVO) {
+    public void updateModel(Long userId, BpmModelSaveReqVO updateReqVO) {
         // 1. 校验流程模型存在
         // 1. 校验流程模型存在
         Model model = validateModelManager(updateReqVO.getId(), userId);
         Model model = validateModelManager(updateReqVO.getId(), userId);
 
 
-        // 修改流程定义
+        // 2. 填充 Model 信息
         BpmModelConvert.INSTANCE.copyToModel(model, updateReqVO);
         BpmModelConvert.INSTANCE.copyToModel(model, updateReqVO);
-        // 更新模型
+
+        // 3. 保存模型
+        saveModel(model, updateReqVO);
+    }
+
+    /**
+     * 保存模型的基本信息、流程图
+     *
+     * @param model 模型
+     * @param saveReqVO 保存信息
+     */
+    private void saveModel(Model model, BpmModelSaveReqVO saveReqVO) {
+        // 1. 保存模型的基础信息
         repositoryService.saveModel(model);
         repositoryService.saveModel(model);
+
+        // 2. 保存流程图
+        if (ObjUtil.equals(BpmModelTypeEnum.BPMN.getType(), saveReqVO.getType())
+                && StrUtil.isNotEmpty(saveReqVO.getBpmnXml())) {
+            updateModelBpmnXml(model.getId(), saveReqVO.getBpmnXml());
+        } else if (ObjUtil.equals(BpmModelTypeEnum.SIMPLE.getType(), saveReqVO.getType())
+                && saveReqVO.getSimpleModel() != null) {
+            // JSON 转换成 bpmnModel
+            BpmnModel bpmnModel = SimpleModelUtils.buildBpmnModel(model.getKey(), model.getName(),
+                    saveReqVO.getSimpleModel());
+            // 保存 Bpmn XML
+            updateModelBpmnXml(model.getId(), BpmnModelUtils.getBpmnXml(bpmnModel));
+            // 保存 JSON 数据
+            updateModelSimpleJson(model.getId(), saveReqVO.getSimpleModel());
+        }
     }
     }
 
 
     @Override
     @Override
@@ -110,7 +140,7 @@ public class BpmModelServiceImpl implements BpmModelService {
         // 1.1 校验流程模型存在
         // 1.1 校验流程模型存在
         List<Model> models = repositoryService.createModelQuery()
         List<Model> models = repositoryService.createModelQuery()
                 .modelTenantId(FlowableUtils.getTenantId()).list();
                 .modelTenantId(FlowableUtils.getTenantId()).list();
-        models.removeIf(model ->!ids.contains(model.getId()));
+        models.removeIf(model -> !ids.contains(model.getId()));
         if (ids.size() != models.size()) {
         if (ids.size() != models.size()) {
             throw exception(MODEL_NOT_EXISTS);
             throw exception(MODEL_NOT_EXISTS);
         }
         }
@@ -173,7 +203,8 @@ public class BpmModelServiceImpl implements BpmModelService {
         String simpleJson = getModelSimpleJson(model.getId());
         String simpleJson = getModelSimpleJson(model.getId());
 
 
         // 2.1 创建流程定义
         // 2.1 创建流程定义
-        String definitionId = processDefinitionService.createProcessDefinition(model, metaInfo, bpmnBytes, simpleJson, form);
+        String definitionId = processDefinitionService.createProcessDefinition(model, metaInfo, bpmnBytes, simpleJson,
+                form);
 
 
         // 2.2 将老的流程定义进行挂起。也就是说,只有最新部署的流程定义,才可以发起任务。
         // 2.2 将老的流程定义进行挂起。也就是说,只有最新部署的流程定义,才可以发起任务。
         updateProcessDefinitionSuspended(model.getDeploymentId());
         updateProcessDefinitionSuspended(model.getDeploymentId());
@@ -220,7 +251,8 @@ public class BpmModelServiceImpl implements BpmModelService {
         // 1.1 校验流程模型存在
         // 1.1 校验流程模型存在
         Model model = validateModelManager(id, userId);
         Model model = validateModelManager(id, userId);
         // 1.2 校验流程定义存在
         // 1.2 校验流程定义存在
-        ProcessDefinition definition = processDefinitionService.getProcessDefinitionByDeploymentId(model.getDeploymentId());
+        ProcessDefinition definition = processDefinitionService
+                .getProcessDefinitionByDeploymentId(model.getDeploymentId());
         if (definition == null) {
         if (definition == null) {
             throw exception(PROCESS_DEFINITION_NOT_EXISTS);
             throw exception(PROCESS_DEFINITION_NOT_EXISTS);
         }
         }
@@ -276,7 +308,8 @@ public class BpmModelServiceImpl implements BpmModelService {
             }
             }
             return form;
             return form;
         } else {
         } else {
-            if (StrUtil.isEmpty(metaInfo.getFormCustomCreatePath()) || StrUtil.isEmpty(metaInfo.getFormCustomViewPath())) {
+            if (StrUtil.isEmpty(metaInfo.getFormCustomCreatePath())
+                    || StrUtil.isEmpty(metaInfo.getFormCustomViewPath())) {
                 throw exception(MODEL_DEPLOY_FAIL_FORM_NOT_CONFIG);
                 throw exception(MODEL_DEPLOY_FAIL_FORM_NOT_CONFIG);
             }
             }
             return null;
             return null;
@@ -323,7 +356,8 @@ public class BpmModelServiceImpl implements BpmModelService {
         if (oldDefinition == null) {
         if (oldDefinition == null) {
             return;
             return;
         }
         }
-        processDefinitionService.updateProcessDefinitionState(oldDefinition.getId(), SuspensionState.SUSPENDED.getStateCode());
+        processDefinitionService.updateProcessDefinitionState(oldDefinition.getId(),
+                SuspensionState.SUSPENDED.getStateCode());
     }
     }
 
 
     private Model getModelByKey(String key) {
     private Model getModelByKey(String key) {

File diff suppressed because it is too large
+ 0 - 0
citu-module-bpm/citu-module-bpm-biz/src/main/java/com/citu/module/bpm/service/task/BpmProcessInstanceServiceImpl.java


+ 67 - 21
citu-module-bpm/citu-module-bpm-biz/src/main/java/com/citu/module/bpm/service/task/BpmTaskServiceImpl.java

@@ -12,6 +12,7 @@ import com.citu.framework.common.util.object.PageUtils;
 import com.citu.framework.web.core.util.WebFrameworkUtils;
 import com.citu.framework.web.core.util.WebFrameworkUtils;
 import com.citu.module.bpm.controller.admin.task.vo.task.*;
 import com.citu.module.bpm.controller.admin.task.vo.task.*;
 import com.citu.module.bpm.convert.task.BpmTaskConvert;
 import com.citu.module.bpm.convert.task.BpmTaskConvert;
+import com.citu.module.bpm.dal.dataobject.definition.BpmFormDO;
 import com.citu.module.bpm.enums.definition.*;
 import com.citu.module.bpm.enums.definition.*;
 import com.citu.module.bpm.enums.task.BpmCommentTypeEnum;
 import com.citu.module.bpm.enums.task.BpmCommentTypeEnum;
 import com.citu.module.bpm.enums.task.BpmReasonEnum;
 import com.citu.module.bpm.enums.task.BpmReasonEnum;
@@ -20,6 +21,7 @@ import com.citu.module.bpm.enums.task.BpmTaskStatusEnum;
 import com.citu.module.bpm.framework.flowable.core.enums.BpmnVariableConstants;
 import com.citu.module.bpm.framework.flowable.core.enums.BpmnVariableConstants;
 import com.citu.module.bpm.framework.flowable.core.util.BpmnModelUtils;
 import com.citu.module.bpm.framework.flowable.core.util.BpmnModelUtils;
 import com.citu.module.bpm.framework.flowable.core.util.FlowableUtils;
 import com.citu.module.bpm.framework.flowable.core.util.FlowableUtils;
+import com.citu.module.bpm.service.definition.BpmFormService;
 import com.citu.module.bpm.service.definition.BpmModelService;
 import com.citu.module.bpm.service.definition.BpmModelService;
 import com.citu.module.bpm.service.definition.BpmProcessDefinitionService;
 import com.citu.module.bpm.service.definition.BpmProcessDefinitionService;
 import com.citu.module.bpm.service.message.BpmMessageService;
 import com.citu.module.bpm.service.message.BpmMessageService;
@@ -91,6 +93,8 @@ public class BpmTaskServiceImpl implements BpmTaskService {
     private BpmModelService modelService;
     private BpmModelService modelService;
     @Resource
     @Resource
     private BpmMessageService messageService;
     private BpmMessageService messageService;
+    @Resource
+    private BpmFormService formService;
 
 
     @Resource
     @Resource
     private AdminUserApi adminUserApi;
     private AdminUserApi adminUserApi;
@@ -109,6 +113,9 @@ public class BpmTaskServiceImpl implements BpmTaskService {
         if (StrUtil.isNotBlank(pageVO.getName())) {
         if (StrUtil.isNotBlank(pageVO.getName())) {
             taskQuery.taskNameLike("%" + pageVO.getName() + "%");
             taskQuery.taskNameLike("%" + pageVO.getName() + "%");
         }
         }
+        if (StrUtil.isNotEmpty(pageVO.getCategory())) {
+            taskQuery.taskCategory(pageVO.getCategory());
+        }
         if (ArrayUtil.isNotEmpty(pageVO.getCreateTime())) {
         if (ArrayUtil.isNotEmpty(pageVO.getCreateTime())) {
             taskQuery.taskCreatedAfter(DateUtils.of(pageVO.getCreateTime()[0]));
             taskQuery.taskCreatedAfter(DateUtils.of(pageVO.getCreateTime()[0]));
             taskQuery.taskCreatedBefore(DateUtils.of(pageVO.getCreateTime()[1]));
             taskQuery.taskCreatedBefore(DateUtils.of(pageVO.getCreateTime()[1]));
@@ -153,7 +160,13 @@ public class BpmTaskServiceImpl implements BpmTaskService {
         BpmnModel bpmnModel = bpmProcessDefinitionService.getProcessDefinitionBpmnModel(todoTask.getProcessDefinitionId());
         BpmnModel bpmnModel = bpmProcessDefinitionService.getProcessDefinitionBpmnModel(todoTask.getProcessDefinitionId());
         Map<Integer, BpmTaskRespVO.OperationButtonSetting> buttonsSetting = BpmnModelUtils.parseButtonsSetting(
         Map<Integer, BpmTaskRespVO.OperationButtonSetting> buttonsSetting = BpmnModelUtils.parseButtonsSetting(
                 bpmnModel, todoTask.getTaskDefinitionKey());
                 bpmnModel, todoTask.getTaskDefinitionKey());
-        return BpmTaskConvert.INSTANCE.buildTodoTask(todoTask, childrenTasks, buttonsSetting);
+
+        // 4. 任务表单
+        BpmFormDO taskForm = null;
+        if (StrUtil.isNotBlank(todoTask.getFormKey())){
+            taskForm = formService.getForm(NumberUtils.parseLong(todoTask.getFormKey()));
+        }
+        return BpmTaskConvert.INSTANCE.buildTodoTask(todoTask, childrenTasks, buttonsSetting, taskForm);
     }
     }
 
 
     @Override
     @Override
@@ -188,6 +201,9 @@ public class BpmTaskServiceImpl implements BpmTaskService {
         if (StrUtil.isNotBlank(pageVO.getName())) {
         if (StrUtil.isNotBlank(pageVO.getName())) {
             taskQuery.taskNameLike("%" + pageVO.getName() + "%");
             taskQuery.taskNameLike("%" + pageVO.getName() + "%");
         }
         }
+        if (StrUtil.isNotEmpty(pageVO.getCategory())) {
+            taskQuery.taskCategory(pageVO.getCategory());
+        }
         if (ArrayUtil.isNotEmpty(pageVO.getCreateTime())) {
         if (ArrayUtil.isNotEmpty(pageVO.getCreateTime())) {
             taskQuery.taskCreatedAfter(DateUtils.of(pageVO.getCreateTime()[0]));
             taskQuery.taskCreatedAfter(DateUtils.of(pageVO.getCreateTime()[0]));
             taskQuery.taskCreatedBefore(DateUtils.of(pageVO.getCreateTime()[1]));
             taskQuery.taskCreatedBefore(DateUtils.of(pageVO.getCreateTime()[1]));
@@ -441,7 +457,7 @@ public class BpmTaskServiceImpl implements BpmTaskService {
      * 判断指定用户,是否是当前任务的加签人
      * 判断指定用户,是否是当前任务的加签人
      *
      *
      * @param userId 用户 Id
      * @param userId 用户 Id
-     * @param task 任务
+     * @param task   任务
      * @return 是否
      * @return 是否
      */
      */
     private boolean isAddSignUserTask(Long userId, Task task) {
     private boolean isAddSignUserTask(Long userId, Task task) {
@@ -669,7 +685,7 @@ public class BpmTaskServiceImpl implements BpmTaskService {
                 reqVO.getTargetTaskDefinitionKey(), task.getProcessDefinitionId());
                 reqVO.getTargetTaskDefinitionKey(), task.getProcessDefinitionId());
 
 
         // 2. 调用 Flowable 框架的退回逻辑
         // 2. 调用 Flowable 框架的退回逻辑
-        returnTask(task, targetElement, reqVO);
+        returnTask(userId, task, targetElement, reqVO);
     }
     }
 
 
     /**
     /**
@@ -701,11 +717,12 @@ public class BpmTaskServiceImpl implements BpmTaskService {
     /**
     /**
      * 执行退回逻辑
      * 执行退回逻辑
      *
      *
+     * @param userId        用户编号
      * @param currentTask   当前退回的任务
      * @param currentTask   当前退回的任务
      * @param targetElement 需要退回到的目标任务
      * @param targetElement 需要退回到的目标任务
      * @param reqVO         前端参数封装
      * @param reqVO         前端参数封装
      */
      */
-    public void returnTask(Task currentTask, FlowElement targetElement, BpmTaskReturnReqVO reqVO) {
+    public void returnTask(Long userId, Task currentTask, FlowElement targetElement, BpmTaskReturnReqVO reqVO) {
         // 1. 获得所有需要回撤的任务 taskDefinitionKey,用于稍后的 moveActivityIdsToSingleActivityId 回撤
         // 1. 获得所有需要回撤的任务 taskDefinitionKey,用于稍后的 moveActivityIdsToSingleActivityId 回撤
         // 1.1 获取所有正常进行的任务节点 Key
         // 1.1 获取所有正常进行的任务节点 Key
         List<Task> taskList = taskService.createTaskQuery().processInstanceId(currentTask.getProcessInstanceId()).list();
         List<Task> taskList = taskService.createTaskQuery().processInstanceId(currentTask.getProcessInstanceId()).list();
@@ -721,22 +738,29 @@ public class BpmTaskServiceImpl implements BpmTaskService {
             if (!returnTaskKeyList.contains(task.getTaskDefinitionKey())) {
             if (!returnTaskKeyList.contains(task.getTaskDefinitionKey())) {
                 return;
                 return;
             }
             }
-            // 2.1 添加评论
-            taskService.addComment(task.getId(), currentTask.getProcessInstanceId(), BpmCommentTypeEnum.RETURN.getType(),
-                    BpmCommentTypeEnum.RETURN.formatComment(reqVO.getReason()));
-            // 2.2 更新 task 状态 + 原因
-            updateTaskStatusAndReason(task.getId(), BpmTaskStatusEnum.RETURN.getStatus(), reqVO.getReason());
+
+            // 判断是否分配给自己任务,因为会签任务,一个节点会有多个任务
+            if (isAssignUserTask(userId, task)) { // 情况一:自己的任务,进行 RETURN 标记
+                // 2.1.1 添加评论
+                taskService.addComment(task.getId(), currentTask.getProcessInstanceId(), BpmCommentTypeEnum.RETURN.getType(),
+                        BpmCommentTypeEnum.RETURN.formatComment(reqVO.getReason()));
+                // 2.1.2 更新 task 状态 + 原因
+                updateTaskStatusAndReason(task.getId(), BpmTaskStatusEnum.RETURN.getStatus(), reqVO.getReason());
+            } else { // 情况二:别人的任务,进行 CANCEL 标记
+                processTaskCanceled(task.getId());
+            }
         });
         });
 
 
         // 3. 设置流程变量节点驳回标记:用于驳回到节点,不执行 BpmUserTaskAssignStartUserHandlerTypeEnum 策略。导致自动通过
         // 3. 设置流程变量节点驳回标记:用于驳回到节点,不执行 BpmUserTaskAssignStartUserHandlerTypeEnum 策略。导致自动通过
         runtimeService.setVariable(currentTask.getProcessInstanceId(),
         runtimeService.setVariable(currentTask.getProcessInstanceId(),
                 String.format(PROCESS_INSTANCE_VARIABLE_RETURN_FLAG, reqVO.getTargetTaskDefinitionKey()), Boolean.TRUE);
                 String.format(PROCESS_INSTANCE_VARIABLE_RETURN_FLAG, reqVO.getTargetTaskDefinitionKey()), Boolean.TRUE);
-
         // 4. 执行驳回
         // 4. 执行驳回
+        // 使用 moveExecutionsToSingleActivityId 替换 moveActivityIdsToSingleActivityId 原因:
+        // 当多实例任务回退的时候有问题。相关 issue: https://github.com/flowable/flowable-engine/issues/3944
+        List<String> runExecutionIds = convertList(taskList, Task::getExecutionId);
         runtimeService.createChangeActivityStateBuilder()
         runtimeService.createChangeActivityStateBuilder()
                 .processInstanceId(currentTask.getProcessInstanceId())
                 .processInstanceId(currentTask.getProcessInstanceId())
-                .moveActivityIdsToSingleActivityId(returnTaskKeyList, // 当前要跳转的节点列表( 1 或多)
-                        reqVO.getTargetTaskDefinitionKey()) // targetKey 跳转到的节点(1)
+                .moveExecutionsToSingleActivityId(runExecutionIds, reqVO.getTargetTaskDefinitionKey())
                 .changeState();
                 .changeState();
     }
     }
 
 
@@ -1021,14 +1045,22 @@ public class BpmTaskServiceImpl implements BpmTaskService {
         Integer assignEmptyHandlerType = BpmnModelUtils.parseAssignEmptyHandlerType(userTaskElement);
         Integer assignEmptyHandlerType = BpmnModelUtils.parseAssignEmptyHandlerType(userTaskElement);
         TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
         TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
 
 
+            /**
+             * 特殊情况:部分情况下,TransactionSynchronizationManager 注册 afterCommit 监听时,不会被调用,但是 afterCompletion 可以
+             * 例如说:第一个 task 就是配置【自动通过】或者【自动拒绝】时
+             * 参见 <a href="https://gitee.com/zhijiantianya/yudao-cloud/issues/IB7V7Q">issue</a> 反馈
+             */
             @Override
             @Override
             public void afterCompletion(int transactionStatus) {
             public void afterCompletion(int transactionStatus) {
-                // 特殊情况:部分情况下,TransactionSynchronizationManager 注册 afterCommit 监听时,不会被调用,但是 afterCompletion 可以
-                // 例如说:第一个 task 就是配置【自动通过】或者【自动拒绝】时
-                if (ObjectUtil.notEqual(transactionStatus, TransactionSynchronization.STATUS_COMMITTED)) {
+                // 回滚情况,直接返回
+                if (ObjectUtil.equal(transactionStatus, TransactionSynchronization.STATUS_ROLLED_BACK)) {
+                    return;
+                }
+                // 特殊情况:第一个 task 【自动通过】时,第二个任务设置审批人时 transactionStatus 会为 STATUS_UNKNOWN,不知道啥原因
+                if (ObjectUtil.equal(transactionStatus, TransactionSynchronization.STATUS_UNKNOWN)
+                        && getTask(task.getId()) == null) {
                     return;
                     return;
                 }
                 }
-                // TODO 芋艿:可以后续优化成 getSelf();
                 // 特殊情况一:【人工审核】审批人为空,根据配置是否要自动通过、自动拒绝
                 // 特殊情况一:【人工审核】审批人为空,根据配置是否要自动通过、自动拒绝
                 if (ObjectUtil.equal(approveType, BpmUserTaskApproveTypeEnum.USER.getType())) {
                 if (ObjectUtil.equal(approveType, BpmUserTaskApproveTypeEnum.USER.getType())) {
                     // 如果有审批人、或者拥有人,则说明不满足情况一,不自动通过、不自动拒绝
                     // 如果有审批人、或者拥有人,则说明不满足情况一,不自动通过、不自动拒绝
@@ -1036,19 +1068,19 @@ public class BpmTaskServiceImpl implements BpmTaskService {
                         return;
                         return;
                     }
                     }
                     if (ObjectUtil.equal(assignEmptyHandlerType, BpmUserTaskAssignEmptyHandlerTypeEnum.APPROVE.getType())) {
                     if (ObjectUtil.equal(assignEmptyHandlerType, BpmUserTaskAssignEmptyHandlerTypeEnum.APPROVE.getType())) {
-                        SpringUtil.getBean(BpmTaskService.class).approveTask(null, new BpmTaskApproveReqVO()
+                        getSelf().approveTask(null, new BpmTaskApproveReqVO()
                                 .setId(task.getId()).setReason(BpmReasonEnum.ASSIGN_EMPTY_APPROVE.getReason()));
                                 .setId(task.getId()).setReason(BpmReasonEnum.ASSIGN_EMPTY_APPROVE.getReason()));
                     } else if (ObjectUtil.equal(assignEmptyHandlerType, BpmUserTaskAssignEmptyHandlerTypeEnum.REJECT.getType())) {
                     } else if (ObjectUtil.equal(assignEmptyHandlerType, BpmUserTaskAssignEmptyHandlerTypeEnum.REJECT.getType())) {
-                        SpringUtil.getBean(BpmTaskService.class).rejectTask(null, new BpmTaskRejectReqVO()
+                        getSelf().rejectTask(null, new BpmTaskRejectReqVO()
                                 .setId(task.getId()).setReason(BpmReasonEnum.ASSIGN_EMPTY_REJECT.getReason()));
                                 .setId(task.getId()).setReason(BpmReasonEnum.ASSIGN_EMPTY_REJECT.getReason()));
                     }
                     }
                     // 特殊情况二:【自动审核】审批类型为自动通过、不通过
                     // 特殊情况二:【自动审核】审批类型为自动通过、不通过
                 } else {
                 } else {
                     if (ObjectUtil.equal(approveType, BpmUserTaskApproveTypeEnum.AUTO_APPROVE.getType())) {
                     if (ObjectUtil.equal(approveType, BpmUserTaskApproveTypeEnum.AUTO_APPROVE.getType())) {
-                        SpringUtil.getBean(BpmTaskService.class).approveTask(null, new BpmTaskApproveReqVO()
+                        getSelf().approveTask(null, new BpmTaskApproveReqVO()
                                 .setId(task.getId()).setReason(BpmReasonEnum.APPROVE_TYPE_AUTO_APPROVE.getReason()));
                                 .setId(task.getId()).setReason(BpmReasonEnum.APPROVE_TYPE_AUTO_APPROVE.getReason()));
                     } else if (ObjectUtil.equal(approveType, BpmUserTaskApproveTypeEnum.AUTO_REJECT.getType())) {
                     } else if (ObjectUtil.equal(approveType, BpmUserTaskApproveTypeEnum.AUTO_REJECT.getType())) {
-                        SpringUtil.getBean(BpmTaskService.class).rejectTask(null, new BpmTaskRejectReqVO()
+                        getSelf().rejectTask(null, new BpmTaskRejectReqVO()
                                 .setId(task.getId()).setReason(BpmReasonEnum.APPROVE_TYPE_AUTO_REJECT.getReason()));
                                 .setId(task.getId()).setReason(BpmReasonEnum.APPROVE_TYPE_AUTO_REJECT.getReason()));
                     }
                     }
                 }
                 }
@@ -1087,8 +1119,22 @@ public class BpmTaskServiceImpl implements BpmTaskService {
         // 发送通知。在事务提交时,批量执行操作,所以直接查询会无法查询到 ProcessInstance,所以这里是通过监听事务的提交来实现。
         // 发送通知。在事务提交时,批量执行操作,所以直接查询会无法查询到 ProcessInstance,所以这里是通过监听事务的提交来实现。
         TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
         TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
 
 
+            /**
+             * 特殊情况:部分情况下,TransactionSynchronizationManager 注册 afterCommit 监听时,不会被调用,但是 afterCompletion 可以
+             * 例如说:第一个 task 就是配置【自动通过】或者【自动拒绝】时
+             * 参见 <a href="https://gitee.com/zhijiantianya/yudao-cloud/issues/IB7V7Q">issue</a> 反馈
+             */
             @Override
             @Override
-            public void afterCommit() {
+            public void afterCompletion(int transactionStatus) {
+                // 回滚情况,直接返回
+                if (ObjectUtil.equal(transactionStatus, TransactionSynchronization.STATUS_ROLLED_BACK)) {
+                    return;
+                }
+                // 特殊情况:第一个 task 【自动通过】时,第二个任务设置审批人时 transactionStatus 会为 STATUS_UNKNOWN,不知道啥原因
+                if (ObjectUtil.equal(transactionStatus, TransactionSynchronization.STATUS_UNKNOWN)
+                        && getTask(task.getId()) == null) {
+                    return;
+                }
                 if (StrUtil.isEmpty(task.getAssignee())) {
                 if (StrUtil.isEmpty(task.getAssignee())) {
                     log.error("[processTaskAssigned][taskId({}) 没有分配到负责人]", task.getId());
                     log.error("[processTaskAssigned][taskId({}) 没有分配到负责人]", task.getId());
                     return;
                     return;

+ 5 - 4
citu-module-crm/citu-module-crm-biz/src/main/java/com/citu/module/crm/dal/mysql/receivable/CrmReceivablePlanMapper.java

@@ -62,12 +62,13 @@ public interface CrmReceivablePlanMapper extends BaseMapperX<CrmReceivablePlanDO
         // Backlog: 回款提醒类型
         // Backlog: 回款提醒类型
         LocalDateTime beginOfToday = LocalDateTimeUtil.beginOfDay(LocalDateTime.now());
         LocalDateTime beginOfToday = LocalDateTimeUtil.beginOfDay(LocalDateTime.now());
         if (CrmReceivablePlanPageReqVO.REMIND_TYPE_NEEDED.equals(pageReqVO.getRemindType())) { // 待回款
         if (CrmReceivablePlanPageReqVO.REMIND_TYPE_NEEDED.equals(pageReqVO.getRemindType())) { // 待回款
+            // 查询条件:未回款 + 提醒时间 <= 当前时间(反过来即当前时间 >= 提醒时间,已经到达提醒的时间点)
             query.isNull(CrmReceivablePlanDO::getReceivableId) // 未回款
             query.isNull(CrmReceivablePlanDO::getReceivableId) // 未回款
-                    .lt(CrmReceivablePlanDO::getReturnTime, beginOfToday) // 已逾期
-                    .lt(CrmReceivablePlanDO::getRemindTime, beginOfToday); // 今天开始提醒
-        } else if (CrmReceivablePlanPageReqVO.REMIND_TYPE_EXPIRED.equals(pageReqVO.getRemindType())) {  // 已逾期
+                    .le(CrmReceivablePlanDO::getRemindTime, beginOfToday); // 今天开始提醒
+        } else if (CrmReceivablePlanPageReqVO.REMIND_TYPE_EXPIRED.equals(pageReqVO.getRemindType())) { // 已逾期
+            // 查询条件:未回款 + 回款时间 < 当前时间(反过来即当前时间 > 回款时间,已经过了回款时间点)
             query.isNull(CrmReceivablePlanDO::getReceivableId) // 未回款
             query.isNull(CrmReceivablePlanDO::getReceivableId) // 未回款
-                    .ge(CrmReceivablePlanDO::getReturnTime, beginOfToday); // 已逾期
+                    .lt(CrmReceivablePlanDO::getReturnTime, beginOfToday); // 已逾期
         } else if (CrmReceivablePlanPageReqVO.REMIND_TYPE_RECEIVED.equals(pageReqVO.getRemindType())) { // 已回款
         } else if (CrmReceivablePlanPageReqVO.REMIND_TYPE_RECEIVED.equals(pageReqVO.getRemindType())) { // 已回款
             query.isNotNull(CrmReceivablePlanDO::getReceivableId);
             query.isNotNull(CrmReceivablePlanDO::getReceivableId);
         }
         }

+ 1 - 1
citu-module-crm/citu-module-crm-biz/src/main/java/com/citu/module/crm/service/contract/CrmContractServiceImpl.java

@@ -270,7 +270,7 @@ public class CrmContractServiceImpl implements CrmContractService {
     }
     }
 
 
     @Override
     @Override
-    @LogRecord(type = CRM_CONTRACT_TYPE, subType = CRM_CONTRACT_FOLLOW_UP_SUB_TYPE, bizNo = "{{#id}",
+    @LogRecord(type = CRM_CONTRACT_TYPE, subType = CRM_CONTRACT_FOLLOW_UP_SUB_TYPE, bizNo = "{{#id}}",
             success = CRM_CONTRACT_FOLLOW_UP_SUCCESS)
             success = CRM_CONTRACT_FOLLOW_UP_SUCCESS)
     @CrmPermission(bizType = CrmBizTypeEnum.CRM_CONTRACT, bizId = "#id", level = CrmPermissionLevelEnum.WRITE)
     @CrmPermission(bizType = CrmBizTypeEnum.CRM_CONTRACT, bizId = "#id", level = CrmPermissionLevelEnum.WRITE)
     public void updateContractFollowUp(Long id, LocalDateTime contactNextTime, String contactLastContent) {
     public void updateContractFollowUp(Long id, LocalDateTime contactNextTime, String contactLastContent) {

+ 2 - 1
citu-module-crm/citu-module-crm-biz/src/main/java/com/citu/module/crm/util/CrmPermissionUtils.java

@@ -62,7 +62,8 @@ public class CrmPermissionUtils {
             }
             }
             query.innerJoin(CrmPermissionDO.class, on -> on.eq(CrmPermissionDO::getBizType, bizType)
             query.innerJoin(CrmPermissionDO.class, on -> on.eq(CrmPermissionDO::getBizType, bizType)
                     .eq(CrmPermissionDO::getBizId, bizId)
                     .eq(CrmPermissionDO::getBizId, bizId)
-                    .in(CrmPermissionDO::getLevel, CrmPermissionLevelEnum.READ.getLevel(), CrmPermissionLevelEnum.WRITE.getLevel()));
+                    .in(CrmPermissionDO::getLevel, CrmPermissionLevelEnum.READ.getLevel(), CrmPermissionLevelEnum.WRITE.getLevel())
+                    .eq(CrmPermissionDO::getUserId,userId));
             query.ne(ownerUserIdField, userId);
             query.ne(ownerUserIdField, userId);
         }
         }
         // 场景三:下属负责的数据(下属是负责人)
         // 场景三:下属负责的数据(下属是负责人)

+ 2 - 0
citu-module-erp/citu-module-erp-biz/src/main/java/com/citu/module/erp/controller/admin/finance/vo/payment/ErpFinancePaymentRespVO.java

@@ -1,5 +1,6 @@
 package com.citu.module.erp.controller.admin.finance.vo.payment;
 package com.citu.module.erp.controller.admin.finance.vo.payment;
 
 
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
 import com.alibaba.excel.annotation.ExcelProperty;
 import com.alibaba.excel.annotation.ExcelProperty;
 import io.swagger.v3.oas.annotations.media.Schema;
 import io.swagger.v3.oas.annotations.media.Schema;
 import javax.validation.constraints.NotNull;
 import javax.validation.constraints.NotNull;
@@ -11,6 +12,7 @@ import java.util.List;
 
 
 @Schema(description = "管理后台 - ERP 付款单 Response VO")
 @Schema(description = "管理后台 - ERP 付款单 Response VO")
 @Data
 @Data
+@ExcelIgnoreUnannotated
 public class ErpFinancePaymentRespVO {
 public class ErpFinancePaymentRespVO {
 
 
     @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "23752")
     @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "23752")

+ 2 - 0
citu-module-erp/citu-module-erp-biz/src/main/java/com/citu/module/erp/controller/admin/finance/vo/receipt/ErpFinanceReceiptRespVO.java

@@ -1,5 +1,6 @@
 package com.citu.module.erp.controller.admin.finance.vo.receipt;
 package com.citu.module.erp.controller.admin.finance.vo.receipt;
 
 
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
 import com.alibaba.excel.annotation.ExcelProperty;
 import com.alibaba.excel.annotation.ExcelProperty;
 import io.swagger.v3.oas.annotations.media.Schema;
 import io.swagger.v3.oas.annotations.media.Schema;
 import javax.validation.constraints.NotNull;
 import javax.validation.constraints.NotNull;
@@ -11,6 +12,7 @@ import java.util.List;
 
 
 @Schema(description = "管理后台 - ERP 收款单 Response VO")
 @Schema(description = "管理后台 - ERP 收款单 Response VO")
 @Data
 @Data
+@ExcelIgnoreUnannotated
 public class ErpFinanceReceiptRespVO {
 public class ErpFinanceReceiptRespVO {
 
 
     @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "23752")
     @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "23752")

+ 2 - 2
citu-module-mall/citu-module-product-api/src/main/java/com/citu/module/product/enums/comment/ProductCommentAuditStatusEnum.java

@@ -15,8 +15,8 @@ import java.util.Arrays;
 @AllArgsConstructor
 @AllArgsConstructor
 public enum ProductCommentAuditStatusEnum implements IntArrayValuable {
 public enum ProductCommentAuditStatusEnum implements IntArrayValuable {
 
 
-    NONE(1, "待审核"),
-    APPROVE(2, "审批通过"),
+    NONE(0, "待审核"),
+    APPROVE(1, "审批通过"),
     REJECT(2, "审批不通过"),;
     REJECT(2, "审批不通过"),;
 
 
     public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(ProductCommentAuditStatusEnum::getStatus).toArray();
     public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(ProductCommentAuditStatusEnum::getStatus).toArray();

+ 19 - 0
citu-module-mall/citu-module-product-api/src/main/java/com/citu/module/product/enums/spu/ProductSpuTypeEnum.java

@@ -0,0 +1,19 @@
+package com.citu.module.product.enums.spu;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * 商品 SPU 类型
+ * 0 普通商品 | 1 虚拟商品
+ * @author Rayson
+ */
+@Getter
+@AllArgsConstructor
+public enum ProductSpuTypeEnum {
+    NORMAL("0", "普通商品"),
+    VIRTUAL("1", "虚拟商品");
+
+    private final String type;
+    private final String name;
+}

+ 3 - 0
citu-module-mall/citu-module-product-biz/src/main/java/com/citu/module/product/controller/admin/spu/vo/ProductSpuPageReqVO.java

@@ -45,6 +45,9 @@ public class ProductSpuPageReqVO extends PageParam {
     @Schema(description = "商品名称", example = "清凉小短袖")
     @Schema(description = "商品名称", example = "清凉小短袖")
     private String name;
     private String name;
 
 
+    @Schema(description = "商品类型")
+    private String type;
+
     @Schema(description = "前端请求的tab类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
     @Schema(description = "前端请求的tab类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
     private Integer tabType;
     private Integer tabType;
 
 

+ 5 - 0
citu-module-mall/citu-module-product-biz/src/main/java/com/citu/module/product/controller/admin/spu/vo/ProductSpuRespVO.java

@@ -25,6 +25,11 @@ public class ProductSpuRespVO {
     @ExcelProperty("商品名称")
     @ExcelProperty("商品名称")
     private String name;
     private String name;
 
 
+    @Schema(description = "商品类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
+    @ExcelProperty("商品类型")
+    private String type;
+
+
     @Schema(description = "关键字", requiredMode = Schema.RequiredMode.REQUIRED, example = "清凉丝滑不出汗")
     @Schema(description = "关键字", requiredMode = Schema.RequiredMode.REQUIRED, example = "清凉丝滑不出汗")
     @ExcelProperty("关键字")
     @ExcelProperty("关键字")
     private String keyword;
     private String keyword;

+ 5 - 1
citu-module-mall/citu-module-product-biz/src/main/java/com/citu/module/product/controller/admin/spu/vo/ProductSpuSaveReqVO.java

@@ -19,6 +19,10 @@ public class ProductSpuSaveReqVO {
     @NotEmpty(message = "商品名称不能为空")
     @NotEmpty(message = "商品名称不能为空")
     private String name;
     private String name;
 
 
+    @Schema(description = "商品类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
+    @NotEmpty(message = "商品类型不能为空")
+    private String type;
+
     @Schema(description = "关键字", requiredMode = Schema.RequiredMode.REQUIRED, example = "清凉丝滑不出汗")
     @Schema(description = "关键字", requiredMode = Schema.RequiredMode.REQUIRED, example = "清凉丝滑不出汗")
     @NotEmpty(message = "商品关键字不能为空")
     @NotEmpty(message = "商品关键字不能为空")
     private String keyword;
     private String keyword;
@@ -60,7 +64,7 @@ public class ProductSpuSaveReqVO {
     // ========== 物流相关字段 =========
     // ========== 物流相关字段 =========
 
 
     @Schema(description = "配送方式数组", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
     @Schema(description = "配送方式数组", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
-    @NotEmpty(message = "配送方式不能为空")
+//    @NotEmpty(message = "配送方式不能为空")
     private List<Integer> deliveryTypes;
     private List<Integer> deliveryTypes;
 
 
     @Schema(description = "物流配置模板编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "111")
     @Schema(description = "物流配置模板编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "111")

+ 3 - 0
citu-module-mall/citu-module-product-biz/src/main/java/com/citu/module/product/controller/admin/spu/vo/ProductSpuSimpleRespVO.java

@@ -15,6 +15,9 @@ public class ProductSpuSimpleRespVO {
     @Schema(description = "商品名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "清凉小短袖")
     @Schema(description = "商品名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "清凉小短袖")
     private String name;
     private String name;
 
 
+    @Schema(description = "商品类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
+    private String type;
+
     @Schema(description = "商品价格,单位使用:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "1999")
     @Schema(description = "商品价格,单位使用:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "1999")
     private Integer price;
     private Integer price;
 
 

+ 3 - 0
citu-module-mall/citu-module-product-biz/src/main/java/com/citu/module/product/controller/app/spu/vo/AppProductSpuDetailRespVO.java

@@ -18,6 +18,9 @@ public class AppProductSpuDetailRespVO {
     @Schema(description = "商品名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道")
     @Schema(description = "商品名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道")
     private String name;
     private String name;
 
 
+    @Schema(description = "商品类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
+    private String type;
+
     @Schema(description = "商品简介", requiredMode = Schema.RequiredMode.REQUIRED, example = "我是一个快乐简介")
     @Schema(description = "商品简介", requiredMode = Schema.RequiredMode.REQUIRED, example = "我是一个快乐简介")
     private String introduction;
     private String introduction;
 
 

+ 9 - 0
citu-module-mall/citu-module-product-biz/src/main/java/com/citu/module/product/controller/app/spu/vo/AppProductSpuRespVO.java

@@ -15,6 +15,9 @@ public class AppProductSpuRespVO {
     @Schema(description = "商品名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道")
     @Schema(description = "商品名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道")
     private String name;
     private String name;
 
 
+    @Schema(description = "商品类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
+    private String type;
+
     @Schema(description = "商品简介", requiredMode = Schema.RequiredMode.REQUIRED, example = "清凉小短袖简介")
     @Schema(description = "商品简介", requiredMode = Schema.RequiredMode.REQUIRED, example = "清凉小短袖简介")
     private String introduction;
     private String introduction;
 
 
@@ -48,4 +51,10 @@ public class AppProductSpuRespVO {
     @Schema(description = "商品销量", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
     @Schema(description = "商品销量", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
     private Integer salesCount;
     private Integer salesCount;
 
 
+    // ========== 物流相关字段 =========
+
+    @Schema(description = "配送方式数组", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+    private List<Integer> deliveryTypes;
+
+
 }
 }

+ 7 - 0
citu-module-mall/citu-module-product-biz/src/main/java/com/citu/module/product/dal/dataobject/spu/ProductSpuDO.java

@@ -11,6 +11,7 @@ import com.baomidou.mybatisplus.annotation.TableField;
 import com.baomidou.mybatisplus.annotation.TableId;
 import com.baomidou.mybatisplus.annotation.TableId;
 import com.baomidou.mybatisplus.annotation.TableName;
 import com.baomidou.mybatisplus.annotation.TableName;
 import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
 import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
+import com.citu.module.product.enums.spu.ProductSpuTypeEnum;
 import lombok.*;
 import lombok.*;
 
 
 import java.util.List;
 import java.util.List;
@@ -42,6 +43,12 @@ public class ProductSpuDO extends BaseDO {
      * 商品名称
      * 商品名称
      */
      */
     private String name;
     private String name;
+    /**
+     * 商品类型
+     *
+     * 枚举 {@link ProductSpuTypeEnum}
+     */
+    private String type;
     /**
     /**
      * 关键字
      * 关键字
      */
      */

+ 1 - 0
citu-module-mall/citu-module-product-biz/src/main/java/com/citu/module/product/dal/mysql/spu/ProductSpuMapper.java

@@ -28,6 +28,7 @@ public interface ProductSpuMapper extends BaseMapperX<ProductSpuDO> {
         Integer tabType = reqVO.getTabType();
         Integer tabType = reqVO.getTabType();
         LambdaQueryWrapperX<ProductSpuDO> queryWrapper = new LambdaQueryWrapperX<ProductSpuDO>()
         LambdaQueryWrapperX<ProductSpuDO> queryWrapper = new LambdaQueryWrapperX<ProductSpuDO>()
                 .likeIfPresent(ProductSpuDO::getName, reqVO.getName())
                 .likeIfPresent(ProductSpuDO::getName, reqVO.getName())
+                .eqIfPresent(ProductSpuDO::getType, reqVO.getType())
                 .eqIfPresent(ProductSpuDO::getCategoryId, reqVO.getCategoryId())
                 .eqIfPresent(ProductSpuDO::getCategoryId, reqVO.getCategoryId())
                 .betweenIfPresent(ProductSpuDO::getCreateTime, reqVO.getCreateTime())
                 .betweenIfPresent(ProductSpuDO::getCreateTime, reqVO.getCreateTime())
                 .orderByDesc(ProductSpuDO::getSort);
                 .orderByDesc(ProductSpuDO::getSort);

+ 6 - 4
citu-module-mall/citu-module-product-biz/src/main/java/com/citu/module/product/service/spu/ProductSpuServiceImpl.java

@@ -78,7 +78,7 @@ public class ProductSpuServiceImpl implements ProductSpuService {
     @Transactional(rollbackFor = Exception.class)
     @Transactional(rollbackFor = Exception.class)
     public void updateSpu(ProductSpuSaveReqVO updateReqVO) {
     public void updateSpu(ProductSpuSaveReqVO updateReqVO) {
         // 校验 SPU 是否存在
         // 校验 SPU 是否存在
-        validateSpuExists(updateReqVO.getId());
+        ProductSpuDO spu = validateSpuExists(updateReqVO.getId());
         // 校验分类、品牌
         // 校验分类、品牌
         validateCategory(updateReqVO.getCategoryId());
         validateCategory(updateReqVO.getCategoryId());
         brandService.validateProductBrand(updateReqVO.getBrandId());
         brandService.validateProductBrand(updateReqVO.getBrandId());
@@ -87,7 +87,7 @@ public class ProductSpuServiceImpl implements ProductSpuService {
         productSkuService.validateSkuList(skuSaveReqList, updateReqVO.getSpecType());
         productSkuService.validateSkuList(skuSaveReqList, updateReqVO.getSpecType());
 
 
         // 更新 SPU
         // 更新 SPU
-        ProductSpuDO updateObj = BeanUtils.toBean(updateReqVO, ProductSpuDO.class);
+        ProductSpuDO updateObj = BeanUtils.toBean(updateReqVO, ProductSpuDO.class).setStatus(spu.getStatus());
         initSpuFromSkus(updateObj, skuSaveReqList);
         initSpuFromSkus(updateObj, skuSaveReqList);
         productSpuMapper.updateById(updateObj);
         productSpuMapper.updateById(updateObj);
         // 批量更新 SKU
         // 批量更新 SKU
@@ -176,10 +176,12 @@ public class ProductSpuServiceImpl implements ProductSpuService {
         productSkuService.deleteSkuBySpuId(id);
         productSkuService.deleteSkuBySpuId(id);
     }
     }
 
 
-    private void validateSpuExists(Long id) {
-        if (productSpuMapper.selectById(id) == null) {
+    private ProductSpuDO validateSpuExists(Long id) {
+        ProductSpuDO spuDO = productSpuMapper.selectById(id);
+        if (spuDO == null) {
             throw exception(SPU_NOT_EXISTS);
             throw exception(SPU_NOT_EXISTS);
         }
         }
+        return spuDO;
     }
     }
 
 
     @Override
     @Override

+ 0 - 6
citu-module-mall/citu-module-promotion-biz/src/main/java/com/citu/module/promotion/dal/mysql/discount/DiscountProductMapper.java

@@ -26,12 +26,6 @@ public interface DiscountProductMapper extends BaseMapperX<DiscountProductDO> {
         return selectList(DiscountProductDO::getActivityId, activityIds);
         return selectList(DiscountProductDO::getActivityId, activityIds);
     }
     }
 
 
-    default List<DiscountProductDO> selectListBySpuIdsAndStatus(Collection<Long> spuIds, Integer status) {
-        return selectList(new LambdaQueryWrapperX<DiscountProductDO>()
-                .in(DiscountProductDO::getSpuId, spuIds)
-                .eq(DiscountProductDO::getActivityStatus, status));
-    }
-
     default void updateByActivityId(DiscountProductDO discountProductDO) {
     default void updateByActivityId(DiscountProductDO discountProductDO) {
         update(discountProductDO, new LambdaUpdateWrapper<DiscountProductDO>()
         update(discountProductDO, new LambdaUpdateWrapper<DiscountProductDO>()
                 .eq(DiscountProductDO::getActivityId, discountProductDO.getActivityId()));
                 .eq(DiscountProductDO::getActivityId, discountProductDO.getActivityId()));

+ 2 - 2
citu-module-mall/citu-module-promotion-biz/src/main/java/com/citu/module/promotion/service/coupon/CouponServiceImpl.java

@@ -152,7 +152,7 @@ public class CouponServiceImpl implements CouponService {
                     findAndThen(userCouponIdsMap, userId, couponIds::addAll);
                     findAndThen(userCouponIdsMap, userId, couponIds::addAll);
                 }
                 }
             } catch (Exception e) {
             } catch (Exception e) {
-                log.error("[takeCouponsByAdmin][coupon({}) 优惠券发放失败]", entry, e);
+                log.error("[takeCouponsByAdmin][coupon({}) 优惠券发放失败 userId({})]", entry, userId, e);
             }
             }
         }
         }
         return couponIds;
         return couponIds;
@@ -270,7 +270,7 @@ public class CouponServiceImpl implements CouponService {
         }
         }
         // 校验剩余数量
         // 校验剩余数量
         if (ObjUtil.notEqual(couponTemplate.getTakeLimitCount(), CouponTemplateDO.TIME_LIMIT_COUNT_MAX) // 非不限制
         if (ObjUtil.notEqual(couponTemplate.getTakeLimitCount(), CouponTemplateDO.TIME_LIMIT_COUNT_MAX) // 非不限制
-            && couponTemplate.getTakeCount() + userIds.size() > couponTemplate.getTotalCount()) {
+                && couponTemplate.getTakeCount() + userIds.size() > couponTemplate.getTotalCount()) {
             throw exception(COUPON_TEMPLATE_NOT_ENOUGH);
             throw exception(COUPON_TEMPLATE_NOT_ENOUGH);
         }
         }
         // 校验"固定日期"的有效期类型是否过期
         // 校验"固定日期"的有效期类型是否过期

+ 6 - 0
citu-module-mall/citu-module-promotion-biz/src/main/java/com/citu/module/promotion/service/discount/DiscountActivityServiceImpl.java

@@ -220,11 +220,17 @@ public class DiscountActivityServiceImpl implements DiscountActivityService {
 
 
     @Override
     @Override
     public List<DiscountProductDO> getDiscountProductsByActivityId(Collection<Long> activityIds) {
     public List<DiscountProductDO> getDiscountProductsByActivityId(Collection<Long> activityIds) {
+        if (CollUtil.isEmpty(activityIds)) {
+            return CollUtil.newArrayList();
+        }
         return discountProductMapper.selectList(DiscountProductDO::getActivityId, activityIds);
         return discountProductMapper.selectList(DiscountProductDO::getActivityId, activityIds);
     }
     }
 
 
     @Override
     @Override
     public List<DiscountProductDO> getMatchDiscountProductListBySkuIds(Collection<Long> skuIds) {
     public List<DiscountProductDO> getMatchDiscountProductListBySkuIds(Collection<Long> skuIds) {
+        if (CollUtil.isEmpty(skuIds)) {
+            return CollUtil.newArrayList();
+        }
         return discountProductMapper.selectListBySkuIdsAndStatusAndNow(skuIds, CommonStatusEnum.ENABLE.getStatus());
         return discountProductMapper.selectListBySkuIdsAndStatusAndNow(skuIds, CommonStatusEnum.ENABLE.getStatus());
     }
     }
 
 

+ 1 - 0
citu-module-mall/citu-module-trade-api/src/main/java/com/citu/module/trade/enums/ErrorCodeConstants.java

@@ -93,6 +93,7 @@ public interface ErrorCodeConstants {
     ErrorCode BROKERAGE_BIND_OVERRIDE = new ErrorCode(1_011_007_006, "已绑定了推广人");
     ErrorCode BROKERAGE_BIND_OVERRIDE = new ErrorCode(1_011_007_006, "已绑定了推广人");
     ErrorCode BROKERAGE_BIND_LOOP = new ErrorCode(1_011_007_007, "下级不能绑定自己的上级");
     ErrorCode BROKERAGE_BIND_LOOP = new ErrorCode(1_011_007_007, "下级不能绑定自己的上级");
     ErrorCode BROKERAGE_USER_LEVEL_NOT_SUPPORT = new ErrorCode(1_011_007_008, "目前只支持 level 小于等于 2");
     ErrorCode BROKERAGE_USER_LEVEL_NOT_SUPPORT = new ErrorCode(1_011_007_008, "目前只支持 level 小于等于 2");
+    ErrorCode BROKERAGE_CREATE_USER_EXISTS = new ErrorCode(1_011_007_009, "分销用户已存在");
 
 
     // ========== 分销提现 模块 1-011-008-000 ==========
     // ========== 分销提现 模块 1-011-008-000 ==========
     ErrorCode BROKERAGE_WITHDRAW_NOT_EXISTS = new ErrorCode(1_011_008_000, "佣金提现记录不存在");
     ErrorCode BROKERAGE_WITHDRAW_NOT_EXISTS = new ErrorCode(1_011_008_000, "佣金提现记录不存在");

+ 7 - 0
citu-module-mall/citu-module-trade-biz/src/main/java/com/citu/module/trade/controller/admin/brokerage/BrokerageUserController.java

@@ -47,6 +47,13 @@ public class BrokerageUserController {
     @Resource
     @Resource
     private MemberUserApi memberUserApi;
     private MemberUserApi memberUserApi;
 
 
+    @PostMapping("/create")
+    @Operation(summary = "创建分销用户")
+    @PreAuthorize("@ss.hasPermission('trade:brokerage-user:create')")
+    public CommonResult<Long> createBrokerageUser(@Valid @RequestBody BrokerageUserCreateReqVO createReqVO) {
+        return success(brokerageUserService.createBrokerageUser(createReqVO));
+    }
+
     @PutMapping("/update-bind-user")
     @PutMapping("/update-bind-user")
     @Operation(summary = "修改推广员")
     @Operation(summary = "修改推广员")
     @PreAuthorize("@ss.hasPermission('trade:brokerage-user:update-bind-user')")
     @PreAuthorize("@ss.hasPermission('trade:brokerage-user:update-bind-user')")

+ 19 - 0
citu-module-mall/citu-module-trade-biz/src/main/java/com/citu/module/trade/controller/admin/brokerage/vo/user/BrokerageUserCreateReqVO.java

@@ -0,0 +1,19 @@
+package com.citu.module.trade.controller.admin.brokerage.vo.user;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import javax.validation.constraints.NotNull;
+
+@Schema(description = "管理后台 - 分销用户创建 Request VO")
+@Data
+public class BrokerageUserCreateReqVO {
+
+    @Schema(description = "分销用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+    @NotNull(message = "分销用户编号不能为空")
+    private Long userId;
+
+    @Schema(description = "推广员编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "4587")
+    private Long bindUserId;
+
+}

+ 1 - 1
citu-module-mall/citu-module-trade-biz/src/main/java/com/citu/module/trade/controller/app/aftersale/AppAfterSaleLogController.java

@@ -20,7 +20,7 @@ import java.util.List;
 
 
 import static com.citu.framework.common.pojo.CommonResult.success;
 import static com.citu.framework.common.pojo.CommonResult.success;
 
 
-@Tag(name = "管理后台 - 售后日志")
+@Tag(name = "用户 App - 售后日志")
 @RestController
 @RestController
 @RequestMapping("/trade/after-sale-log")
 @RequestMapping("/trade/after-sale-log")
 @Validated
 @Validated

+ 3 - 0
citu-module-mall/citu-module-trade-biz/src/main/java/com/citu/module/trade/convert/brokerage/BrokerageUserConvert.java

@@ -59,6 +59,9 @@ public interface BrokerageUserConvert {
     }
     }
 
 
     default BrokerageUserRespVO copyTo(MemberUserRespDTO source, BrokerageUserRespVO target) {
     default BrokerageUserRespVO copyTo(MemberUserRespDTO source, BrokerageUserRespVO target) {
+        if (target == null) {
+            return null;
+        }
         Optional.ofNullable(source).ifPresent(
         Optional.ofNullable(source).ifPresent(
                 user -> target.setNickname(user.getNickname()).setAvatar(user.getAvatar()));
                 user -> target.setNickname(user.getNickname()).setAvatar(user.getAvatar()));
         return target;
         return target;

+ 1 - 1
citu-module-mall/citu-module-trade-biz/src/main/java/com/citu/module/trade/dal/dataobject/order/TradeOrderDO.java

@@ -27,7 +27,7 @@ import java.util.Map;
  *
  *
  * @author 芋道源码
  * @author 芋道源码
  */
  */
-@TableName("trade_order")
+@TableName(value = "trade_order", autoResultMap = true)
 @KeySequence("trade_order_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
 @KeySequence("trade_order_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
 @Data
 @Data
 @EqualsAndHashCode(callSuper = true)
 @EqualsAndHashCode(callSuper = true)

+ 1 - 1
citu-module-mall/citu-module-trade-biz/src/main/java/com/citu/module/trade/service/brokerage/BrokerageRecordServiceImpl.java

@@ -79,7 +79,7 @@ public class BrokerageRecordServiceImpl implements BrokerageRecordService {
         TradeConfigDO memberConfig = tradeConfigService.getTradeConfig();
         TradeConfigDO memberConfig = tradeConfigService.getTradeConfig();
         // 0 未启用分销功能
         // 0 未启用分销功能
         if (memberConfig == null || !BooleanUtil.isTrue(memberConfig.getBrokerageEnabled())) {
         if (memberConfig == null || !BooleanUtil.isTrue(memberConfig.getBrokerageEnabled())) {
-            log.warn("[addBrokerage][增加佣金失败:brokerageEnabled 未配置,userId({})", userId);
+            log.error("[addBrokerage][增加佣金失败:brokerageEnabled 未配置,userId({}) bizType({}) list({})", userId, bizType, list);
             return;
             return;
         }
         }
 
 

+ 10 - 0
citu-module-mall/citu-module-trade-biz/src/main/java/com/citu/module/trade/service/brokerage/BrokerageUserService.java

@@ -1,6 +1,7 @@
 package com.citu.module.trade.service.brokerage;
 package com.citu.module.trade.service.brokerage;
 
 
 import com.citu.framework.common.pojo.PageResult;
 import com.citu.framework.common.pojo.PageResult;
+import com.citu.module.trade.controller.admin.brokerage.vo.user.BrokerageUserCreateReqVO;
 import com.citu.module.trade.controller.admin.brokerage.vo.user.BrokerageUserPageReqVO;
 import com.citu.module.trade.controller.admin.brokerage.vo.user.BrokerageUserPageReqVO;
 import com.citu.module.trade.controller.app.brokerage.vo.user.AppBrokerageUserChildSummaryPageReqVO;
 import com.citu.module.trade.controller.app.brokerage.vo.user.AppBrokerageUserChildSummaryPageReqVO;
 import com.citu.module.trade.controller.app.brokerage.vo.user.AppBrokerageUserChildSummaryRespVO;
 import com.citu.module.trade.controller.app.brokerage.vo.user.AppBrokerageUserChildSummaryRespVO;
@@ -8,6 +9,7 @@ import com.citu.module.trade.controller.app.brokerage.vo.user.AppBrokerageUserRa
 import com.citu.module.trade.controller.app.brokerage.vo.user.AppBrokerageUserRankPageReqVO;
 import com.citu.module.trade.controller.app.brokerage.vo.user.AppBrokerageUserRankPageReqVO;
 import com.citu.module.trade.dal.dataobject.brokerage.BrokerageUserDO;
 import com.citu.module.trade.dal.dataobject.brokerage.BrokerageUserDO;
 
 
+import javax.validation.Valid;
 import javax.validation.constraints.NotNull;
 import javax.validation.constraints.NotNull;
 
 
 /**
 /**
@@ -108,6 +110,14 @@ public interface BrokerageUserService {
      */
      */
     boolean bindBrokerageUser(@NotNull Long userId, @NotNull Long bindUserId);
     boolean bindBrokerageUser(@NotNull Long userId, @NotNull Long bindUserId);
 
 
+    /**
+     * 【管理员】创建分销用户
+     *
+     * @param createReqVO 请求
+     * @return 编号
+     */
+    Long createBrokerageUser(@Valid BrokerageUserCreateReqVO createReqVO);
+
     /**
     /**
      * 获取用户是否有分销资格
      * 获取用户是否有分销资格
      *
      *

+ 21 - 1
citu-module-mall/citu-module-trade-biz/src/main/java/com/citu/module/trade/service/brokerage/BrokerageUserServiceImpl.java

@@ -8,9 +8,11 @@ import cn.hutool.core.util.ObjUtil;
 import cn.hutool.core.util.StrUtil;
 import cn.hutool.core.util.StrUtil;
 import com.citu.framework.common.pojo.PageResult;
 import com.citu.framework.common.pojo.PageResult;
 import com.citu.framework.common.util.date.LocalDateTimeUtils;
 import com.citu.framework.common.util.date.LocalDateTimeUtils;
+import com.citu.framework.common.util.object.BeanUtils;
 import com.citu.framework.mybatis.core.util.MyBatisUtils;
 import com.citu.framework.mybatis.core.util.MyBatisUtils;
 import com.citu.module.member.api.user.MemberUserApi;
 import com.citu.module.member.api.user.MemberUserApi;
 import com.citu.module.member.api.user.dto.MemberUserRespDTO;
 import com.citu.module.member.api.user.dto.MemberUserRespDTO;
+import com.citu.module.trade.controller.admin.brokerage.vo.user.BrokerageUserCreateReqVO;
 import com.citu.module.trade.controller.admin.brokerage.vo.user.BrokerageUserPageReqVO;
 import com.citu.module.trade.controller.admin.brokerage.vo.user.BrokerageUserPageReqVO;
 import com.citu.module.trade.controller.app.brokerage.vo.user.AppBrokerageUserChildSummaryPageReqVO;
 import com.citu.module.trade.controller.app.brokerage.vo.user.AppBrokerageUserChildSummaryPageReqVO;
 import com.citu.module.trade.controller.app.brokerage.vo.user.AppBrokerageUserChildSummaryRespVO;
 import com.citu.module.trade.controller.app.brokerage.vo.user.AppBrokerageUserChildSummaryRespVO;
@@ -27,6 +29,7 @@ import com.citu.module.trade.enums.brokerage.BrokerageRecordStatusEnum;
 import com.citu.module.trade.service.config.TradeConfigService;
 import com.citu.module.trade.service.config.TradeConfigService;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import org.springframework.stereotype.Service;
 import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
 import org.springframework.validation.annotation.Validated;
 import org.springframework.validation.annotation.Validated;
 
 
 import javax.annotation.Resource;
 import javax.annotation.Resource;
@@ -110,7 +113,6 @@ public class BrokerageUserServiceImpl implements BrokerageUserService {
         if (brokerageUserDO == null) {
         if (brokerageUserDO == null) {
             throw exception(BROKERAGE_USER_NOT_EXISTS);
             throw exception(BROKERAGE_USER_NOT_EXISTS);
         }
         }
-
         return brokerageUserDO;
         return brokerageUserDO;
     }
     }
 
 
@@ -202,6 +204,24 @@ public class BrokerageUserServiceImpl implements BrokerageUserService {
         return true;
         return true;
     }
     }
 
 
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Long createBrokerageUser(BrokerageUserCreateReqVO createReqVO) {
+        // 1.1 校验分销用户是否已存在
+        BrokerageUserDO brokerageUser = brokerageUserMapper.selectById(createReqVO.getUserId());
+        if (brokerageUser != null) {
+            throw exception(BROKERAGE_CREATE_USER_EXISTS);
+        }
+        // 1.2 校验是否能绑定用户
+        brokerageUser = BeanUtils.toBean(createReqVO, BrokerageUserDO.class).setId(createReqVO.getUserId())
+                .setBrokerageTime(LocalDateTime.now());
+        validateCanBindUser(brokerageUser, createReqVO.getBindUserId());
+
+        // 2. 创建分销人
+        brokerageUserMapper.insert(brokerageUser);
+        return brokerageUser.getId();
+    }
+
     /**
     /**
      * 补全绑定用户的字段
      * 补全绑定用户的字段
      *
      *

+ 2 - 2
citu-module-mall/citu-module-trade-biz/src/main/java/com/citu/module/trade/service/cart/CartServiceImpl.java

@@ -55,7 +55,7 @@ public class CartServiceImpl implements CartService {
             cartMapper.updateById(new CartDO().setId(cart.getId()).setSelected(true)
             cartMapper.updateById(new CartDO().setId(cart.getId()).setSelected(true)
                     .setCount(cart.getCount() + count));
                     .setCount(cart.getCount() + count));
             return cart.getId();
             return cart.getId();
-        // 情况二:不存在,则进行插入
+            // 情况二:不存在,则进行插入
         } else {
         } else {
             cart = new CartDO().setUserId(userId).setSelected(true)
             cart = new CartDO().setUserId(userId).setSelected(true)
                     .setSpuId(sku.getSpuId()).setSkuId(sku.getId()).setCount(count);
                     .setSpuId(sku.getSpuId()).setSkuId(sku.getId()).setCount(count);
@@ -121,7 +121,7 @@ public class CartServiceImpl implements CartService {
         }
         }
 
 
         // 批量标记删除
         // 批量标记删除
-        cartMapper.deleteBatchIds(ids);
+        cartMapper.deleteByIds(convertSet(carts, CartDO::getId));
     }
     }
 
 
     @Override
     @Override

+ 6 - 5
citu-module-mall/citu-module-trade-biz/src/main/java/com/citu/module/trade/service/order/TradeOrderUpdateServiceImpl.java

@@ -329,7 +329,7 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
     /**
     /**
      * 校验支付订单的合法性
      * 校验支付订单的合法性
      *
      *
-     * @param order 交易订单
+     * @param order      交易订单
      * @param payOrderId 支付订单编号
      * @param payOrderId 支付订单编号
      * @return 支付订单
      * @return 支付订单
      */
      */
@@ -393,7 +393,7 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
 
 
         // 3. 记录订单日志
         // 3. 记录订单日志
         TradeOrderLogUtils.setOrderInfo(order.getId(), order.getStatus(), TradeOrderStatusEnum.DELIVERED.getStatus(),
         TradeOrderLogUtils.setOrderInfo(order.getId(), order.getStatus(), TradeOrderStatusEnum.DELIVERED.getStatus(),
-                MapUtil.<String, Object>builder().put("expressName", express != null ? express.getName() : "")
+                MapUtil.<String, Object>builder().put("deliveryName", express != null ? express.getName() : "")
                         .put("logisticsNo", express != null ? deliveryReqVO.getLogisticsNo() : "").build());
                         .put("logisticsNo", express != null ? deliveryReqVO.getLogisticsNo() : "").build());
 
 
         // 4.1 发送站内信
         // 4.1 发送站内信
@@ -688,8 +688,9 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
         List<TradeOrderItemDO> updateItems = new ArrayList<>();
         List<TradeOrderItemDO> updateItems = new ArrayList<>();
         for (int i = 0; i < orderOrderItems.size(); i++) {
         for (int i = 0; i < orderOrderItems.size(); i++) {
             TradeOrderItemDO item = orderOrderItems.get(i);
             TradeOrderItemDO item = orderOrderItems.get(i);
-            updateItems.add(new TradeOrderItemDO().setId(item.getId()).setAdjustPrice(item.getAdjustPrice() + dividePrices.get(i))
-                    .setPayPrice((item.getPayPrice() - item.getAdjustPrice()) + dividePrices.get(i)));
+            updateItems.add(new TradeOrderItemDO().setId(item.getId())
+                    .setAdjustPrice(item.getAdjustPrice() + dividePrices.get(i))
+                    .setPayPrice(item.getPayPrice() + dividePrices.get(i)));
         }
         }
         tradeOrderItemMapper.updateBatch(updateItems);
         tradeOrderItemMapper.updateBatch(updateItems);
 
 
@@ -747,7 +748,7 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
         }
         }
         DeliveryPickUpStoreDO deliveryPickUpStore = pickUpStoreService.getDeliveryPickUpStore(order.getPickUpStoreId());
         DeliveryPickUpStoreDO deliveryPickUpStore = pickUpStoreService.getDeliveryPickUpStore(order.getPickUpStoreId());
         if (deliveryPickUpStore == null
         if (deliveryPickUpStore == null
-            || !CollUtil.contains(deliveryPickUpStore.getVerifyUserIds(), userId)) {
+                || !CollUtil.contains(deliveryPickUpStore.getVerifyUserIds(), userId)) {
             throw exception(ORDER_PICK_UP_FAIL_NOT_VERIFY_USER);
             throw exception(ORDER_PICK_UP_FAIL_NOT_VERIFY_USER);
         }
         }
 
 

+ 10 - 4
citu-module-mall/citu-module-trade-biz/src/main/java/com/citu/module/trade/service/order/handler/TradeCouponOrderHandler.java

@@ -7,6 +7,7 @@ import com.citu.module.trade.dal.dataobject.order.TradeOrderDO;
 import com.citu.module.trade.dal.dataobject.order.TradeOrderItemDO;
 import com.citu.module.trade.dal.dataobject.order.TradeOrderItemDO;
 import com.citu.module.trade.service.order.TradeOrderQueryService;
 import com.citu.module.trade.service.order.TradeOrderQueryService;
 import com.citu.module.trade.service.order.TradeOrderUpdateService;
 import com.citu.module.trade.service.order.TradeOrderUpdateService;
+import lombok.extern.slf4j.Slf4j;
 import org.springframework.context.annotation.Lazy;
 import org.springframework.context.annotation.Lazy;
 import org.springframework.stereotype.Component;
 import org.springframework.stereotype.Component;
 
 
@@ -19,6 +20,7 @@ import java.util.List;
  * @author 芋道源码
  * @author 芋道源码
  */
  */
 @Component
 @Component
+@Slf4j
 public class TradeCouponOrderHandler implements TradeOrderHandler {
 public class TradeCouponOrderHandler implements TradeOrderHandler {
 
 
     @Resource
     @Resource
@@ -46,11 +48,15 @@ public class TradeCouponOrderHandler implements TradeOrderHandler {
             return;
             return;
         }
         }
         // 赠送优惠券
         // 赠送优惠券
-        List<Long> couponIds = couponApi.takeCouponsByAdmin(order.getGiveCouponTemplateCounts(), order.getUserId()).getCheckedData();
-        if (CollUtil.isEmpty(couponIds)) {
-            return;
+        try {
+            List<Long> couponIds = couponApi.takeCouponsByAdmin(order.getGiveCouponTemplateCounts(), order.getUserId()).getCheckedData();
+            if (CollUtil.isEmpty(couponIds)) {
+                return;
+            }
+            orderUpdateService.updateOrderGiveCouponIds(order.getUserId(), order.getId(), couponIds);
+        } catch (Exception e) {
+            log.error("[afterPayOrder][order({}) 赠送优惠券({})失败,需要手工补偿]", order.getId(), order.getGiveCouponTemplateCounts(), e);
         }
         }
-        orderUpdateService.updateOrderGiveCouponIds(order.getUserId(), order.getId(), couponIds);
     }
     }
 
 
     @Override
     @Override

+ 8 - 4
citu-module-mall/citu-module-trade-biz/src/main/java/com/citu/module/trade/service/price/calculator/TradeDeliveryPriceCalculator.java

@@ -122,9 +122,13 @@ public class TradeDeliveryPriceCalculator implements TradePriceCalculator {
      */
      */
     private boolean isGlobalExpressFree(TradePriceCalculateRespBO result) {
     private boolean isGlobalExpressFree(TradePriceCalculateRespBO result) {
         TradeConfigDO config = tradeConfigService.getTradeConfig();
         TradeConfigDO config = tradeConfigService.getTradeConfig();
-        return config == null
-                || Boolean.TRUE.equals(config.getDeliveryExpressFreeEnabled()) // 开启包邮
-                || result.getPrice().getPayPrice() >= config.getDeliveryExpressFreePrice(); // 满足包邮的价格
+        // 情况一:交易中心配置不存在默认不包邮
+        if (config == null) {
+            return false;
+        }
+        // 情况二:开启了全局包邮 && 满足包邮金额
+        return Boolean.TRUE.equals(config.getDeliveryExpressFreeEnabled()) &&
+                result.getPrice().getPayPrice() >= config.getDeliveryExpressFreePrice();
     }
     }
 
 
     private void calculateDeliveryPrice(List<OrderItem> selectedSkus,
     private void calculateDeliveryPrice(List<OrderItem> selectedSkus,
@@ -180,7 +184,7 @@ public class TradeDeliveryPriceCalculator implements TradePriceCalculator {
         // 2. 分摊快递费用到 SKU. 退费的时候,可能按照 SKU 考虑退费金额
         // 2. 分摊快递费用到 SKU. 退费的时候,可能按照 SKU 考虑退费金额
         int remainPrice = deliveryPrice;
         int remainPrice = deliveryPrice;
         for (int i = 0; i < orderItems.size(); i++) {
         for (int i = 0; i < orderItems.size(); i++) {
-            OrderItem item = orderItems.get(i);
+            TradePriceCalculateRespBO.OrderItem item = orderItems.get(i);
             int partPrice;
             int partPrice;
             double chargeValue = getChargeValue(item, chargeMode);
             double chargeValue = getChargeValue(item, chargeMode);
             if (i < orderItems.size() - 1) { // 减一的原因,是因为拆分时,如果按照比例,可能会出现.所以最后一个,使用反减
             if (i < orderItems.size() - 1) { // 减一的原因,是因为拆分时,如果按照比例,可能会出现.所以最后一个,使用反减

+ 1 - 1
citu-module-member/citu-module-member-biz/src/main/java/com/citu/module/member/controller/app/signin/AppMemberSignInRecordController.java

@@ -22,7 +22,7 @@ import javax.annotation.Resource;
 import static com.citu.framework.common.pojo.CommonResult.success;
 import static com.citu.framework.common.pojo.CommonResult.success;
 import static com.citu.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
 import static com.citu.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
 
 
-@Tag(name = "管理后台 - 签到记录")
+@Tag(name = "用户 App - 签到记录")
 @RestController
 @RestController
 @RequestMapping("/member/sign-in/record")
 @RequestMapping("/member/sign-in/record")
 @Validated
 @Validated

+ 3 - 1
citu-module-member/citu-module-member-biz/src/main/java/com/citu/module/member/service/point/MemberPointRecordServiceImpl.java

@@ -75,7 +75,9 @@ public class MemberPointRecordServiceImpl implements MemberPointRecordService {
         Integer userPoint = ObjectUtil.defaultIfNull(user.getPoint(), 0);
         Integer userPoint = ObjectUtil.defaultIfNull(user.getPoint(), 0);
         int totalPoint = userPoint + point; // 用户变动后的积分
         int totalPoint = userPoint + point; // 用户变动后的积分
         if (totalPoint < 0) {
         if (totalPoint < 0) {
-            throw exception(USER_POINT_NOT_ENOUGH);
+            log.error("[createPointRecord][userId({}) point({}) bizType({}) bizId({}) {}]", userId, point, bizType, bizId,
+                    USER_POINT_NOT_ENOUGH);
+            return;
         }
         }
 
 
         // 2. 更新用户积分
         // 2. 更新用户积分

+ 1 - 0
citu-module-system/citu-module-system-api/src/main/java/com/citu/module/system/enums/ErrorCodeConstants.java

@@ -115,6 +115,7 @@ public interface ErrorCodeConstants {
     ErrorCode TENANT_PACKAGE_NOT_EXISTS = new ErrorCode(1_002_016_000, "租户套餐不存在");
     ErrorCode TENANT_PACKAGE_NOT_EXISTS = new ErrorCode(1_002_016_000, "租户套餐不存在");
     ErrorCode TENANT_PACKAGE_USED = new ErrorCode(1_002_016_001, "租户正在使用该套餐,请给租户重新设置套餐后再尝试删除");
     ErrorCode TENANT_PACKAGE_USED = new ErrorCode(1_002_016_001, "租户正在使用该套餐,请给租户重新设置套餐后再尝试删除");
     ErrorCode TENANT_PACKAGE_DISABLE = new ErrorCode(1_002_016_002, "名字为【{}】的租户套餐已被禁用");
     ErrorCode TENANT_PACKAGE_DISABLE = new ErrorCode(1_002_016_002, "名字为【{}】的租户套餐已被禁用");
+    ErrorCode TENANT_PACKAGE_NAME_DUPLICATE = new ErrorCode(1_002_016_003, "已经存在该名字的租户套餐");
 
 
     // ========== 错误码模块 1-002-017-000 ==========
     // ========== 错误码模块 1-002-017-000 ==========
     ErrorCode ERROR_CODE_NOT_EXISTS = new ErrorCode(1_002_017_000, "错误码不存在");
     ErrorCode ERROR_CODE_NOT_EXISTS = new ErrorCode(1_002_017_000, "错误码不存在");

+ 1 - 1
citu-module-system/citu-module-system-biz/src/main/java/com/citu/module/system/controller/admin/user/vo/user/UserSaveReqVO.java

@@ -23,7 +23,7 @@ public class UserSaveReqVO {
 
 
     @Schema(description = "用户账号", requiredMode = Schema.RequiredMode.REQUIRED, example = "citu")
     @Schema(description = "用户账号", requiredMode = Schema.RequiredMode.REQUIRED, example = "citu")
     @NotBlank(message = "用户账号不能为空")
     @NotBlank(message = "用户账号不能为空")
-    @Pattern(regexp = "^[a-zA-Z0-9]{4,30}$", message = "用户账号由 数字、字母 组成")
+    @Pattern(regexp = "^[a-zA-Z0-9]$", message = "用户账号由 数字、字母 组成")
     @Size(min = 4, max = 30, message = "用户账号长度为 4-30 个字符")
     @Size(min = 4, max = 30, message = "用户账号长度为 4-30 个字符")
     @DiffLogField(name = "用户账号")
     @DiffLogField(name = "用户账号")
     private String username;
     private String username;

+ 4 - 0
citu-module-system/citu-module-system-biz/src/main/java/com/citu/module/system/dal/mysql/tenant/TenantPackageMapper.java

@@ -29,4 +29,8 @@ public interface TenantPackageMapper extends BaseMapperX<TenantPackageDO> {
     default List<TenantPackageDO> selectListByStatus(Integer status) {
     default List<TenantPackageDO> selectListByStatus(Integer status) {
         return selectList(TenantPackageDO::getStatus, status);
         return selectList(TenantPackageDO::getStatus, status);
     }
     }
+
+    default TenantPackageDO selectByName(String name) {
+        return selectOne(TenantPackageDO::getName, name);
+    }
 }
 }

+ 25 - 0
citu-module-system/citu-module-system-biz/src/main/java/com/citu/module/system/service/tenant/TenantPackageServiceImpl.java

@@ -1,6 +1,7 @@
 package com.citu.module.system.service.tenant;
 package com.citu.module.system.service.tenant;
 
 
 import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.StrUtil;
 import com.citu.framework.common.enums.CommonStatusEnum;
 import com.citu.framework.common.enums.CommonStatusEnum;
 import com.citu.framework.common.pojo.PageResult;
 import com.citu.framework.common.pojo.PageResult;
 import com.citu.framework.common.util.object.BeanUtils;
 import com.citu.framework.common.util.object.BeanUtils;
@@ -10,6 +11,7 @@ import com.citu.module.system.dal.dataobject.tenant.TenantDO;
 import com.citu.module.system.dal.dataobject.tenant.TenantPackageDO;
 import com.citu.module.system.dal.dataobject.tenant.TenantPackageDO;
 import com.citu.module.system.dal.mysql.tenant.TenantPackageMapper;
 import com.citu.module.system.dal.mysql.tenant.TenantPackageMapper;
 import com.baomidou.dynamic.datasource.annotation.DSTransactional;
 import com.baomidou.dynamic.datasource.annotation.DSTransactional;
+import com.google.common.annotations.VisibleForTesting;
 import org.springframework.context.annotation.Lazy;
 import org.springframework.context.annotation.Lazy;
 import org.springframework.stereotype.Service;
 import org.springframework.stereotype.Service;
 import org.springframework.validation.annotation.Validated;
 import org.springframework.validation.annotation.Validated;
@@ -38,6 +40,8 @@ public class TenantPackageServiceImpl implements TenantPackageService {
 
 
     @Override
     @Override
     public Long createTenantPackage(TenantPackageSaveReqVO createReqVO) {
     public Long createTenantPackage(TenantPackageSaveReqVO createReqVO) {
+        // 校验套餐名是否重复
+        validateTenantPackageNameUnique(null, createReqVO.getName());
         // 插入
         // 插入
         TenantPackageDO tenantPackage = BeanUtils.toBean(createReqVO, TenantPackageDO.class);
         TenantPackageDO tenantPackage = BeanUtils.toBean(createReqVO, TenantPackageDO.class);
         tenantPackageMapper.insert(tenantPackage);
         tenantPackageMapper.insert(tenantPackage);
@@ -50,6 +54,8 @@ public class TenantPackageServiceImpl implements TenantPackageService {
     public void updateTenantPackage(TenantPackageSaveReqVO updateReqVO) {
     public void updateTenantPackage(TenantPackageSaveReqVO updateReqVO) {
         // 校验存在
         // 校验存在
         TenantPackageDO tenantPackage = validateTenantPackageExists(updateReqVO.getId());
         TenantPackageDO tenantPackage = validateTenantPackageExists(updateReqVO.getId());
+        // 校验套餐名是否重复
+        validateTenantPackageNameUnique(updateReqVO.getId(), updateReqVO.getName());
         // 更新
         // 更新
         TenantPackageDO updateObj = BeanUtils.toBean(updateReqVO, TenantPackageDO.class);
         TenantPackageDO updateObj = BeanUtils.toBean(updateReqVO, TenantPackageDO.class);
         tenantPackageMapper.updateById(updateObj);
         tenantPackageMapper.updateById(updateObj);
@@ -111,4 +117,23 @@ public class TenantPackageServiceImpl implements TenantPackageService {
         return tenantPackageMapper.selectListByStatus(status);
         return tenantPackageMapper.selectListByStatus(status);
     }
     }
 
 
+
+    @VisibleForTesting
+    void validateTenantPackageNameUnique(Long id, String name) {
+        if (StrUtil.isBlank(name)) {
+            return;
+        }
+        TenantPackageDO tenantPackage = tenantPackageMapper.selectByName(name);
+        if (tenantPackage == null) {
+            return;
+        }
+        // 如果 id 为空,说明不用比较是否为相同 id 的用户
+        if (id == null) {
+            throw exception(TENANT_PACKAGE_NAME_DUPLICATE);
+        }
+        if (!tenantPackage.getId().equals(id)) {
+            throw exception(TENANT_PACKAGE_NAME_DUPLICATE);
+        }
+    }
+
 }
 }

+ 0 - 1
menduner/menduner-system-biz/src/main/java/com/citu/module/menduner/system/controller/app/jobhunt/person/AppPersonResumeController.java

@@ -140,7 +140,6 @@ public class AppPersonResumeController {
             reqVO.getWorkExpList().forEach(workExp -> workExpService.saveWorkExp(workExp));
             reqVO.getWorkExpList().forEach(workExp -> workExpService.saveWorkExp(workExp));
         }
         }
         return success(personInfoService.saveSimple(reqVO));
         return success(personInfoService.saveSimple(reqVO));
-
     }
     }
 
 
     @PreAuthenticated
     @PreAuthenticated

+ 1 - 0
menduner/menduner-system-biz/src/main/resources/i18n/messages_zh_CN.properties

@@ -170,6 +170,7 @@
 1_100_019_007=未选择融资阶段
 1_100_019_007=未选择融资阶段
 1_100_019_008=未选择人员规模
 1_100_019_008=未选择人员规模
 1_100_019_009=未填写上班时间
 1_100_019_009=未填写上班时间
+1_100_019_010=企业会员已过期,无法使用权益,请续期
 # ========== 企业工商信息  1_100_020_001 ==========
 # ========== 企业工商信息  1_100_020_001 ==========
 1_100_020_001=企业工商信息不存在
 1_100_020_001=企业工商信息不存在
 1_100_020_002=未填写企业名称
 1_100_020_002=未填写企业名称

+ 2 - 2
pom.xml

@@ -30,7 +30,7 @@
     <url>https://github.com/YunaiV/ruoyi-vue-pro</url>
     <url>https://github.com/YunaiV/ruoyi-vue-pro</url>
 
 
     <properties>
     <properties>
-        <revision>2.3.0-snapshot</revision>
+        <revision>2.4.0-SNAPSHOT</revision>
         <!-- Maven 相关 -->
         <!-- Maven 相关 -->
         <java.version>11</java.version>
         <java.version>11</java.version>
         <maven.compiler.source>${java.version}</maven.compiler.source>
         <maven.compiler.source>${java.version}</maven.compiler.source>
@@ -39,7 +39,7 @@
         <maven-compiler-plugin.version>3.13.0</maven-compiler-plugin.version>
         <maven-compiler-plugin.version>3.13.0</maven-compiler-plugin.version>
         <flatten-maven-plugin.version>1.6.0</flatten-maven-plugin.version>
         <flatten-maven-plugin.version>1.6.0</flatten-maven-plugin.version>
         <!-- 看看咋放到 bom 里 -->
         <!-- 看看咋放到 bom 里 -->
-        <lombok.version>1.18.34</lombok.version>
+        <lombok.version>1.18.36</lombok.version>
         <spring.boot.version>2.7.18</spring.boot.version>
         <spring.boot.version>2.7.18</spring.boot.version>
         <mapstruct.version>1.6.2</mapstruct.version>
         <mapstruct.version>1.6.2</mapstruct.version>
         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>

Some files were not shown because too many files changed in this diff