Просмотр исходного кода

1、增加抽奖相关的逻辑
2、增加企业设置vip接口

rayson 1 год назад
Родитель
Сommit
3fda3d71bc
74 измененных файлов с 3277 добавлено и 56 удалено
  1. 7 2
      citu-framework/citu-spring-boot-starter-protection/src/main/java/com/citu/framework/signature/config/CituApiSignatureAutoConfiguration.java
  2. 5 5
      citu-framework/citu-spring-boot-starter-protection/src/main/java/com/citu/framework/signature/core/aop/ApiSignatureAspect.java
  3. 9 1
      citu-framework/citu-spring-boot-starter-web/src/main/java/com/citu/framework/i18n/config/CituI18nAutoConfiguration.java
  4. 1 1
      citu-framework/citu-spring-boot-starter-web/src/main/java/com/citu/framework/swagger/config/CituSwaggerAutoConfiguration.java
  5. 14 14
      citu-module-infra/citu-module-infra-biz/src/main/resources/codegen/java/service/serviceImpl.vm
  6. 21 0
      citu-module-mall/citu-module-promotion-api/src/main/java/com/citu/module/promotion/enums/ErrorCodeConstants.java
  7. 34 0
      citu-module-mall/citu-module-promotion-api/src/main/java/com/citu/module/promotion/enums/luck/LuckLotteryFactorEnum.java
  8. 23 0
      citu-module-mall/citu-module-promotion-api/src/main/java/com/citu/module/promotion/enums/luck/LuckLotteryTypeEnum.java
  9. 32 0
      citu-module-mall/citu-module-promotion-api/src/main/java/com/citu/module/promotion/enums/luck/LuckPrizeTypeEnum.java
  10. 27 0
      citu-module-mall/citu-module-promotion-api/src/main/java/com/citu/module/promotion/enums/luck/LuckStatusEnum.java
  11. 5 0
      citu-module-mall/citu-module-promotion-biz/pom.xml
  12. 94 0
      citu-module-mall/citu-module-promotion-biz/src/main/java/com/citu/module/promotion/controller/admin/luck/LuckLotteryController.java
  13. 95 0
      citu-module-mall/citu-module-promotion-biz/src/main/java/com/citu/module/promotion/controller/admin/luck/LuckLotteryRecordController.java
  14. 153 0
      citu-module-mall/citu-module-promotion-biz/src/main/java/com/citu/module/promotion/controller/admin/luck/LuckPrizeController.java
  15. 19 0
      citu-module-mall/citu-module-promotion-biz/src/main/java/com/citu/module/promotion/controller/admin/luck/vo/LuckLotteryDetailRespVO.java
  16. 66 0
      citu-module-mall/citu-module-promotion-biz/src/main/java/com/citu/module/promotion/controller/admin/luck/vo/LuckLotteryPageReqVO.java
  17. 116 0
      citu-module-mall/citu-module-promotion-biz/src/main/java/com/citu/module/promotion/controller/admin/luck/vo/LuckLotteryRespVO.java
  18. 98 0
      citu-module-mall/citu-module-promotion-biz/src/main/java/com/citu/module/promotion/controller/admin/luck/vo/LuckLotterySaveReqVO.java
  19. 20 0
      citu-module-mall/citu-module-promotion-biz/src/main/java/com/citu/module/promotion/controller/admin/luck/vo/prize/LuckPrizeDetailRespVO.java
  20. 64 0
      citu-module-mall/citu-module-promotion-biz/src/main/java/com/citu/module/promotion/controller/admin/luck/vo/prize/LuckPrizeImportExcelVO.java
  21. 40 0
      citu-module-mall/citu-module-promotion-biz/src/main/java/com/citu/module/promotion/controller/admin/luck/vo/prize/LuckPrizePageReqVO.java
  22. 81 0
      citu-module-mall/citu-module-promotion-biz/src/main/java/com/citu/module/promotion/controller/admin/luck/vo/prize/LuckPrizeRespVO.java
  23. 72 0
      citu-module-mall/citu-module-promotion-biz/src/main/java/com/citu/module/promotion/controller/admin/luck/vo/prize/LuckPrizeSaveReqVO.java
  24. 29 0
      citu-module-mall/citu-module-promotion-biz/src/main/java/com/citu/module/promotion/controller/admin/luck/vo/record/LuckLotteryRecordDetailRespVO.java
  25. 43 0
      citu-module-mall/citu-module-promotion-biz/src/main/java/com/citu/module/promotion/controller/admin/luck/vo/record/LuckLotteryRecordPageReqVO.java
  26. 68 0
      citu-module-mall/citu-module-promotion-biz/src/main/java/com/citu/module/promotion/controller/admin/luck/vo/record/LuckLotteryRecordRespVO.java
  27. 55 0
      citu-module-mall/citu-module-promotion-biz/src/main/java/com/citu/module/promotion/controller/admin/luck/vo/record/LuckLotteryRecordSaveReqVO.java
  28. 55 0
      citu-module-mall/citu-module-promotion-biz/src/main/java/com/citu/module/promotion/controller/app/luck/AppLuckLotteryController.java
  29. 59 0
      citu-module-mall/citu-module-promotion-biz/src/main/java/com/citu/module/promotion/controller/app/luck/AppLuckLotteryRecordController.java
  30. 22 0
      citu-module-mall/citu-module-promotion-biz/src/main/java/com/citu/module/promotion/convert/luck/LuckLotteryConvert.java
  31. 32 0
      citu-module-mall/citu-module-promotion-biz/src/main/java/com/citu/module/promotion/convert/luck/LuckLotteryRecordConvert.java
  32. 25 0
      citu-module-mall/citu-module-promotion-biz/src/main/java/com/citu/module/promotion/convert/luck/LuckPrizeConvert.java
  33. 131 0
      citu-module-mall/citu-module-promotion-biz/src/main/java/com/citu/module/promotion/dal/dataobject/luck/LuckLotteryDO.java
  34. 80 0
      citu-module-mall/citu-module-promotion-biz/src/main/java/com/citu/module/promotion/dal/dataobject/luck/LuckLotteryRecordDO.java
  35. 86 0
      citu-module-mall/citu-module-promotion-biz/src/main/java/com/citu/module/promotion/dal/dataobject/luck/LuckPrizeDO.java
  36. 38 0
      citu-module-mall/citu-module-promotion-biz/src/main/java/com/citu/module/promotion/dal/dataobject/luck/LuckPrizeExtend.java
  37. 70 0
      citu-module-mall/citu-module-promotion-biz/src/main/java/com/citu/module/promotion/dal/dataobject/luck/LuckPrizeExtendDO.java
  38. 77 0
      citu-module-mall/citu-module-promotion-biz/src/main/java/com/citu/module/promotion/dal/mysql/luck/LuckLotteryMapper.java
  39. 41 0
      citu-module-mall/citu-module-promotion-biz/src/main/java/com/citu/module/promotion/dal/mysql/luck/LuckLotteryRecordMapper.java
  40. 22 0
      citu-module-mall/citu-module-promotion-biz/src/main/java/com/citu/module/promotion/dal/mysql/luck/LuckPrizeExtendMapper.java
  41. 46 0
      citu-module-mall/citu-module-promotion-biz/src/main/java/com/citu/module/promotion/dal/mysql/luck/LuckPrizeMapper.java
  42. 4 0
      citu-module-mall/citu-module-promotion-biz/src/main/java/com/citu/module/promotion/framework/rpc/config/RpcConfiguration.java
  43. 82 0
      citu-module-mall/citu-module-promotion-biz/src/main/java/com/citu/module/promotion/service/luck/LuckLotteryRecordService.java
  44. 198 0
      citu-module-mall/citu-module-promotion-biz/src/main/java/com/citu/module/promotion/service/luck/LuckLotteryRecordServiceImpl.java
  45. 94 0
      citu-module-mall/citu-module-promotion-biz/src/main/java/com/citu/module/promotion/service/luck/LuckLotteryService.java
  46. 143 0
      citu-module-mall/citu-module-promotion-biz/src/main/java/com/citu/module/promotion/service/luck/LuckLotteryServiceImpl.java
  47. 302 0
      citu-module-mall/citu-module-promotion-biz/src/main/java/com/citu/module/promotion/service/luck/LuckPrizeServiceImpl.java
  48. 1 0
      citu-module-mall/citu-module-promotion-biz/src/main/resources/application.yaml
  49. 21 0
      citu-module-mall/citu-module-trade-biz/src/main/java/com/citu/module/trade/service/order/handler/TradeLotteryOrderHandler.java
  50. 2 1
      menduner/menduner-common/src/main/java/com/citu/module/menduner/common/db/CituTransformDataSourceAutoConfiguration.java
  51. 2 6
      menduner/menduner-im-biz/src/main/java/com/citu/module/menduner/im/framework/rpc/config/RpcConfiguration.java
  52. 5 6
      menduner/menduner-im-biz/src/main/java/com/citu/module/menduner/im/service/UserServiceImpl.java
  53. 2 2
      menduner/menduner-reward-biz/src/main/java/com/citu/module/menduner/reward/framework/rpc/config/RpcConfiguration.java
  54. 40 0
      menduner/menduner-system-api/src/main/java/com/citu/module/menduner/system/api/area/MendunerAreaApi.java
  55. 14 1
      menduner/menduner-system-api/src/main/java/com/citu/module/menduner/system/api/user/MendunerUserApi.java
  56. 45 0
      menduner/menduner-system-biz/src/main/java/com/citu/module/menduner/system/api/area/MendunerAreaApiImpl.java
  57. 40 1
      menduner/menduner-system-biz/src/main/java/com/citu/module/menduner/system/api/user/MendunerUserApiImpl.java
  58. 21 0
      menduner/menduner-system-biz/src/main/java/com/citu/module/menduner/system/controller/admin/enterprise/EnterpriseController.java
  59. 9 0
      menduner/menduner-system-biz/src/main/java/com/citu/module/menduner/system/controller/admin/enterprise/EnterprisePackageController.java
  60. 16 0
      menduner/menduner-system-biz/src/main/java/com/citu/module/menduner/system/controller/base/enterprise/vip/EnterpriseVipReqVO.java
  61. 5 0
      menduner/menduner-system-biz/src/main/java/com/citu/module/menduner/system/dal/mysql/area/AreaMapper.java
  62. 7 0
      menduner/menduner-system-biz/src/main/java/com/citu/module/menduner/system/dal/mysql/enterprise/EnterpriseEntitlementMapper.java
  63. 2 2
      menduner/menduner-system-biz/src/main/java/com/citu/module/menduner/system/dal/mysql/enterprise/EnterprisePackageMapper.java
  64. 1 0
      menduner/menduner-system-biz/src/main/java/com/citu/module/menduner/system/dal/mysql/job/JobAdvertisedMapper.java
  65. 0 1
      menduner/menduner-system-biz/src/main/java/com/citu/module/menduner/system/mq/consumer/UserMemberConsumer.java
  66. 5 0
      menduner/menduner-system-biz/src/main/java/com/citu/module/menduner/system/service/area/AreaService.java
  67. 5 0
      menduner/menduner-system-biz/src/main/java/com/citu/module/menduner/system/service/area/AreaServiceImpl.java
  68. 12 1
      menduner/menduner-system-biz/src/main/java/com/citu/module/menduner/system/service/enterprise/EnterpriseService.java
  69. 7 1
      menduner/menduner-system-biz/src/main/java/com/citu/module/menduner/system/service/enterprise/EnterpriseServiceImpl.java
  70. 15 0
      menduner/menduner-system-biz/src/main/java/com/citu/module/menduner/system/service/enterprise/vip/EnterpriseEntitlementService.java
  71. 86 7
      menduner/menduner-system-biz/src/main/java/com/citu/module/menduner/system/service/enterprise/vip/EnterpriseEntitlementServiceImpl.java
  72. 7 0
      menduner/menduner-system-biz/src/main/java/com/citu/module/menduner/system/service/enterprise/vip/EnterprisePackageService.java
  73. 6 1
      menduner/menduner-system-biz/src/main/java/com/citu/module/menduner/system/service/enterprise/vip/EnterprisePackageServiceImpl.java
  74. 3 3
      menduner/menduner-system-biz/src/test/java/com/citu/module/menduner/system/service/userapi/MendunerUserApiTest.java

+ 7 - 2
citu-framework/citu-spring-boot-starter-protection/src/main/java/com/citu/framework/signature/config/CituApiSignatureAutoConfiguration.java

@@ -16,9 +16,14 @@ import org.springframework.data.redis.core.StringRedisTemplate;
 @AutoConfiguration(after = CituRedisAutoConfiguration.class)
 public class CituApiSignatureAutoConfiguration {
 
+//    @Bean
+//    public ApiSignatureAspect signatureAspect(ApiSignatureRedisDAO signatureRedisDAO, ErrorRecordApi errorRecordApi) {
+//        return new ApiSignatureAspect(signatureRedisDAO,errorRecordApi);
+//    }
+
     @Bean
-    public ApiSignatureAspect signatureAspect(ApiSignatureRedisDAO signatureRedisDAO, ErrorRecordApi errorRecordApi) {
-        return new ApiSignatureAspect(signatureRedisDAO,errorRecordApi);
+    public ApiSignatureAspect signatureAspect(ApiSignatureRedisDAO signatureRedisDAO) {
+        return new ApiSignatureAspect(signatureRedisDAO);
     }
 
     @Bean

+ 5 - 5
citu-framework/citu-spring-boot-starter-protection/src/main/java/com/citu/framework/signature/core/aop/ApiSignatureAspect.java

@@ -37,7 +37,7 @@ public class ApiSignatureAspect {
 
     private final ApiSignatureRedisDAO signatureRedisDAO;
 
-    private final ErrorRecordApi errorRecordApi;
+//    private final ErrorRecordApi errorRecordApi;
 
     private static final ThreadLocal<Map<String,Object>> recordThreadLocal = new ThreadLocal<>();
 
@@ -87,10 +87,10 @@ public class ApiSignatureAspect {
             recordThreadLocal.remove();
             return;
         }
-        errorRecordApi.create(ErrorRecordReqDTO.builder()
-                .mark(ServletUtils.getRequest().getHeader(signature.timestamp()))
-                .content(JSON.toJSONString(recordThreadLocal.get()))
-                .build());
+//        errorRecordApi.create(ErrorRecordReqDTO.builder()
+//                .mark(ServletUtils.getRequest().getHeader(signature.timestamp()))
+//                .content(JSON.toJSONString(recordThreadLocal.get()))
+//                .build());
         recordThreadLocal.remove();
 
         // 2. 验证不通过,抛出异常

+ 9 - 1
citu-framework/citu-spring-boot-starter-web/src/main/java/com/citu/framework/i18n/config/CituI18nAutoConfiguration.java

@@ -12,6 +12,7 @@ import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
 import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
 import org.springframework.web.servlet.i18n.SessionLocaleResolver;
 
+import javax.annotation.Resource;
 import java.util.Locale;
 
 /**
@@ -25,7 +26,11 @@ import java.util.Locale;
 // 设置为 false 时,禁用
 public class CituI18nAutoConfiguration implements WebMvcConfigurer {
 
+    @Resource
+    private I18nProperties i18nProperties;
+
     @Bean
+    @ConditionalOnProperty(value = "citu.i18n.enable", havingValue = "true")
     public LocaleResolver localeResolver() {
         SessionLocaleResolver localeResolver = new SessionLocaleResolver();
         localeResolver.setDefaultLocale(Locale.SIMPLIFIED_CHINESE);
@@ -34,6 +39,7 @@ public class CituI18nAutoConfiguration implements WebMvcConfigurer {
     }
 
     @Bean
+    @ConditionalOnProperty(value = "citu.i18n.enable", havingValue = "true")
     public Validator validator(MessageSource messageSource) {
         LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
         validator.setValidationMessageSource(messageSource);
@@ -42,6 +48,8 @@ public class CituI18nAutoConfiguration implements WebMvcConfigurer {
 
     @Override
     public void addInterceptors(InterceptorRegistry registry) {
-        registry.addInterceptor(new LocaleInterceptor());
+        if (i18nProperties.isEnable()) {
+            registry.addInterceptor(new LocaleInterceptor());
+        }
     }
 }

+ 1 - 1
citu-framework/citu-spring-boot-starter-web/src/main/java/com/citu/framework/swagger/config/CituSwaggerAutoConfiguration.java

@@ -118,7 +118,7 @@ public class CituSwaggerAutoConfiguration {
     public static GroupedOpenApi buildGroupedOpenApi(String group, String path) {
         return GroupedOpenApi.builder()
                 .group(group)
-                .pathsToMatch("/admin-api/" + path + "/**", "/app-api/" + path + "/**", "/app-admin-api/" + path + "/**")
+                .pathsToMatch("/admin-api/" + path + "/**", "/app-api/" + path + "/**")
                 .addOperationCustomizer((operation, handlerMethod) -> operation
                         .addParametersItem(buildTenantHeaderParameter())
                         .addParametersItem(buildSecurityHeaderParameter())

+ 14 - 14
citu-module-infra/citu-module-infra-biz/src/main/resources/codegen/java/service/serviceImpl.vm

@@ -54,19 +54,19 @@ public ${primaryColumn.javaType} create${simpleClassName}(${sceneEnum.prefixClas
 #if ( $table.templateType == 2 )
     #set ($TreeParentJavaField = $treeParentColumn.javaField.substring(0,1).toUpperCase() + ${treeParentColumn.javaField.substring(1)})##首字母大写
     #set ($TreeNameJavaField = $treeNameColumn.javaField.substring(0,1).toUpperCase() + ${treeNameColumn.javaField.substring(1)})##首字母大写
-// 校验${treeParentColumn.columnComment}的有效性
+        // 校验${treeParentColumn.columnComment}的有效性
 validateParent${simpleClassName}(null, createReqVO.get${TreeParentJavaField}());
-// 校验${treeNameColumn.columnComment}的唯一性
+        // 校验${treeNameColumn.columnComment}的唯一性
 validate${simpleClassName}${TreeNameJavaField}Unique(null, createReqVO.get${TreeParentJavaField}(), createReqVO.get${TreeNameJavaField}());
 
 #end
-// 插入
+        // 插入
 ${table.className}DO ${classNameVar} = BeanUtils.toBean(createReqVO, ${table.className}DO.class);
 ${classNameVar}Mapper.insert(${classNameVar});
 ## 特殊:主子表专属逻辑(非 ERP 模式)
 #if ( $subTables && $subTables.size() > 0 && $table.templateType != 11 )
 
-// 插入子表
+        // 插入子表
     #foreach ($subTable in $subTables)
         #set ($index = $foreach.count - 1)
         #set ($subSimpleClassName = $subSimpleClassNames.get($index))
@@ -79,7 +79,7 @@ ${classNameVar}Mapper.insert(${classNameVar});
         #end
     #end
 #end
-// 返回
+        // 返回
 return ${classNameVar}.getId();
 }
 
@@ -89,25 +89,25 @@ return ${classNameVar}.getId();
 @Transactional(rollbackFor = Exception.class)
 #end
 public void update${simpleClassName}(${sceneEnum.prefixClass}${table.className}SaveReqVO updateReqVO) {
-// 校验存在
+        // 校验存在
 validate${simpleClassName}Exists(updateReqVO.getId());
 ## 特殊:树表专属逻辑
 #if ( $table.templateType == 2 )
     #set ($TreeParentJavaField = $treeParentColumn.javaField.substring(0,1).toUpperCase() + ${treeParentColumn.javaField.substring(1)})##首字母大写
     #set ($TreeNameJavaField = $treeNameColumn.javaField.substring(0,1).toUpperCase() + ${treeNameColumn.javaField.substring(1)})##首字母大写
-// 校验${treeParentColumn.columnComment}的有效性
+        // 校验${treeParentColumn.columnComment}的有效性
 validateParent${simpleClassName}(updateReqVO.getId(), updateReqVO.get${TreeParentJavaField}());
-// 校验${treeNameColumn.columnComment}的唯一性
+        // 校验${treeNameColumn.columnComment}的唯一性
 validate${simpleClassName}${TreeNameJavaField}Unique(updateReqVO.getId(), updateReqVO.get${TreeParentJavaField}(), updateReqVO.get${TreeNameJavaField}());
 
 #end
-// 更新
+        // 更新
 ${table.className}DO updateObj = BeanUtils.toBean(updateReqVO, ${table.className}DO.class);
 ${classNameVar}Mapper.updateById(updateObj);
 ## 特殊:主子表专属逻辑(非 ERP 模式)
 #if ( $subTables && $subTables.size() > 0 && $table.templateType != 11)
 
-// 更新子表
+        // 更新子表
     #foreach ($subTable in $subTables)
         #set ($index = $foreach.count - 1)
         #set ($subSimpleClassName = $subSimpleClassNames.get($index))
@@ -128,22 +128,22 @@ ${classNameVar}Mapper.updateById(updateObj);
 @Transactional(rollbackFor = Exception.class)
 #end
 public void delete${simpleClassName}(${primaryColumn.javaType} id) {
-// 校验存在
+        // 校验存在
 validate${simpleClassName}Exists(id);
 ## 特殊:树表专属逻辑
 #if ( $table.templateType == 2 )
     #set ($ParentJavaField = $treeParentColumn.javaField.substring(0,1).toUpperCase() + ${treeParentColumn.javaField.substring(1)})##首字母大写
-// 校验是否有子${table.classComment}
+        // 校验是否有子${table.classComment}
 if (${classNameVar}Mapper.selectCountBy${ParentJavaField}(id) > 0) {
 throw exception(${simpleClassName_underlineCase.toUpperCase()}_EXITS_CHILDREN);
 }
 #end
-// 删除
+        // 删除
 ${classNameVar}Mapper.deleteById(id);
 ## 特殊:主子表专属逻辑
 #if ( $subTables && $subTables.size() > 0)
 
-// 删除子表
+        // 删除子表
     #foreach ($subTable in $subTables)
         #set ($index = $foreach.count - 1)
         #set ($subSimpleClassName = $subSimpleClassNames.get($index))

+ 21 - 0
citu-module-mall/citu-module-promotion-api/src/main/java/com/citu/module/promotion/enums/ErrorCodeConstants.java

@@ -138,4 +138,25 @@ public interface ErrorCodeConstants {
     // ========== 客服消息 1-013-020-000 ==========
     ErrorCode KEFU_MESSAGE_NOT_EXISTS = new ErrorCode(1_013_020_000, "客服消息不存在");
 
+    // ========== 幸运抽奖-活动 1-013-050-00 ==========
+    ErrorCode LUCK_LOTTERY_NOT_EXISTS = new ErrorCode(1_013_050_01, "幸运抽奖活动不存在");
+    ErrorCode LUCK_LOTTERY_NOT_START = new ErrorCode(1_013_050_02, "幸运抽奖活动还未开始");
+    ErrorCode LUCK_LOTTERY_END = new ErrorCode(1_013_050_03, "幸运抽奖活动已结束");
+    ErrorCode LUCK_LOTTERY_NAME_USED = new ErrorCode(1_013_050_04, "幸运抽奖活动名称({})已经被使用");
+
+    // ========== 幸运抽奖-奖品 1-013-051-00 ==========
+    ErrorCode LUCK_PRIZE_NOT_EXISTS = new ErrorCode(1_013_051_01, "幸运抽奖奖品不存在");
+    ErrorCode LUCK_LOTTERY_NOT_ADD_PRIZE = new ErrorCode(1_013_051_02, "抽奖活动未添加奖品");
+    ErrorCode LUCK_LOTTERY_PRIZE_COUNT_EXCEED = new ErrorCode(1_013_051_03, "奖品不能超过8个");
+    ErrorCode LUCK_LOTTERY_PRIZE_EXTEND_NOT_COMPLETE = new ErrorCode(1_013_051_04, "自定义奖品未填写扩展信息");
+
+    // ========== 幸运抽奖-抽奖记录 1-013-052-00 ==========
+    ErrorCode LUCK_LOTTERY_RECORD_NOT_EXISTS = new ErrorCode(1_013_051_02, "幸运抽奖抽奖记录不存在");
+
+    // ========== 幸运抽奖-奖品扩展 1-013-053-00 ==========
+    ErrorCode LUCK_PRIZE_EXTEND_NOT_EXISTS = new ErrorCode(1_013_053_01, "幸运抽奖奖品扩展不存在");
+    ErrorCode LUCK_PRIZE_EXTEND_PROVINCE_INCORRECT = new ErrorCode(1_013_053_02, "省份不正确,请填写正确省份名称");
+    ErrorCode LUCK_PRIZE_EXTEND_CITY_INCORRECT = new ErrorCode(1_013_053_03, "城市不正确,请填写正确城市名称");
+    ErrorCode LUCK_PRIZE_EXTEND_COUNTY_INCORRECT = new ErrorCode(1_013_053_04, "区县不正确,请填写正确区县名称");
+
 }

+ 34 - 0
citu-module-mall/citu-module-promotion-api/src/main/java/com/citu/module/promotion/enums/luck/LuckLotteryFactorEnum.java

@@ -0,0 +1,34 @@
+package com.citu.module.promotion.enums.luck;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * 幸运抽奖消耗枚举
+ * (1积分 2余额 3下单支付成功 4关注 5订单评价 6指定商品下单支付成功)
+ *
+ * @author Rayson
+ */
+@AllArgsConstructor
+@Getter
+public enum LuckLotteryFactorEnum {
+    POINTS("1", "积分"),
+    BALANCE("2", "余额"),
+    ORDER_PAY_SUCCESS("3", "下单支付成功"),
+    ATTENDS_USER("4", "关注"),
+    ORDER_COMMENT("5", "订单评价"),
+    ORDER_PRODUCT_PAY_SUCCESS("6", "下单指定商品支付成功");
+
+    private final String factor;
+    private final String name;
+
+    public static LuckLotteryFactorEnum getByFactor(String factor) {
+        for (LuckLotteryFactorEnum luckLotteryFactorEnum : LuckLotteryFactorEnum.values()) {
+            if (luckLotteryFactorEnum.getFactor().equals(factor)) {
+                return luckLotteryFactorEnum;
+            }
+        }
+        return null;
+    }
+
+}

+ 23 - 0
citu-module-mall/citu-module-promotion-api/src/main/java/com/citu/module/promotion/enums/luck/LuckLotteryTypeEnum.java

@@ -0,0 +1,23 @@
+package com.citu.module.promotion.enums.luck;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * 幸运抽奖类型枚举
+ * (1九宫格 2大转盘 3九宫格升级版 4幸运翻牌)
+ *
+ * @author Rayson
+ */
+@AllArgsConstructor
+@Getter
+public enum LuckLotteryTypeEnum {
+    GRID_9("1", "九宫格"),
+    ROTARY_DISK("2", "大转盘"),
+    GRID_9_UPGRADE("3", "九宫格升级版"),
+    LUCKY_FLIP_CARD("4", "幸运翻牌");
+
+    private final String type;
+    private final String name;
+
+}

+ 32 - 0
citu-module-mall/citu-module-promotion-api/src/main/java/com/citu/module/promotion/enums/luck/LuckPrizeTypeEnum.java

@@ -0,0 +1,32 @@
+package com.citu.module.promotion.enums.luck;
+
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * 幸运抽奖奖品类型枚举
+ * (1未中奖 2积分 3余额 4红包 5优惠券 6站内商品 7等级经验 8用户等级 9svip天数 99自定义)
+ *
+ * @author Rayson
+ */
+@AllArgsConstructor
+@Getter
+public enum LuckPrizeTypeEnum {
+
+    NOT_WIN("1", "未中奖"),
+    POINTS("2", "积分"),
+    BALANCE("3", "余额"),
+    REDPACKET("4", "红包"),
+    COUPON("5", "优惠券"),
+    PRODUCT("6", "站内商品"),
+    LEVEL_EXPERIENCE("7", "等级经验"),
+    USER_LEVEL("8", "用户等级"),
+    SVIP_DAYS("9", "svip天数"),
+    CUSTOM("99", "自定义"),
+
+    ;
+
+    private final String type;
+    private final String name;
+}

+ 27 - 0
citu-module-mall/citu-module-promotion-api/src/main/java/com/citu/module/promotion/enums/luck/LuckStatusEnum.java

@@ -0,0 +1,27 @@
+package com.citu.module.promotion.enums.luck;
+
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * 幸运抽奖状态
+ * (0开启 1关闭)
+ *
+ * @author Rayson
+ */
+@AllArgsConstructor
+@Getter
+public enum LuckStatusEnum {
+    ENABLE("0", "开启"),
+    DISABLE("1", "关闭");
+
+    /**
+     * 状态值
+     */
+    private final String status;
+    /**
+     * 状态名
+     */
+    private final String name;
+}

+ 5 - 0
citu-module-mall/citu-module-promotion-biz/pom.xml

@@ -58,6 +58,11 @@
             <artifactId>citu-spring-boot-starter-biz-tenant</artifactId>
         </dependency>
 
+        <dependency>
+            <groupId>com.citu</groupId>
+            <artifactId>citu-spring-boot-starter-protection</artifactId>
+        </dependency>
+
         <!-- Web 相关 -->
         <dependency>
             <groupId>com.citu</groupId>

+ 94 - 0
citu-module-mall/citu-module-promotion-biz/src/main/java/com/citu/module/promotion/controller/admin/luck/LuckLotteryController.java

@@ -0,0 +1,94 @@
+package com.citu.module.promotion.controller.admin.luck;
+
+
+import com.citu.framework.apilog.core.annotation.ApiAccessLog;
+import com.citu.framework.common.pojo.CommonResult;
+import com.citu.framework.common.pojo.PageParam;
+import com.citu.framework.common.pojo.PageResult;
+import com.citu.framework.common.util.object.BeanUtils;
+import com.citu.framework.excel.core.util.ExcelUtils;
+import com.citu.module.promotion.controller.admin.luck.vo.LuckLotteryDetailRespVO;
+import com.citu.module.promotion.controller.admin.luck.vo.LuckLotteryPageReqVO;
+import com.citu.module.promotion.controller.admin.luck.vo.LuckLotteryRespVO;
+import com.citu.module.promotion.controller.admin.luck.vo.LuckLotterySaveReqVO;
+import com.citu.module.promotion.dal.dataobject.luck.LuckLotteryDO;
+import com.citu.module.promotion.service.luck.LuckLotteryService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletResponse;
+import javax.validation.Valid;
+import java.io.IOException;
+import java.util.List;
+
+import static com.citu.framework.apilog.core.enums.OperateTypeEnum.EXPORT;
+import static com.citu.framework.common.pojo.CommonResult.success;
+
+@Tag(name = "管理后台 - 幸运抽奖-活动")
+@RestController
+@RequestMapping("/promotion/luck-lottery")
+@Validated
+public class LuckLotteryController {
+
+    @Resource
+    private LuckLotteryService luckLotteryService;
+
+    @PostMapping("/create")
+    @Operation(summary = "创建幸运抽奖-活动")
+    @PreAuthorize("@ss.hasPermission('promotion:luck-lottery:create')")
+    public CommonResult<Long> createLuckLottery(@Valid @RequestBody LuckLotterySaveReqVO createReqVO) {
+        return success(luckLotteryService.createLuckLottery(createReqVO));
+    }
+
+    @PutMapping("/update")
+    @Operation(summary = "更新幸运抽奖-活动")
+    @PreAuthorize("@ss.hasPermission('promotion:luck-lottery:update')")
+    public CommonResult<Boolean> updateLuckLottery(@Valid @RequestBody LuckLotterySaveReqVO updateReqVO) {
+        luckLotteryService.updateLuckLottery(updateReqVO);
+        return success(true);
+    }
+
+    @DeleteMapping("/delete")
+    @Operation(summary = "删除幸运抽奖-活动")
+    @Parameter(name = "id", description = "编号", required = true)
+    @PreAuthorize("@ss.hasPermission('promotion:luck-lottery:delete')")
+    public CommonResult<Boolean> deleteLuckLottery(@RequestParam("id") Long id) {
+        luckLotteryService.deleteLuckLottery(id);
+        return success(true);
+    }
+
+    @GetMapping("/get")
+    @Operation(summary = "获得幸运抽奖-活动")
+    @Parameter(name = "id", description = "编号", required = true, example = "1024")
+    @PreAuthorize("@ss.hasPermission('promotion:luck-lottery:query')")
+    public CommonResult<LuckLotteryDetailRespVO> getLuckLottery(@RequestParam("id") Long id) {
+        return success(luckLotteryService.detail(id));
+    }
+
+    @GetMapping("/page")
+    @Operation(summary = "获得幸运抽奖-活动分页")
+    @PreAuthorize("@ss.hasPermission('promotion:luck-lottery:query')")
+    public CommonResult<PageResult<LuckLotteryRespVO>> getLuckLotteryPage(@Valid LuckLotteryPageReqVO pageReqVO) {
+        PageResult<LuckLotteryDO> pageResult = luckLotteryService.getLuckLotteryPage(pageReqVO);
+        return success(BeanUtils.toBean(pageResult, LuckLotteryRespVO.class));
+    }
+
+    @GetMapping("/export-excel")
+    @Operation(summary = "导出幸运抽奖-活动 Excel")
+    @PreAuthorize("@ss.hasPermission('promotion:luck-lottery:export')")
+    @ApiAccessLog(operateType = EXPORT)
+    public void exportLuckLotteryExcel(@Valid LuckLotteryPageReqVO pageReqVO,
+                                       HttpServletResponse response) throws IOException {
+        pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
+        List<LuckLotteryDO> list = luckLotteryService.getLuckLotteryPage(pageReqVO).getList();
+        // 导出 Excel
+        ExcelUtils.write(response, "幸运抽奖-活动.xls", "数据", LuckLotteryRespVO.class,
+                BeanUtils.toBean(list, LuckLotteryRespVO.class));
+    }
+
+}

+ 95 - 0
citu-module-mall/citu-module-promotion-biz/src/main/java/com/citu/module/promotion/controller/admin/luck/LuckLotteryRecordController.java

@@ -0,0 +1,95 @@
+package com.citu.module.promotion.controller.admin.luck;
+
+
+import com.citu.framework.apilog.core.annotation.ApiAccessLog;
+import com.citu.framework.common.pojo.CommonResult;
+import com.citu.framework.common.pojo.PageParam;
+import com.citu.framework.common.pojo.PageResult;
+import com.citu.framework.common.util.object.BeanUtils;
+import com.citu.framework.excel.core.util.ExcelUtils;
+import com.citu.module.promotion.controller.admin.luck.vo.record.LuckLotteryRecordDetailRespVO;
+import com.citu.module.promotion.controller.admin.luck.vo.record.LuckLotteryRecordPageReqVO;
+import com.citu.module.promotion.controller.admin.luck.vo.record.LuckLotteryRecordRespVO;
+import com.citu.module.promotion.controller.admin.luck.vo.record.LuckLotteryRecordSaveReqVO;
+import com.citu.module.promotion.dal.dataobject.luck.LuckLotteryRecordDO;
+import com.citu.module.promotion.service.luck.LuckLotteryRecordService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletResponse;
+import javax.validation.Valid;
+import java.io.IOException;
+import java.util.List;
+
+import static com.citu.framework.apilog.core.enums.OperateTypeEnum.EXPORT;
+import static com.citu.framework.common.pojo.CommonResult.success;
+
+@Tag(name = "管理后台 - 幸运抽奖-抽奖记录")
+@RestController
+@RequestMapping("/promotion/luck-lottery-record")
+@Validated
+public class LuckLotteryRecordController {
+
+    @Resource
+    private LuckLotteryRecordService luckLotteryRecordService;
+
+    @PostMapping("/create")
+    @Operation(summary = "创建幸运抽奖-抽奖记录")
+    @PreAuthorize("@ss.hasPermission('promotion:luck-lottery-record:create')")
+    public CommonResult<Long> createLuckLotteryRecord(@Valid @RequestBody LuckLotteryRecordSaveReqVO createReqVO) {
+        return success(luckLotteryRecordService.createLuckLotteryRecord(createReqVO));
+    }
+
+    @PutMapping("/update")
+    @Operation(summary = "更新幸运抽奖-抽奖记录")
+    @PreAuthorize("@ss.hasPermission('promotion:luck-lottery-record:update')")
+    public CommonResult<Boolean> updateLuckLotteryRecord(@Valid @RequestBody LuckLotteryRecordSaveReqVO updateReqVO) {
+        luckLotteryRecordService.updateLuckLotteryRecord(updateReqVO);
+        return success(true);
+    }
+
+    @DeleteMapping("/delete")
+    @Operation(summary = "删除幸运抽奖-抽奖记录")
+    @Parameter(name = "id", description = "编号", required = true)
+    @PreAuthorize("@ss.hasPermission('promotion:luck-lottery-record:delete')")
+    public CommonResult<Boolean> deleteLuckLotteryRecord(@RequestParam("id") Long id) {
+        luckLotteryRecordService.deleteLuckLotteryRecord(id);
+        return success(true);
+    }
+
+    @GetMapping("/get")
+    @Operation(summary = "获得幸运抽奖-抽奖记录")
+    @Parameter(name = "id", description = "编号", required = true, example = "1024")
+    @PreAuthorize("@ss.hasPermission('promotion:luck-lottery-record:query')")
+    public CommonResult<LuckLotteryRecordRespVO> getLuckLotteryRecord(@RequestParam("id") Long id) {
+        LuckLotteryRecordDO luckLotteryRecord = luckLotteryRecordService.getLuckLotteryRecord(id);
+        return success(BeanUtils.toBean(luckLotteryRecord, LuckLotteryRecordRespVO.class));
+    }
+
+    @GetMapping("/page")
+    @Operation(summary = "获得幸运抽奖-抽奖记录分页")
+    @PreAuthorize("@ss.hasPermission('promotion:luck-lottery-record:query')")
+    public CommonResult<PageResult<LuckLotteryRecordDetailRespVO>>
+    getLuckLotteryRecordPage(@Valid LuckLotteryRecordPageReqVO pageReqVO) {
+        return success(luckLotteryRecordService.page(pageReqVO));
+    }
+
+    @GetMapping("/export-excel")
+    @Operation(summary = "导出幸运抽奖-抽奖记录 Excel")
+    @PreAuthorize("@ss.hasPermission('promotion:luck-lottery-record:export')")
+    @ApiAccessLog(operateType = EXPORT)
+    public void exportLuckLotteryRecordExcel(@Valid LuckLotteryRecordPageReqVO pageReqVO,
+                                             HttpServletResponse response) throws IOException {
+        pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
+        List<LuckLotteryRecordDO> list = luckLotteryRecordService.getLuckLotteryRecordPage(pageReqVO).getList();
+        // 导出 Excel
+        ExcelUtils.write(response, "幸运抽奖-抽奖记录.xls", "数据", LuckLotteryRecordRespVO.class,
+                BeanUtils.toBean(list, LuckLotteryRecordRespVO.class));
+    }
+
+}

+ 153 - 0
citu-module-mall/citu-module-promotion-biz/src/main/java/com/citu/module/promotion/controller/admin/luck/LuckPrizeController.java

@@ -0,0 +1,153 @@
+package com.citu.module.promotion.controller.admin.luck;
+
+
+import com.citu.framework.apilog.core.annotation.ApiAccessLog;
+import com.citu.framework.common.pojo.CommonResult;
+import com.citu.framework.common.pojo.PageParam;
+import com.citu.framework.common.pojo.PageResult;
+import com.citu.framework.common.util.date.LocalDateTimeUtils;
+import com.citu.framework.common.util.object.BeanUtils;
+import com.citu.framework.excel.core.util.ExcelUtils;
+import com.citu.framework.security.core.annotations.PreAuthenticated;
+import com.citu.module.menduner.system.enums.eduexp.EducationTypeEnum;
+import com.citu.module.menduner.system.enums.job.JobStatusEnum;
+import com.citu.module.menduner.system.enums.job.JobTypeEnum;
+import com.citu.module.menduner.system.enums.job.PayTypeEnum;
+import com.citu.module.menduner.system.enums.workexp.ExpTypeEnum;
+import com.citu.module.promotion.controller.admin.luck.vo.prize.*;
+import com.citu.module.promotion.dal.dataobject.luck.LuckPrizeDO;
+import com.citu.module.promotion.enums.luck.LuckPrizeTypeEnum;
+import com.citu.module.promotion.enums.luck.LuckStatusEnum;
+import com.citu.module.promotion.service.luck.LuckPrizeService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletResponse;
+import javax.validation.Valid;
+import java.io.IOException;
+import java.math.BigDecimal;
+import java.time.Duration;
+import java.util.Arrays;
+import java.util.List;
+
+import static com.citu.framework.apilog.core.enums.OperateTypeEnum.EXPORT;
+import static com.citu.framework.common.pojo.CommonResult.success;
+
+@Tag(name = "管理后台 - 幸运抽奖-奖品")
+@RestController
+@RequestMapping("/promotion/luck-prize")
+@Validated
+public class LuckPrizeController {
+
+    @Resource
+    private LuckPrizeService luckPrizeService;
+
+    @PostMapping("/create")
+    @Operation(summary = "创建幸运抽奖-奖品")
+    @PreAuthorize("@ss.hasPermission('promotion:luck-prize:create')")
+    public CommonResult<Long> createLuckPrize(@Valid @RequestBody LuckPrizeSaveReqVO createReqVO) {
+        return success(luckPrizeService.createLuckPrize(createReqVO));
+    }
+
+    @PutMapping("/update")
+    @Operation(summary = "更新幸运抽奖-奖品")
+    @PreAuthorize("@ss.hasPermission('promotion:luck-prize:update')")
+    public CommonResult<Boolean> updateLuckPrize(@Valid @RequestBody LuckPrizeSaveReqVO updateReqVO) {
+        luckPrizeService.updateLuckPrize(updateReqVO);
+        return success(true);
+    }
+
+    @DeleteMapping("/delete")
+    @Operation(summary = "删除幸运抽奖-奖品")
+    @Parameter(name = "id", description = "编号", required = true)
+    @PreAuthorize("@ss.hasPermission('promotion:luck-prize:delete')")
+    public CommonResult<Boolean> deleteLuckPrize(@RequestParam("id") Long id) {
+        luckPrizeService.deleteLuckPrize(id);
+        return success(true);
+    }
+
+    @GetMapping("/get")
+    @Operation(summary = "获得幸运抽奖-奖品")
+    @Parameter(name = "id", description = "编号", required = true, example = "1024")
+    @PreAuthorize("@ss.hasPermission('promotion:luck-prize:query')")
+    public CommonResult<LuckPrizeRespVO> getLuckPrize(@RequestParam("id") Long id) {
+        return success(luckPrizeService.detail(id));
+    }
+
+    @GetMapping("/page")
+    @Operation(summary = "获得幸运抽奖-奖品分页")
+    @PreAuthorize("@ss.hasPermission('promotion:luck-prize:query')")
+    public CommonResult<PageResult<LuckPrizeDetailRespVO>> getLuckPrizePage(@Valid LuckPrizePageReqVO pageReqVO) {
+        return success(luckPrizeService.page(pageReqVO));
+    }
+
+    @GetMapping("/export-excel")
+    @Operation(summary = "导出幸运抽奖-奖品 Excel")
+    @PreAuthorize("@ss.hasPermission('promotion:luck-prize:export')")
+    @ApiAccessLog(operateType = EXPORT)
+    public void exportLuckPrizeExcel(@Valid LuckPrizePageReqVO pageReqVO,
+                                     HttpServletResponse response) throws IOException {
+        pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
+        List<LuckPrizeDO> list = luckPrizeService.getLuckPrizePage(pageReqVO).getList();
+        // 导出 Excel
+        ExcelUtils.write(response, "幸运抽奖-奖品.xls", "数据", LuckPrizeRespVO.class,
+                BeanUtils.toBean(list, LuckPrizeRespVO.class));
+    }
+
+    @GetMapping("/import-template")
+    @Operation(summary = "下载奖品导入模版")
+    @ApiAccessLog(operateType = EXPORT)
+    public void importTemplate(HttpServletResponse response) throws IOException {
+        // 手动创建导出 demo
+        List<LuckPrizeImportExcelVO> list = Arrays.asList(
+                LuckPrizeImportExcelVO.builder()
+                        .lotteryName("房卷抽奖活动")
+                        .name("某酒店一天抵扣卷")
+                        .image(null)
+                        .prompt("恭喜你获得房卷一张!")
+                        .type(LuckPrizeTypeEnum.CUSTOM.getType())
+                        .chance(100)
+                        .total(100)
+                        .bloc("万豪集团")
+                        .brand("宝格丽")
+                        .provinceName("广东省")
+                        .cityName("广州市")
+                        .districtName("海珠区")
+                        .status(LuckStatusEnum.ENABLE.getStatus())
+                        .build(),
+
+                LuckPrizeImportExcelVO.builder()
+                        .lotteryName("房卷抽奖活动")
+                        .name("某酒店三天抵扣卷")
+                        .image(null)
+                        .prompt("恭喜你获得某酒店房卷一张!")
+                        .type(LuckPrizeTypeEnum.CUSTOM.getType())
+                        .chance(1)
+                        .total(3)
+                        .bloc("万豪集团")
+                        .brand("万豪")
+                        .provinceName("广东省")
+                        .status(LuckStatusEnum.ENABLE.getStatus())
+                        .build()
+        );
+        // 输出
+        ExcelUtils.write(response, "奖品导入模版.xlsx", "Sheet", LuckPrizeImportExcelVO.class, list);
+    }
+
+    @PreAuthenticated
+    @PostMapping("/import")
+    @Operation(summary = "导入抽奖奖品")
+    public CommonResult<Boolean> importExcel(@RequestPart @RequestParam MultipartFile multipartFile)
+            throws Exception {
+        List<LuckPrizeImportExcelVO> list = ExcelUtils.read(multipartFile, LuckPrizeImportExcelVO.class);
+        luckPrizeService.importData(list);
+        return success(true);
+    }
+
+}

+ 19 - 0
citu-module-mall/citu-module-promotion-biz/src/main/java/com/citu/module/promotion/controller/admin/luck/vo/LuckLotteryDetailRespVO.java

@@ -0,0 +1,19 @@
+package com.citu.module.promotion.controller.admin.luck.vo;
+
+
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
+import com.citu.module.product.api.spu.dto.ProductSpuRespDTO;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.util.List;
+
+@Schema(description = "管理后台 - 幸运抽奖-活动详情 Response VO")
+@Data
+@ExcelIgnoreUnannotated
+public class LuckLotteryDetailRespVO extends LuckLotteryRespVO {
+
+    @Schema(description = "商品信息", example = "9192")
+    private List<ProductSpuRespDTO> spuList;
+
+}

+ 66 - 0
citu-module-mall/citu-module-promotion-biz/src/main/java/com/citu/module/promotion/controller/admin/luck/vo/LuckLotteryPageReqVO.java

@@ -0,0 +1,66 @@
+package com.citu.module.promotion.controller.admin.luck.vo;
+
+
+import com.citu.framework.common.pojo.PageParam;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.time.LocalDateTime;
+
+import static com.citu.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
+
+@Schema(description = "管理后台 - 幸运抽奖-活动分页 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class LuckLotteryPageReqVO extends PageParam {
+
+    @Schema(description = "奖品名称", example = "李四")
+    private String name;
+
+    @Schema(description = "类型(1九宫格 2大转盘 3九宫格升级版 4幸运翻牌)", example = "1")
+    private String type;
+
+    @Schema(description = "抽奖消耗 (1积分 2余额 3下单支付成功 4关注 5订单评价 6指定商品下单支付成功)")
+    private String factor;
+
+    @Schema(description = "获取一次抽奖的条件数量")
+    private Integer factorNum;
+
+    @Schema(description = "参与用户(1所有 2部分)")
+    private String attendsUser;
+
+    @Schema(description = "参与用户是否付费会员")
+    private Boolean isSvip;
+
+    @Schema(description = "开始时间")
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    private LocalDateTime[] startTime;
+
+    @Schema(description = "结束时间")
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    private LocalDateTime[] endTime;
+
+    @Schema(description = "中奖记录展示")
+    private Boolean isAllRecord;
+
+    @Schema(description = "个人中奖记录展示")
+    private Boolean isPersonalRecord;
+
+    @Schema(description = "活动规格是否展示")
+    private Boolean isContent;
+
+    @Schema(description = "排序")
+    private Integer sort;
+
+    @Schema(description = "状态", example = "2")
+    private String status;
+
+    @Schema(description = "创建时间")
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    private LocalDateTime[] createTime;
+
+}

+ 116 - 0
citu-module-mall/citu-module-promotion-biz/src/main/java/com/citu/module/promotion/controller/admin/luck/vo/LuckLotteryRespVO.java

@@ -0,0 +1,116 @@
+package com.citu.module.promotion.controller.admin.luck.vo;
+
+
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
+import com.alibaba.excel.annotation.ExcelProperty;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+import java.util.List;
+
+@Schema(description = "管理后台 - 幸运抽奖-活动 Response VO")
+@Data
+@ExcelIgnoreUnannotated
+public class LuckLotteryRespVO {
+
+    @Schema(description = "id", requiredMode = Schema.RequiredMode.REQUIRED, example = "9192")
+    @ExcelProperty("id")
+    private Long id;
+
+    @Schema(description = "奖品名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四")
+    @ExcelProperty("奖品名称")
+    private String name;
+
+    @Schema(description = "类型(1九宫格 2大转盘 3九宫格升级版 4幸运翻牌)", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+    @ExcelProperty("类型(1九宫格 2大转盘 3九宫格升级版 4幸运翻牌)")
+    private String type;
+
+    @Schema(description = "抽奖消耗 (1积分 2余额 3下单支付成功 4关注 5订单评价 6指定商品下单支付成功)", requiredMode = Schema.RequiredMode.REQUIRED)
+    @ExcelProperty("抽奖消耗 (1积分 2余额 3下单支付成功 4关注 5订单评价 6指定商品下单支付成功)")
+    private String factor;
+
+    @Schema(description = "抽奖消耗信息", requiredMode = Schema.RequiredMode.REQUIRED)
+    private List<String> factorInfo;
+
+    @Schema(description = "获取一次抽奖的条件数量", requiredMode = Schema.RequiredMode.REQUIRED)
+    @ExcelProperty("获取一次抽奖的条件数量")
+    private Integer factorNum;
+
+    @Schema(description = "活动描述", requiredMode = Schema.RequiredMode.REQUIRED)
+    @ExcelProperty("活动描述")
+    private String description;
+
+    @Schema(description = "活动背景图", requiredMode = Schema.RequiredMode.REQUIRED)
+    @ExcelProperty("活动背景图")
+    private String image;
+
+    @Schema(description = "参与用户(1所有 2部分)", requiredMode = Schema.RequiredMode.REQUIRED)
+    @ExcelProperty("参与用户(1所有 2部分)")
+    private String attendsUser;
+
+    @Schema(description = "参与用户等级")
+    @ExcelProperty("参与用户等级")
+    private List<Object> userLevel;
+
+    @Schema(description = "参与用户标签")
+    @ExcelProperty("参与用户标签")
+    private List<Object> userLabel;
+
+    @Schema(description = "参与用户是否付费会员")
+    @ExcelProperty("参与用户是否付费会员")
+    private Boolean isSvip;
+
+    @Schema(description = "奖品数量", requiredMode = Schema.RequiredMode.REQUIRED)
+    @ExcelProperty("奖品数量")
+    private Integer prizeNum;
+
+    @Schema(description = "开始时间", requiredMode = Schema.RequiredMode.REQUIRED)
+    @ExcelProperty("开始时间")
+    private LocalDateTime startTime;
+
+    @Schema(description = "结束时间", requiredMode = Schema.RequiredMode.REQUIRED)
+    @ExcelProperty("结束时间")
+    private LocalDateTime endTime;
+
+    @Schema(description = "抽奖次数限制(1每天 2每人)", requiredMode = Schema.RequiredMode.REQUIRED)
+    @ExcelProperty("抽奖次数限制(1每天 2每人)")
+    private Integer lotteryNumTerm;
+
+    @Schema(description = "抽奖次数")
+    @ExcelProperty("抽奖次数")
+    private Integer lotteryNum;
+
+    @Schema(description = "关注推广获取抽奖次数")
+    @ExcelProperty("关注推广获取抽奖次数")
+    private Integer spreadNum;
+
+    @Schema(description = "中奖记录展示")
+    @ExcelProperty("中奖记录展示")
+    private Boolean isAllRecord;
+
+    @Schema(description = "个人中奖记录展示")
+    @ExcelProperty("个人中奖记录展示")
+    private Boolean isPersonalRecord;
+
+    @Schema(description = "活动规格是否展示")
+    @ExcelProperty("活动规格是否展示")
+    private Boolean isContent;
+
+    @Schema(description = "活动文案抽奖协议之类")
+    @ExcelProperty("活动文案抽奖协议之类")
+    private String content;
+
+    @Schema(description = "排序")
+    @ExcelProperty("排序")
+    private Integer sort;
+
+    @Schema(description = "状态", example = "2")
+    @ExcelProperty("状态")
+    private String status;
+
+    @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
+    @ExcelProperty("创建时间")
+    private LocalDateTime createTime;
+
+}

+ 98 - 0
citu-module-mall/citu-module-promotion-biz/src/main/java/com/citu/module/promotion/controller/admin/luck/vo/LuckLotterySaveReqVO.java

@@ -0,0 +1,98 @@
+package com.citu.module.promotion.controller.admin.luck.vo;
+
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotEmpty;
+import javax.validation.constraints.NotNull;
+import java.time.LocalDateTime;
+import java.util.List;
+
+@Schema(description = "管理后台 - 幸运抽奖-活动新增/修改 Request VO")
+@Data
+public class LuckLotterySaveReqVO {
+
+    @Schema(description = "id", requiredMode = Schema.RequiredMode.REQUIRED, example = "9192")
+    private Long id;
+
+    @Schema(description = "奖品名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四")
+    @NotBlank(message = "奖品名称不能为空")
+    private String name;
+
+    @Schema(description = "类型(1九宫格 2大转盘 3九宫格升级版 4幸运翻牌)", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+    @NotBlank(message = "类型(1九宫格 2大转盘 3九宫格升级版 4幸运翻牌)不能为空")
+    private String type;
+
+    @Schema(description = "抽奖消耗 (1积分 2余额 3下单支付成功 4关注 5订单评价 6指定商品下单支付成功)", requiredMode = Schema.RequiredMode.REQUIRED)
+    @NotBlank(message = "抽奖消耗 (1积分 2余额 3下单支付成功 4关注 5订单评价 6指定商品下单支付成功)不能为空")
+    private String factor;
+
+    @Schema(description = "抽奖消耗信息", requiredMode = Schema.RequiredMode.REQUIRED)
+    private List<String> factorInfo;
+
+    @Schema(description = "获取一次抽奖的条件数量", requiredMode = Schema.RequiredMode.REQUIRED)
+    @NotNull(message = "获取一次抽奖的条件数量不能为空")
+    private Integer factorNum;
+
+    @Schema(description = "活动描述", requiredMode = Schema.RequiredMode.REQUIRED)
+    private String description;
+
+    @Schema(description = "活动背景图", requiredMode = Schema.RequiredMode.REQUIRED)
+    //@NotBlank(message = "活动背景图不能为空")
+    private String image;
+
+    @Schema(description = "参与用户(1所有 2部分)", requiredMode = Schema.RequiredMode.REQUIRED)
+    // @NotNull(message = "参与用户(1所有 2部分)不能为空")
+    private String attendsUser = "1";
+
+    @Schema(description = "参与用户等级")
+    private List<Object> userLevel;
+
+    @Schema(description = "参与用户标签")
+    private List<Object> userLabel;
+
+    @Schema(description = "参与用户是否付费会员")
+    private Boolean isSvip = false;
+
+    @Schema(description = "奖品数量", requiredMode = Schema.RequiredMode.REQUIRED)
+    private Integer prizeNum;
+
+    @Schema(description = "开始时间", requiredMode = Schema.RequiredMode.REQUIRED)
+    @NotNull(message = "开始时间不能为空")
+    private LocalDateTime startTime;
+
+    @Schema(description = "结束时间", requiredMode = Schema.RequiredMode.REQUIRED)
+    @NotNull(message = "结束时间不能为空")
+    private LocalDateTime endTime;
+
+    @Schema(description = "抽奖次数限制(1每天 2每人)", requiredMode = Schema.RequiredMode.REQUIRED)
+    // @NotNull(message = "抽奖次数限制(1每天 2每人)不能为空")
+    private Integer lotteryNumTerm = 1;
+
+    @Schema(description = "抽奖次数")
+    private Integer lotteryNum = 1;
+
+    @Schema(description = "关注推广获取抽奖次数")
+    private Integer spreadNum;
+
+    @Schema(description = "中奖记录展示")
+    private Boolean isAllRecord = true;
+
+    @Schema(description = "个人中奖记录展示")
+    private Boolean isPersonalRecord = true;
+
+    @Schema(description = "活动规格是否展示")
+    private Boolean isContent = true;
+
+    @Schema(description = "活动文案抽奖协议之类")
+    private String content;
+
+    @Schema(description = "排序")
+    private Integer sort = 0;
+
+    @Schema(description = "状态", example = "2")
+    private String status;
+
+}

+ 20 - 0
citu-module-mall/citu-module-promotion-biz/src/main/java/com/citu/module/promotion/controller/admin/luck/vo/prize/LuckPrizeDetailRespVO.java

@@ -0,0 +1,20 @@
+package com.citu.module.promotion.controller.admin.luck.vo.prize;
+
+
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
+import com.citu.module.product.api.spu.dto.ProductSpuRespDTO;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+@Schema(description = "管理后台 - 幸运抽奖-奖品详情 Response VO")
+@Data
+@ExcelIgnoreUnannotated
+public class LuckPrizeDetailRespVO extends LuckPrizeRespVO {
+
+    @Schema(description = "商品信息", example = "30925")
+    private ProductSpuRespDTO spu;
+
+    @Schema(description = "概率")
+    private double probability;
+
+}

+ 64 - 0
citu-module-mall/citu-module-promotion-biz/src/main/java/com/citu/module/promotion/controller/admin/luck/vo/prize/LuckPrizeImportExcelVO.java

@@ -0,0 +1,64 @@
+package com.citu.module.promotion.controller.admin.luck.vo.prize;
+
+import com.alibaba.excel.annotation.ExcelIgnore;
+import com.alibaba.excel.annotation.ExcelProperty;
+import com.citu.module.promotion.enums.luck.LuckPrizeTypeEnum;
+import com.citu.module.promotion.enums.luck.LuckStatusEnum;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.experimental.Accessors;
+
+/**
+ * 抽奖奖品导入 Excel VO
+ */
+@Data
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+@Accessors(chain = false) // 设置 chain = false,避免用户导入有问题
+public class LuckPrizeImportExcelVO {
+
+    @ExcelProperty("活动名称")
+    private String lotteryName;
+
+    @ExcelProperty("奖品图片地址")
+    private String image;
+
+    @ExcelIgnore
+    @Schema(description = "奖品类型(1未中奖 2积分 3余额 4红包 5优惠券 6站内商品 7等级经验 8用户等级 9svip天数 99自定义)")
+    private String type = LuckPrizeTypeEnum.CUSTOM.getType();
+
+    @ExcelProperty("奖品名称")
+    private String name;
+
+    @ExcelProperty("中奖提示语")
+    private String prompt;
+
+    @ExcelProperty("中奖基数")
+    private Integer chance;
+
+    @ExcelProperty("奖品数量")
+    private Integer total;
+
+    @ExcelProperty("集团")
+    private String bloc;
+
+    @ExcelProperty("品牌")
+    private String brand;
+
+    @ExcelProperty("省份")
+    private String provinceName;
+
+    @ExcelProperty("城市")
+    private String cityName;
+
+    @ExcelProperty("地区")
+    private String districtName;
+
+    @ExcelIgnore
+    @Schema(description = "状态")
+    private String status = LuckStatusEnum.ENABLE.getStatus();
+}

+ 40 - 0
citu-module-mall/citu-module-promotion-biz/src/main/java/com/citu/module/promotion/controller/admin/luck/vo/prize/LuckPrizePageReqVO.java

@@ -0,0 +1,40 @@
+package com.citu.module.promotion.controller.admin.luck.vo.prize;
+
+
+import com.citu.framework.common.pojo.PageParam;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.time.LocalDateTime;
+
+import static com.citu.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
+
+@Schema(description = "管理后台 - 幸运抽奖-奖品分页 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class LuckPrizePageReqVO extends PageParam {
+
+    @Schema(description = "抽奖活动id", example = "15505")
+    private Long lotteryId;
+
+    @Schema(description = "奖品名称", example = "李四")
+    private String name;
+
+    @Schema(description = "奖品类型(1未中奖 2积分 3余额 4红包 5优惠券 6站内商品 7等级经验 8用户等级 9svip天数 99自定义)", example = "2")
+    private String type;
+
+    @Schema(description = "关联优惠券id", example = "26766")
+    private Long couponId;
+
+    @Schema(description = "关联商品id", example = "31375")
+    private Long productId;
+
+    @Schema(description = "创建时间")
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    private LocalDateTime[] createTime;
+
+}

+ 81 - 0
citu-module-mall/citu-module-promotion-biz/src/main/java/com/citu/module/promotion/controller/admin/luck/vo/prize/LuckPrizeRespVO.java

@@ -0,0 +1,81 @@
+package com.citu.module.promotion.controller.admin.luck.vo.prize;
+
+
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
+import com.alibaba.excel.annotation.ExcelProperty;
+import com.citu.module.promotion.dal.dataobject.luck.LuckPrizeExtend;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+@Schema(description = "管理后台 - 幸运抽奖-奖品 Response VO")
+@Data
+@ExcelIgnoreUnannotated
+public class LuckPrizeRespVO {
+
+    @Schema(description = "id", requiredMode = Schema.RequiredMode.REQUIRED, example = "30925")
+    @ExcelProperty("id")
+    private Long id;
+
+    @Schema(description = "抽奖活动id", requiredMode = Schema.RequiredMode.REQUIRED, example = "15505")
+    @ExcelProperty("抽奖活动id")
+    private Long lotteryId;
+
+    @Schema(description = "奖品名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四")
+    @ExcelProperty("奖品名称")
+    private String name;
+
+    @Schema(description = "奖品图片", requiredMode = Schema.RequiredMode.REQUIRED)
+    @ExcelProperty("奖品图片")
+    private String image;
+
+    @Schema(description = "奖品类型(1未中奖 2积分 3余额 4红包 5优惠券 6站内商品 7等级经验 8用户等级 9svip天数 99自定义)", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
+    @ExcelProperty("奖品类型(1未中奖 2积分 3余额 4红包 5优惠券 6站内商品 7等级经验 8用户等级 9svip天数 99自定义)")
+    private String type;
+
+    @Schema(description = "奖品扩展", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四")
+    @ExcelProperty("奖品扩展")
+    private LuckPrizeExtend extend;
+
+    @Schema(description = "中奖提示语", requiredMode = Schema.RequiredMode.REQUIRED)
+    @ExcelProperty("中奖提示语")
+    private String prompt;
+
+    @Schema(description = "中奖基数", requiredMode = Schema.RequiredMode.REQUIRED)
+    @ExcelProperty("中奖基数")
+    private Integer chance;
+
+    @Schema(description = "奖品数量")
+    @ExcelProperty("奖品数量")
+    private Integer total;
+
+    @Schema(description = "关联优惠券id", example = "26766")
+    @ExcelProperty("关联优惠券id")
+    private Long couponId;
+
+    @Schema(description = "关联商品id", example = "31375")
+    @ExcelProperty("关联商品id")
+    private Long productId;
+
+    @Schema(description = "关联商品规格唯一值")
+    @ExcelProperty("关联商品规格唯一值")
+    private String standard;
+
+    @Schema(description = "积分 经验 会员天数")
+    @ExcelProperty("积分 经验 会员天数")
+    private Integer num;
+
+    @Schema(description = "排序")
+    @ExcelProperty("排序")
+    private Integer sort;
+
+    @Schema(description = "状态", example = "2")
+    @ExcelProperty("状态")
+    private String status;
+
+    @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
+    @ExcelProperty("创建时间")
+    private LocalDateTime createTime;
+
+}

+ 72 - 0
citu-module-mall/citu-module-promotion-biz/src/main/java/com/citu/module/promotion/controller/admin/luck/vo/prize/LuckPrizeSaveReqVO.java

@@ -0,0 +1,72 @@
+package com.citu.module.promotion.controller.admin.luck.vo.prize;
+
+
+import com.citu.module.promotion.dal.dataobject.luck.LuckPrizeExtend;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+
+@Schema(description = "管理后台 - 幸运抽奖-奖品新增/修改 Request VO")
+@Data
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+public class LuckPrizeSaveReqVO {
+
+    @Schema(description = "id", requiredMode = Schema.RequiredMode.REQUIRED, example = "30925")
+    private Long id;
+
+    @Schema(description = "抽奖活动id", requiredMode = Schema.RequiredMode.REQUIRED, example = "15505")
+    @NotNull(message = "抽奖活动id不能为空")
+    private Long lotteryId;
+
+    @Schema(description = "奖品名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四")
+    @NotBlank(message = "奖品名称不能为空")
+    private String name;
+
+    @Schema(description = "奖品图片", requiredMode = Schema.RequiredMode.REQUIRED)
+    @NotBlank(message = "奖品图片不能为空")
+    private String image;
+
+    @Schema(description = "奖品类型(1未中奖 2积分 3余额 4红包 5优惠券 6站内商品 7等级经验 8用户等级 9svip天数 99自定义)", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
+    @NotBlank(message = "奖品类型(1未中奖 2积分 3余额 4红包 5优惠券 6站内商品 7等级经验 8用户等级 9svip天数 99自定义)不能为空")
+    private String type;
+
+    @Schema(description = "奖品扩展", example = "李四")
+    private LuckPrizeExtend extend;
+
+    @Schema(description = "中奖提示语", requiredMode = Schema.RequiredMode.REQUIRED)
+    @NotBlank(message = "中奖提示语不能为空")
+    private String prompt;
+
+    @Schema(description = "中奖基数", requiredMode = Schema.RequiredMode.REQUIRED)
+    @NotNull(message = "中奖基数不能为空")
+    private Integer chance;
+
+    @Schema(description = "奖品数量")
+    private Integer total;
+
+    @Schema(description = "关联优惠券id", example = "26766")
+    private Long couponId;
+
+    @Schema(description = "关联商品id", example = "31375")
+    private Long productId;
+
+    @Schema(description = "关联商品规格唯一值")
+    private String standard;
+
+    @Schema(description = "积分 经验 会员天数")
+    private Integer num;
+
+    @Schema(description = "排序")
+    private Integer sort = 1;
+
+    @Schema(description = "状态", example = "2")
+    private String status;
+
+}

+ 29 - 0
citu-module-mall/citu-module-promotion-biz/src/main/java/com/citu/module/promotion/controller/admin/luck/vo/record/LuckLotteryRecordDetailRespVO.java

@@ -0,0 +1,29 @@
+package com.citu.module.promotion.controller.admin.luck.vo.record;
+
+
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
+import com.citu.module.menduner.system.api.user.UserInfoRespDTO;
+import com.citu.module.promotion.controller.admin.luck.vo.LuckLotteryDetailRespVO;
+import com.citu.module.promotion.controller.admin.luck.vo.prize.LuckPrizeDetailRespVO;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+@Schema(description = "管理后台 - 幸运抽奖-抽奖记录 Response VO")
+@Data
+@ExcelIgnoreUnannotated
+public class LuckLotteryRecordDetailRespVO {
+
+    @Schema(description = "记录")
+    private LuckLotteryRecordRespVO record;
+
+    @Schema(description = "活动")
+    private LuckLotteryDetailRespVO lottery;
+
+    @Schema(description = "奖品")
+    private LuckPrizeDetailRespVO prize;
+
+    @Schema(description = "用户信息")
+    private UserInfoRespDTO user;
+
+
+}

+ 43 - 0
citu-module-mall/citu-module-promotion-biz/src/main/java/com/citu/module/promotion/controller/admin/luck/vo/record/LuckLotteryRecordPageReqVO.java

@@ -0,0 +1,43 @@
+package com.citu.module.promotion.controller.admin.luck.vo.record;
+
+
+import com.citu.framework.common.pojo.PageParam;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.time.LocalDateTime;
+
+import static com.citu.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
+
+@Schema(description = "管理后台 - 幸运抽奖-抽奖记录分页 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class LuckLotteryRecordPageReqVO extends PageParam {
+
+    @Schema(description = "用户id", example = "9325")
+    private Long userId;
+
+    @Schema(description = "活动id", example = "14605")
+    private Long lotteryId;
+
+    @Schema(description = "奖品id", example = "369")
+    private Long prizeId;
+
+    @Schema(description = "奖品类型(1未中奖 2积分 3余额 4红包 5优惠券 6站内商品 7等级经验 8用户等级 9svip天数 99自定义)", example = "1")
+    private String type;
+
+    @Schema(description = "是否领取")
+    private Boolean isReceive;
+
+    @Schema(description = "是否发货")
+    private Boolean isDeliver;
+
+    @Schema(description = "创建时间")
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    private LocalDateTime[] createTime;
+
+}

+ 68 - 0
citu-module-mall/citu-module-promotion-biz/src/main/java/com/citu/module/promotion/controller/admin/luck/vo/record/LuckLotteryRecordRespVO.java

@@ -0,0 +1,68 @@
+package com.citu.module.promotion.controller.admin.luck.vo.record;
+
+
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
+import com.alibaba.excel.annotation.ExcelProperty;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+@Schema(description = "管理后台 - 幸运抽奖-抽奖记录 Response VO")
+@Data
+@ExcelIgnoreUnannotated
+public class LuckLotteryRecordRespVO {
+
+    @Schema(description = "id", requiredMode = Schema.RequiredMode.REQUIRED, example = "6084")
+    @ExcelProperty("id")
+    private Long id;
+
+    @Schema(description = "用户id", requiredMode = Schema.RequiredMode.REQUIRED, example = "9325")
+    @ExcelProperty("用户id")
+    private Long userId;
+
+    @Schema(description = "活动id", requiredMode = Schema.RequiredMode.REQUIRED, example = "14605")
+    @ExcelProperty("活动id")
+    private Long lotteryId;
+
+    @Schema(description = "奖品id", requiredMode = Schema.RequiredMode.REQUIRED, example = "369")
+    @ExcelProperty("奖品id")
+    private Long prizeId;
+
+    @Schema(description = "奖品类型(1未中奖 2积分 3余额 4红包 5优惠券 6站内商品 7等级经验 8用户等级 9svip天数 99自定义)", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+    @ExcelProperty("奖品类型(1未中奖 2积分 3余额 4红包 5优惠券 6站内商品 7等级经验 8用户等级 9svip天数 99自定义)")
+    private String type;
+
+    @Schema(description = "奖品扩展", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四")
+    @ExcelProperty("奖品扩展")
+    private Object extend;
+
+    @Schema(description = "是否领取", requiredMode = Schema.RequiredMode.REQUIRED)
+    @ExcelProperty("是否领取")
+    private Boolean isReceive;
+
+    @Schema(description = "领取时间")
+    @ExcelProperty("领取时间")
+    private LocalDateTime receiveTime;
+
+    @Schema(description = "收获地址、备注等")
+    @ExcelProperty("收获地址、备注等")
+    private String receiveInfo;
+
+    @Schema(description = "是否发货", requiredMode = Schema.RequiredMode.REQUIRED)
+    @ExcelProperty("是否发货")
+    private Boolean isDeliver;
+
+    @Schema(description = "发货处理时间")
+    @ExcelProperty("发货处理时间")
+    private LocalDateTime deliverTime;
+
+    @Schema(description = "发货单号、备注等")
+    @ExcelProperty("发货单号、备注等")
+    private String deliverInfo;
+
+    @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
+    @ExcelProperty("创建时间")
+    private LocalDateTime createTime;
+
+}

+ 55 - 0
citu-module-mall/citu-module-promotion-biz/src/main/java/com/citu/module/promotion/controller/admin/luck/vo/record/LuckLotteryRecordSaveReqVO.java

@@ -0,0 +1,55 @@
+package com.citu.module.promotion.controller.admin.luck.vo.record;
+
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import javax.validation.constraints.NotEmpty;
+import javax.validation.constraints.NotNull;
+import java.time.LocalDateTime;
+
+@Schema(description = "管理后台 - 幸运抽奖-抽奖记录新增/修改 Request VO")
+@Data
+public class LuckLotteryRecordSaveReqVO {
+
+    @Schema(description = "id", requiredMode = Schema.RequiredMode.REQUIRED, example = "6084")
+    @NotNull(message = "id不能为空")
+    private Long id;
+
+    @Schema(description = "用户id", requiredMode = Schema.RequiredMode.REQUIRED, example = "9325")
+    private Long userId;
+
+    @Schema(description = "活动id", requiredMode = Schema.RequiredMode.REQUIRED, example = "14605")
+    private Long lotteryId;
+
+    @Schema(description = "奖品id", requiredMode = Schema.RequiredMode.REQUIRED, example = "369")
+    private Long prizeId;
+
+    @Schema(description = "奖品类型(1未中奖 2积分 3余额 4红包 5优惠券 6站内商品 7等级经验 8用户等级 9svip天数 99自定义)", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+    @NotEmpty(message = "奖品类型(1未中奖 2积分 3余额 4红包 5优惠券 6站内商品 7等级经验 8用户等级 9svip天数 99自定义)不能为空")
+    private String type;
+
+    @Schema(description = "奖品扩展", example = "李四")
+    private Object extend;
+
+    @Schema(description = "是否领取", requiredMode = Schema.RequiredMode.REQUIRED)
+    @NotNull(message = "是否领取不能为空")
+    private Boolean isReceive;
+
+    @Schema(description = "领取时间")
+    private LocalDateTime receiveTime;
+
+    @Schema(description = "收获地址、备注等")
+    private String receiveInfo;
+
+    @Schema(description = "是否发货", requiredMode = Schema.RequiredMode.REQUIRED)
+    @NotNull(message = "是否发货不能为空")
+    private Boolean isDeliver;
+
+    @Schema(description = "发货处理时间")
+    private LocalDateTime deliverTime;
+
+    @Schema(description = "发货单号、备注等")
+    private String deliverInfo;
+
+}

+ 55 - 0
citu-module-mall/citu-module-promotion-biz/src/main/java/com/citu/module/promotion/controller/app/luck/AppLuckLotteryController.java

@@ -0,0 +1,55 @@
+package com.citu.module.promotion.controller.app.luck;
+
+
+import com.citu.framework.common.pojo.CommonResult;
+import com.citu.framework.common.util.object.BeanUtils;
+import com.citu.module.promotion.controller.admin.luck.vo.LuckLotteryRespVO;
+import com.citu.module.promotion.dal.dataobject.luck.LuckLotteryDO;
+import com.citu.module.promotion.service.luck.LuckLotteryService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+import java.time.LocalDateTime;
+import java.util.List;
+
+import static com.citu.framework.common.pojo.CommonResult.success;
+
+@Tag(name = "用户 APP - 幸运抽奖-活动")
+@RestController
+@RequestMapping("/promotion/luck-lottery")
+@Validated
+public class AppLuckLotteryController {
+
+    @Resource
+    private LuckLotteryService luckLotteryService;
+
+
+    @GetMapping("/list")
+    @Operation(summary = "获得幸运抽奖活动分页")
+    public CommonResult<List<LuckLotteryRespVO>> getLuckLotteryList() {
+        LocalDateTime now = LocalDateTime.now();
+        // 当天开始时间和当天结束时间
+        LocalDateTime startTime = now.withHour(0).withMinute(0).withSecond(0);
+        LocalDateTime endTime = now.withHour(23).withMinute(59).withSecond(59);
+        List<LuckLotteryDO> pageResult = luckLotteryService.getLuckLotteryListByTime(startTime, endTime);
+        return success(BeanUtils.toBean(pageResult, LuckLotteryRespVO.class));
+    }
+
+    @GetMapping("/list2")
+    @Operation(summary = "获得幸运抽奖活动分页2")
+    public CommonResult<List<LuckLotteryRespVO>> getLuckLotteryList2(@RequestParam("spuId") Long spuId) {
+        LocalDateTime now = LocalDateTime.now();
+        // 当天开始时间和当天结束时间
+        LocalDateTime startTime = now.withHour(0).withMinute(0).withSecond(0);
+        LocalDateTime endTime = now.withHour(23).withMinute(59).withSecond(59);
+        List<LuckLotteryDO> pageResult = luckLotteryService.getLuckLotteryListByTime(spuId,startTime, endTime);
+        return success(BeanUtils.toBean(pageResult, LuckLotteryRespVO.class));
+    }
+
+}

+ 59 - 0
citu-module-mall/citu-module-promotion-biz/src/main/java/com/citu/module/promotion/controller/app/luck/AppLuckLotteryRecordController.java

@@ -0,0 +1,59 @@
+package com.citu.module.promotion.controller.app.luck;
+
+
+import com.citu.framework.common.pojo.CommonResult;
+import com.citu.framework.common.pojo.PageResult;
+import com.citu.framework.common.util.object.BeanUtils;
+import com.citu.framework.security.core.annotations.PreAuthenticated;
+import com.citu.module.promotion.controller.admin.luck.vo.record.LuckLotteryRecordDetailRespVO;
+import com.citu.module.promotion.controller.admin.luck.vo.record.LuckLotteryRecordPageReqVO;
+import com.citu.module.promotion.controller.admin.luck.vo.record.LuckLotteryRecordRespVO;
+import com.citu.module.promotion.dal.dataobject.luck.LuckLotteryRecordDO;
+import com.citu.module.promotion.service.luck.LuckLotteryRecordService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+import javax.validation.Valid;
+import java.util.List;
+
+import static com.citu.framework.common.pojo.CommonResult.success;
+import static com.citu.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
+
+@Tag(name = "用户 APP - 幸运抽奖-抽奖记录")
+@RestController
+@RequestMapping("/promotion/luck-lottery-record")
+@Validated
+public class AppLuckLotteryRecordController {
+
+    @Resource
+    private LuckLotteryRecordService luckLotteryRecordService;
+
+    @GetMapping("/page")
+    @Operation(summary = "抽奖记录分页")
+    public CommonResult<PageResult<LuckLotteryRecordDetailRespVO>> page
+            (@Valid LuckLotteryRecordPageReqVO pageReqVO) {
+        return success(luckLotteryRecordService.page(pageReqVO));
+    }
+
+    @GetMapping("/raffle")
+    @PreAuthenticated
+    @Operation(summary = "抽奖")
+    public CommonResult<LuckLotteryRecordRespVO> raffle
+            (@RequestParam("lotteryId") Long lotteryId) {
+        return success(luckLotteryRecordService.raffle(lotteryId, getLoginUserId()));
+    }
+
+    @GetMapping("/list")
+    @PreAuthenticated
+    @Operation(summary = "根据抽奖活动id获取当前用户抽奖记录")
+    public CommonResult<List<LuckLotteryRecordDetailRespVO>> getLuckLotteryRecordList
+            (@RequestParam("lotteryId") Long lotteryId) {
+        return success(luckLotteryRecordService.getLuckLotteryRecordList(lotteryId, getLoginUserId()));
+    }
+}

+ 22 - 0
citu-module-mall/citu-module-promotion-biz/src/main/java/com/citu/module/promotion/convert/luck/LuckLotteryConvert.java

@@ -0,0 +1,22 @@
+package com.citu.module.promotion.convert.luck;
+
+import com.citu.module.promotion.controller.admin.luck.vo.LuckLotteryDetailRespVO;
+import com.citu.module.promotion.controller.admin.luck.vo.LuckLotteryRespVO;
+import com.citu.module.promotion.dal.dataobject.luck.LuckLotteryDO;
+import org.mapstruct.Mapper;
+import org.mapstruct.factory.Mappers;
+
+/**
+ * 抽奖配置 Convert
+ *
+ * @author Rayson
+ */
+@Mapper
+public interface LuckLotteryConvert {
+
+    LuckLotteryConvert INSTANCE = Mappers.getMapper(LuckLotteryConvert.class);
+
+    LuckLotteryRespVO convert(LuckLotteryDO bean);
+
+    LuckLotteryDetailRespVO convert2(LuckLotteryDO bean);
+}

+ 32 - 0
citu-module-mall/citu-module-promotion-biz/src/main/java/com/citu/module/promotion/convert/luck/LuckLotteryRecordConvert.java

@@ -0,0 +1,32 @@
+package com.citu.module.promotion.convert.luck;
+
+import com.citu.module.menduner.system.api.user.UserInfoRespDTO;
+import com.citu.module.promotion.controller.admin.luck.vo.LuckLotteryDetailRespVO;
+import com.citu.module.promotion.controller.admin.luck.vo.prize.LuckPrizeDetailRespVO;
+import com.citu.module.promotion.controller.admin.luck.vo.record.LuckLotteryRecordDetailRespVO;
+import com.citu.module.promotion.controller.admin.luck.vo.record.LuckLotteryRecordRespVO;
+import com.citu.module.promotion.dal.dataobject.luck.LuckLotteryRecordDO;
+import org.mapstruct.Mapper;
+import org.mapstruct.factory.Mappers;
+
+import java.util.List;
+
+/**
+ * 抽奖记录 Convert
+ *
+ * @author Rayson
+ */
+@Mapper
+public interface LuckLotteryRecordConvert {
+
+    LuckLotteryRecordConvert INSTANCE = Mappers.getMapper(LuckLotteryRecordConvert.class);
+
+    LuckLotteryRecordRespVO convert(LuckLotteryRecordDO bean);
+
+    List<LuckLotteryRecordRespVO> convertList(List<LuckLotteryRecordDO> list);
+
+    LuckLotteryRecordDetailRespVO convertDetail(LuckLotteryRecordRespVO record,
+                                                LuckLotteryDetailRespVO lottery,
+                                                LuckPrizeDetailRespVO prize,
+                                                UserInfoRespDTO user);
+}

+ 25 - 0
citu-module-mall/citu-module-promotion-biz/src/main/java/com/citu/module/promotion/convert/luck/LuckPrizeConvert.java

@@ -0,0 +1,25 @@
+package com.citu.module.promotion.convert.luck;
+
+import com.citu.framework.common.pojo.PageResult;
+import com.citu.module.promotion.controller.admin.luck.vo.prize.LuckPrizeDetailRespVO;
+import com.citu.module.promotion.controller.admin.luck.vo.prize.LuckPrizeRespVO;
+import com.citu.module.promotion.dal.dataobject.luck.LuckPrizeDO;
+import org.mapstruct.Mapper;
+import org.mapstruct.factory.Mappers;
+
+/**
+ * 抽奖奖品 Convert
+ *
+ * @author Rayson
+ */
+@Mapper
+public interface LuckPrizeConvert {
+
+    LuckPrizeConvert INSTANCE = Mappers.getMapper(LuckPrizeConvert.class);
+
+    LuckPrizeRespVO convert(LuckPrizeDO bean);
+
+    LuckPrizeDetailRespVO convert2(LuckPrizeDO bean);
+
+    PageResult<LuckPrizeDetailRespVO> convertPage(PageResult<LuckPrizeDO> page);
+}

+ 131 - 0
citu-module-mall/citu-module-promotion-biz/src/main/java/com/citu/module/promotion/dal/dataobject/luck/LuckLotteryDO.java

@@ -0,0 +1,131 @@
+package com.citu.module.promotion.dal.dataobject.luck;
+
+
+import com.baomidou.mybatisplus.annotation.KeySequence;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
+import com.citu.framework.mybatis.core.dataobject.BaseDO;
+import lombok.*;
+
+import java.time.LocalDateTime;
+import java.util.List;
+
+/**
+ * 幸运抽奖-活动 DO
+ *
+ * @author Rayson
+ */
+@TableName(value = "promotion_luck_lottery", autoResultMap = true)
+@KeySequence("promotion_luck_lottery_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class LuckLotteryDO extends BaseDO {
+
+    /**
+     * id
+     */
+    @TableId
+    private Long id;
+    /**
+     * 奖品名称
+     */
+    private String name;
+    /**
+     * 类型(1九宫格 2大转盘 3九宫格升级版 4幸运翻牌)
+     */
+    private String type;
+    /**
+     * 抽奖消耗 (1积分 2余额 3下单支付成功 4关注 5订单评价 6指定商品下单支付成功)
+     */
+    private String factor;
+    /**
+     * 抽奖消耗信息
+     */
+    @TableField(typeHandler = JacksonTypeHandler.class)
+    private List<String> factorInfo;
+    /**
+     * 获取一次抽奖的条件数量
+     */
+    private Integer factorNum;
+    /**
+     * 活动描述
+     */
+    private String description;
+    /**
+     * 活动背景图
+     */
+    private String image;
+    /**
+     * 参与用户(1所有 2部分)
+     */
+    private String attendsUser;
+    /**
+     * 参与用户等级
+     */
+    @TableField(typeHandler = JacksonTypeHandler.class)
+    private List<Object> userLevel;
+    /**
+     * 参与用户标签
+     */
+    @TableField(typeHandler = JacksonTypeHandler.class)
+    private List<Object> userLabel;
+    /**
+     * 参与用户是否付费会员
+     */
+    private Boolean isSvip;
+    /**
+     * 奖品数量
+     */
+    private Integer prizeNum;
+    /**
+     * 开始时间
+     */
+    private LocalDateTime startTime;
+    /**
+     * 结束时间
+     */
+    private LocalDateTime endTime;
+    /**
+     * 抽奖次数限制(1每天 2每人)
+     */
+    private Integer lotteryNumTerm;
+    /**
+     * 抽奖次数
+     */
+    private Integer lotteryNum;
+    /**
+     * 关注推广获取抽奖次数
+     */
+    private Integer spreadNum;
+    /**
+     * 中奖记录展示
+     */
+    private Boolean isAllRecord;
+    /**
+     * 个人中奖记录展示
+     */
+    private Boolean isPersonalRecord;
+    /**
+     * 活动规格是否展示
+     */
+    private Boolean isContent;
+    /**
+     * 活动文案抽奖协议之类
+     */
+    private String content;
+    /**
+     * 排序
+     */
+    private Integer sort;
+    /**
+     * 状态
+     */
+    private String status;
+
+}

+ 80 - 0
citu-module-mall/citu-module-promotion-biz/src/main/java/com/citu/module/promotion/dal/dataobject/luck/LuckLotteryRecordDO.java

@@ -0,0 +1,80 @@
+package com.citu.module.promotion.dal.dataobject.luck;
+
+
+import com.baomidou.mybatisplus.annotation.KeySequence;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
+import com.citu.framework.mybatis.core.dataobject.BaseDO;
+import lombok.*;
+
+import java.time.LocalDateTime;
+
+/**
+ * 幸运抽奖-抽奖记录 DO
+ *
+ * @author Rayson
+ */
+@TableName(value ="promotion_luck_lottery_record", autoResultMap = true)
+@KeySequence("promotion_luck_lottery_record_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class LuckLotteryRecordDO extends BaseDO {
+
+    /**
+     * id
+     */
+    @TableId
+    private Long id;
+    /**
+     * 用户id
+     */
+    private Long userId;
+    /**
+     * 活动id
+     */
+    private Long lotteryId;
+    /**
+     * 奖品id
+     */
+    private Long prizeId;
+    /**
+     * 奖品类型(1未中奖 2积分 3余额 4红包 5优惠券 6站内商品 7等级经验 8用户等级 9svip天数 99自定义)
+     */
+    private String type;
+    /**
+     * 奖品扩展
+     */
+    @TableField(typeHandler = JacksonTypeHandler.class)
+    private Object extend;
+    /**
+     * 是否领取
+     */
+    private Boolean isReceive;
+    /**
+     * 领取时间
+     */
+    private LocalDateTime receiveTime;
+    /**
+     * 收获地址、备注等
+     */
+    private String receiveInfo;
+    /**
+     * 是否发货
+     */
+    private Boolean isDeliver;
+    /**
+     * 发货处理时间
+     */
+    private LocalDateTime deliverTime;
+    /**
+     * 发货单号、备注等
+     */
+    private String deliverInfo;
+
+}

+ 86 - 0
citu-module-mall/citu-module-promotion-biz/src/main/java/com/citu/module/promotion/dal/dataobject/luck/LuckPrizeDO.java

@@ -0,0 +1,86 @@
+package com.citu.module.promotion.dal.dataobject.luck;
+
+import com.baomidou.mybatisplus.annotation.*;
+import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
+import com.citu.framework.mybatis.core.dataobject.BaseDO;
+import lombok.*;
+
+/**
+ * 幸运抽奖-奖品 DO
+ *
+ * @author Rayson
+ */
+@TableName(value = "promotion_luck_prize", autoResultMap = true)
+@KeySequence("promotion_luck_prize_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class LuckPrizeDO extends BaseDO {
+
+    /**
+     * id
+     */
+    @TableId
+    private Long id;
+    /**
+     * 抽奖活动id
+     */
+    private Long lotteryId;
+    /**
+     * 奖品名称
+     */
+    private String name;
+    /**
+     * 奖品图片
+     */
+    private String image;
+    /**
+     * 奖品类型(1未中奖 2积分 3余额 4红包 5优惠券 6站内商品 7等级经验 8用户等级 9svip天数 99自定义)
+     */
+    private String type;
+    /**
+     * 奖品扩展
+     */
+    @TableField(updateStrategy = FieldStrategy.ALWAYS, typeHandler = JacksonTypeHandler.class)
+    private LuckPrizeExtend extend;
+    /**
+     * 中奖提示语
+     */
+    private String prompt;
+    /**
+     * 中奖基数
+     */
+    private Integer chance;
+    /**
+     * 奖品数量
+     */
+    private Integer total;
+    /**
+     * 关联优惠券id
+     */
+    private Long couponId;
+    /**
+     * 关联商品id
+     */
+    private Long productId;
+    /**
+     * 关联商品规格唯一值
+     */
+    private String standard;
+    /**
+     * 积分 经验 会员天数
+     */
+    private Integer num;
+    /**
+     * 排序
+     */
+    private Integer sort;
+    /**
+     * 状态
+     */
+    private String status;
+
+}

+ 38 - 0
citu-module-mall/citu-module-promotion-biz/src/main/java/com/citu/module/promotion/dal/dataobject/luck/LuckPrizeExtend.java

@@ -0,0 +1,38 @@
+package com.citu.module.promotion.dal.dataobject.luck;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+public class LuckPrizeExtend {
+
+    @Schema(description = "省份id")
+    private Long provinceId;
+
+    @Schema(description = "省份")
+    private String provinceName;
+
+    @Schema(description = "城市id")
+    private Long cityId;
+
+    @Schema(description = "城市")
+    private String cityName;
+
+    @Schema(description = "区域id")
+    private Long districtId;
+
+    @Schema(description = "区域")
+    private String districtName;
+
+    @Schema(description = "集团")
+    private String bloc;
+
+    @Schema(description = "品牌")
+    private String brand;
+}

+ 70 - 0
citu-module-mall/citu-module-promotion-biz/src/main/java/com/citu/module/promotion/dal/dataobject/luck/LuckPrizeExtendDO.java

@@ -0,0 +1,70 @@
+package com.citu.module.promotion.dal.dataobject.luck;
+
+import com.baomidou.mybatisplus.annotation.KeySequence;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.citu.framework.mybatis.core.dataobject.BaseDO;
+import lombok.*;
+
+/**
+ * 幸运抽奖-奖品夸张 DO
+ *
+ * @author Rayson
+ */
+@TableName(value = "promotion_luck_prize_extend", autoResultMap = true)
+@KeySequence("promotion_luck_prize_extend_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class LuckPrizeExtendDO extends BaseDO {
+
+    /**
+     * id
+     */
+    @TableId
+    private Long id;
+    /**
+     * 抽奖活动id
+     */
+    private Long lotteryId;
+    /**
+     * 奖品id
+     */
+    private Long luckPrizeId;
+    /**
+     * 省份id
+     */
+    private Long provinceId;
+    /**
+     * 省份
+     */
+    private String provinceName;
+    /**
+     * 城市id
+     */
+    private Long cityId;
+    /**
+     * 城市
+     */
+    private String cityName;
+    /**
+     * 区域id
+     */
+    private Long districtId;
+    /**
+     * 区域
+     */
+    private String districtName;
+    /**
+     * 集团
+     */
+    private String bloc;
+    /**
+     * 品牌
+     **/
+    private String brand;
+
+}

+ 77 - 0
citu-module-mall/citu-module-promotion-biz/src/main/java/com/citu/module/promotion/dal/mysql/luck/LuckLotteryMapper.java

@@ -0,0 +1,77 @@
+package com.citu.module.promotion.dal.mysql.luck;
+
+
+import com.citu.framework.common.pojo.PageResult;
+import com.citu.framework.mybatis.core.mapper.BaseMapperX;
+import com.citu.framework.mybatis.core.query.LambdaQueryWrapperX;
+import com.citu.module.promotion.controller.admin.luck.vo.LuckLotteryPageReqVO;
+import com.citu.module.promotion.dal.dataobject.luck.LuckLotteryDO;
+import com.citu.module.promotion.enums.luck.LuckStatusEnum;
+import org.apache.ibatis.annotations.Mapper;
+
+import java.time.LocalDateTime;
+import java.util.List;
+
+/**
+ * 幸运抽奖-活动 Mapper
+ *
+ * @author Rayson
+ */
+@Mapper
+public interface LuckLotteryMapper extends BaseMapperX<LuckLotteryDO> {
+
+    default PageResult<LuckLotteryDO> selectPage(LuckLotteryPageReqVO reqVO) {
+        return selectPage(reqVO, new LambdaQueryWrapperX<LuckLotteryDO>()
+                .likeIfPresent(LuckLotteryDO::getName, reqVO.getName())
+                .eqIfPresent(LuckLotteryDO::getType, reqVO.getType())
+                .eqIfPresent(LuckLotteryDO::getFactor, reqVO.getFactor())
+                .eqIfPresent(LuckLotteryDO::getFactorNum, reqVO.getFactorNum())
+                .eqIfPresent(LuckLotteryDO::getAttendsUser, reqVO.getAttendsUser())
+                .eqIfPresent(LuckLotteryDO::getIsSvip, reqVO.getIsSvip())
+                .betweenIfPresent(LuckLotteryDO::getStartTime, reqVO.getStartTime())
+                .betweenIfPresent(LuckLotteryDO::getEndTime, reqVO.getEndTime())
+                .eqIfPresent(LuckLotteryDO::getIsAllRecord, reqVO.getIsAllRecord())
+                .eqIfPresent(LuckLotteryDO::getIsPersonalRecord, reqVO.getIsPersonalRecord())
+                .eqIfPresent(LuckLotteryDO::getIsContent, reqVO.getIsContent())
+                .eqIfPresent(LuckLotteryDO::getSort, reqVO.getSort())
+                .eqIfPresent(LuckLotteryDO::getStatus, reqVO.getStatus())
+                .betweenIfPresent(LuckLotteryDO::getCreateTime, reqVO.getCreateTime())
+                .orderByDesc(LuckLotteryDO::getSort));
+    }
+
+    /**
+     * 获得时间段内有效的抽奖活动
+     *
+     * @param startTime 开始时间
+     * @param endTime   结束时间
+     */
+    default List<LuckLotteryDO> getLuckLotteryListByTime(LocalDateTime startTime, LocalDateTime endTime) {
+        return selectList(new LambdaQueryWrapperX<LuckLotteryDO>()
+                .le(LuckLotteryDO::getStartTime, startTime)
+                .ge(LuckLotteryDO::getEndTime, endTime)
+                .eq(LuckLotteryDO::getStatus, LuckStatusEnum.ENABLE.getStatus())
+                .orderByDesc(LuckLotteryDO::getSort));
+    }
+
+    /**
+     * 获得时间段内有效的抽奖活动
+     *
+     * @param startTime 开始时间
+     * @param endTime   结束时间
+     */
+    default List<LuckLotteryDO> getLuckLotteryListByTime(Long id,LocalDateTime startTime, LocalDateTime endTime) {
+        return selectList(new LambdaQueryWrapperX<LuckLotteryDO>()
+                .le(LuckLotteryDO::getStartTime, startTime)
+                .ge(LuckLotteryDO::getEndTime, endTime)
+                .eq(LuckLotteryDO::getStatus, LuckStatusEnum.ENABLE.getStatus())
+                .apply("JSON_CONTAINS(factor_info, '\""+id+"\"')")
+                .orderByDesc(LuckLotteryDO::getSort));
+    }
+
+
+    default LuckLotteryDO selectByName(String name) {
+        return selectOne(new LambdaQueryWrapperX<LuckLotteryDO>()
+                .eq(LuckLotteryDO::getName, name));
+    }
+
+}

+ 41 - 0
citu-module-mall/citu-module-promotion-biz/src/main/java/com/citu/module/promotion/dal/mysql/luck/LuckLotteryRecordMapper.java

@@ -0,0 +1,41 @@
+package com.citu.module.promotion.dal.mysql.luck;
+
+
+import com.citu.framework.common.pojo.PageResult;
+import com.citu.framework.mybatis.core.mapper.BaseMapperX;
+import com.citu.framework.mybatis.core.query.LambdaQueryWrapperX;
+import com.citu.module.promotion.controller.admin.luck.vo.record.LuckLotteryRecordPageReqVO;
+import com.citu.module.promotion.dal.dataobject.luck.LuckLotteryRecordDO;
+import org.apache.ibatis.annotations.Mapper;
+
+import java.util.List;
+
+/**
+ * 幸运抽奖-抽奖记录 Mapper
+ *
+ * @author Rayson
+ */
+@Mapper
+public interface LuckLotteryRecordMapper extends BaseMapperX<LuckLotteryRecordDO> {
+
+    default PageResult<LuckLotteryRecordDO> selectPage(LuckLotteryRecordPageReqVO reqVO) {
+        return selectPage(reqVO, new LambdaQueryWrapperX<LuckLotteryRecordDO>()
+                .eqIfPresent(LuckLotteryRecordDO::getUserId, reqVO.getUserId())
+                .eqIfPresent(LuckLotteryRecordDO::getLotteryId, reqVO.getLotteryId())
+                .eqIfPresent(LuckLotteryRecordDO::getPrizeId, reqVO.getPrizeId())
+                .eqIfPresent(LuckLotteryRecordDO::getType, reqVO.getType())
+                .eqIfPresent(LuckLotteryRecordDO::getIsReceive, reqVO.getIsReceive())
+                .eqIfPresent(LuckLotteryRecordDO::getIsDeliver, reqVO.getIsDeliver())
+                .betweenIfPresent(LuckLotteryRecordDO::getCreateTime, reqVO.getCreateTime())
+                .orderByDesc(LuckLotteryRecordDO::getId));
+    }
+
+    /** 查询指定抽奖活动id和用户id的记录列表 */
+    default List<LuckLotteryRecordDO> selectListByLotteryIdAndUserId(Long lotteryId, Long userId) {
+        return selectList(new LambdaQueryWrapperX<LuckLotteryRecordDO>()
+                .eq(LuckLotteryRecordDO::getLotteryId, lotteryId)
+                .eq(LuckLotteryRecordDO::getUserId, userId)
+        );
+    }
+
+}

+ 22 - 0
citu-module-mall/citu-module-promotion-biz/src/main/java/com/citu/module/promotion/dal/mysql/luck/LuckPrizeExtendMapper.java

@@ -0,0 +1,22 @@
+package com.citu.module.promotion.dal.mysql.luck;
+
+import com.citu.framework.mybatis.core.mapper.BaseMapperX;
+import com.citu.module.promotion.dal.dataobject.luck.LuckPrizeExtendDO;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * 幸运抽奖-奖品扩展 Mapper
+ *
+ * @author Rayson
+ */
+@Mapper
+public interface LuckPrizeExtendMapper extends BaseMapperX<LuckPrizeExtendDO> {
+
+    default LuckPrizeExtendDO selectByLuckPrizeId(Long luckPrizeId) {
+        return selectOne(LuckPrizeExtendDO::getLuckPrizeId, luckPrizeId);
+    }
+
+    default int deleteByLuckPrizeId(Long luckPrizeId) {
+        return delete(LuckPrizeExtendDO::getLuckPrizeId, luckPrizeId);
+    }
+}

+ 46 - 0
citu-module-mall/citu-module-promotion-biz/src/main/java/com/citu/module/promotion/dal/mysql/luck/LuckPrizeMapper.java

@@ -0,0 +1,46 @@
+package com.citu.module.promotion.dal.mysql.luck;
+
+
+import com.citu.framework.common.pojo.PageResult;
+import com.citu.framework.mybatis.core.mapper.BaseMapperX;
+import com.citu.framework.mybatis.core.query.LambdaQueryWrapperX;
+import com.citu.module.promotion.controller.admin.luck.vo.prize.LuckPrizePageReqVO;
+import com.citu.module.promotion.dal.dataobject.luck.LuckPrizeDO;
+import com.citu.module.promotion.enums.luck.LuckStatusEnum;
+import org.apache.ibatis.annotations.Mapper;
+
+import java.util.List;
+
+/**
+ * 幸运抽奖-奖品 Mapper
+ *
+ * @author Rayson
+ */
+@Mapper
+public interface LuckPrizeMapper extends BaseMapperX<LuckPrizeDO> {
+
+    default PageResult<LuckPrizeDO> selectPage(LuckPrizePageReqVO reqVO) {
+        return selectPage(reqVO, new LambdaQueryWrapperX<LuckPrizeDO>()
+                .eqIfPresent(LuckPrizeDO::getLotteryId, reqVO.getLotteryId())
+                .likeIfPresent(LuckPrizeDO::getName, reqVO.getName())
+                .eqIfPresent(LuckPrizeDO::getType, reqVO.getType())
+                .eqIfPresent(LuckPrizeDO::getCouponId, reqVO.getCouponId())
+                .eqIfPresent(LuckPrizeDO::getProductId, reqVO.getProductId())
+                .betweenIfPresent(LuckPrizeDO::getCreateTime, reqVO.getCreateTime())
+                .orderByDesc(LuckPrizeDO::getSort));
+    }
+
+    default List<LuckPrizeDO> getListByLotteryId(Long lotteryId) {
+        return selectList(new LambdaQueryWrapperX<LuckPrizeDO>()
+                .eq(LuckPrizeDO::getLotteryId, lotteryId)
+                .eq(LuckPrizeDO::getStatus, LuckStatusEnum.ENABLE.getStatus())
+                .orderByDesc(LuckPrizeDO::getSort)
+        );
+    }
+    default LuckPrizeDO selectByName(String name){
+        return selectOne(new LambdaQueryWrapperX<LuckPrizeDO>()
+                .eq(LuckPrizeDO::getName, name)
+        );
+    }
+
+}

+ 4 - 0
citu-module-mall/citu-module-promotion-biz/src/main/java/com/citu/module/promotion/framework/rpc/config/RpcConfiguration.java

@@ -2,6 +2,9 @@ package com.citu.module.promotion.framework.rpc.config;
 
 import com.citu.module.infra.api.websocket.WebSocketSenderApi;
 import com.citu.module.member.api.user.MemberUserApi;
+import com.citu.module.menduner.system.api.area.MendunerAreaApi;
+import com.citu.module.menduner.system.api.url.MendunerSystemUrlApi;
+import com.citu.module.menduner.system.api.user.MendunerUserApi;
 import com.citu.module.product.api.category.ProductCategoryApi;
 import com.citu.module.product.api.sku.ProductSkuApi;
 import com.citu.module.product.api.spu.ProductSpuApi;
@@ -14,6 +17,7 @@ import org.springframework.context.annotation.Configuration;
 @Configuration(proxyBeanMethods = false)
 @EnableFeignClients(clients = {ProductSkuApi.class, ProductSpuApi.class, ProductCategoryApi.class,
         MemberUserApi.class, TradeOrderApi.class, AdminUserApi.class, SocialClientApi.class,
+        MendunerUserApi.class, MendunerAreaApi.class,
         WebSocketSenderApi.class})
 public class RpcConfiguration {
 }

+ 82 - 0
citu-module-mall/citu-module-promotion-biz/src/main/java/com/citu/module/promotion/service/luck/LuckLotteryRecordService.java

@@ -0,0 +1,82 @@
+package com.citu.module.promotion.service.luck;
+
+
+import com.citu.framework.common.pojo.PageResult;
+import com.citu.module.promotion.controller.admin.luck.vo.record.LuckLotteryRecordDetailRespVO;
+import com.citu.module.promotion.controller.admin.luck.vo.record.LuckLotteryRecordPageReqVO;
+import com.citu.module.promotion.controller.admin.luck.vo.record.LuckLotteryRecordRespVO;
+import com.citu.module.promotion.controller.admin.luck.vo.record.LuckLotteryRecordSaveReqVO;
+import com.citu.module.promotion.dal.dataobject.luck.LuckLotteryRecordDO;
+
+import javax.validation.Valid;
+import java.util.List;
+
+/**
+ * 幸运抽奖-抽奖记录 Service 接口
+ *
+ * @author Rayson
+ */
+public interface LuckLotteryRecordService {
+
+    /**
+     * 创建幸运抽奖-抽奖记录
+     *
+     * @param createReqVO 创建信息
+     * @return 编号
+     */
+    Long createLuckLotteryRecord(@Valid LuckLotteryRecordSaveReqVO createReqVO);
+
+    /**
+     * 更新幸运抽奖-抽奖记录
+     *
+     * @param updateReqVO 更新信息
+     */
+    void updateLuckLotteryRecord(@Valid LuckLotteryRecordSaveReqVO updateReqVO);
+
+    /**
+     * 删除幸运抽奖-抽奖记录
+     *
+     * @param id 编号
+     */
+    void deleteLuckLotteryRecord(Long id);
+
+    /**
+     * 获得幸运抽奖-抽奖记录
+     *
+     * @param id 编号
+     * @return 幸运抽奖-抽奖记录
+     */
+    LuckLotteryRecordDO getLuckLotteryRecord(Long id);
+
+    /**
+     * 获得幸运抽奖-抽奖记录分页
+     *
+     * @param pageReqVO 分页查询
+     * @return 幸运抽奖-抽奖记录分页
+     */
+    PageResult<LuckLotteryRecordDO> getLuckLotteryRecordPage(LuckLotteryRecordPageReqVO pageReqVO);
+
+    /**
+     * 抽奖
+     * @param lotteryId 抽奖活动id
+     * @param userId 抽奖用户
+     */
+    LuckLotteryRecordRespVO raffle(Long lotteryId,Long userId);
+
+
+    /**
+     * 获取用户抽奖记录
+     * @param lotteryId 抽奖活动id
+     * @param userId 抽奖用户
+     */
+    List<LuckLotteryRecordDetailRespVO> getLuckLotteryRecordList(Long lotteryId, Long userId);
+
+    /**
+     * 获取用户抽奖记录分页
+     * @param pageReqVO 分页查询
+     * @return 幸运抽奖-抽奖记录分页
+     */
+    PageResult<LuckLotteryRecordDetailRespVO> page(LuckLotteryRecordPageReqVO pageReqVO);
+
+
+}

+ 198 - 0
citu-module-mall/citu-module-promotion-biz/src/main/java/com/citu/module/promotion/service/luck/LuckLotteryRecordServiceImpl.java

@@ -0,0 +1,198 @@
+package com.citu.module.promotion.service.luck;
+
+import cn.hutool.core.collection.CollUtil;
+import com.baomidou.lock.annotation.Lock4j;
+import com.citu.framework.common.pojo.PageResult;
+import com.citu.framework.common.util.object.BeanUtils;
+import com.citu.module.menduner.system.api.user.MendunerUserApi;
+import com.citu.module.menduner.system.api.user.UserInfoRespDTO;
+import com.citu.module.promotion.controller.admin.luck.vo.record.LuckLotteryRecordDetailRespVO;
+import com.citu.module.promotion.controller.admin.luck.vo.record.LuckLotteryRecordPageReqVO;
+import com.citu.module.promotion.controller.admin.luck.vo.record.LuckLotteryRecordRespVO;
+import com.citu.module.promotion.controller.admin.luck.vo.record.LuckLotteryRecordSaveReqVO;
+import com.citu.module.promotion.convert.luck.LuckLotteryRecordConvert;
+import com.citu.module.promotion.dal.dataobject.luck.LuckLotteryDO;
+import com.citu.module.promotion.dal.dataobject.luck.LuckLotteryRecordDO;
+import com.citu.module.promotion.dal.dataobject.luck.LuckPrizeDO;
+import com.citu.module.promotion.dal.mysql.luck.LuckLotteryRecordMapper;
+import org.springframework.stereotype.Service;
+import org.springframework.validation.annotation.Validated;
+
+import javax.annotation.Resource;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Random;
+import java.util.concurrent.ThreadLocalRandom;
+import java.util.stream.Collectors;
+
+import static com.citu.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static com.citu.module.promotion.enums.ErrorCodeConstants.LUCK_LOTTERY_RECORD_NOT_EXISTS;
+
+/**
+ * 幸运抽奖-抽奖记录 Service 实现类
+ *
+ * @author Rayson
+ */
+@Service
+@Validated
+public class LuckLotteryRecordServiceImpl implements LuckLotteryRecordService {
+
+    @Resource
+    private LuckLotteryRecordMapper luckLotteryRecordMapper;
+
+    @Resource
+    private LuckLotteryService luckLotteryService;
+
+    @Resource
+    private LuckPrizeService luckPrizeService;
+
+    @Resource
+    private MendunerUserApi mendunerUserApi;
+
+
+    @Override
+    public Long createLuckLotteryRecord(LuckLotteryRecordSaveReqVO createReqVO) {
+        // 插入
+        LuckLotteryRecordDO luckLotteryRecord = BeanUtils.toBean(createReqVO, LuckLotteryRecordDO.class);
+        luckLotteryRecordMapper.insert(luckLotteryRecord);
+        // 返回
+        return luckLotteryRecord.getId();
+    }
+
+    @Override
+    public void updateLuckLotteryRecord(LuckLotteryRecordSaveReqVO updateReqVO) {
+        // 校验存在
+        validateLuckLotteryRecordExists(updateReqVO.getId());
+        // 更新
+        LuckLotteryRecordDO updateObj = BeanUtils.toBean(updateReqVO, LuckLotteryRecordDO.class);
+        luckLotteryRecordMapper.updateById(updateObj);
+    }
+
+    @Override
+    public void deleteLuckLotteryRecord(Long id) {
+        // 校验存在
+        validateLuckLotteryRecordExists(id);
+        // 删除
+        luckLotteryRecordMapper.deleteById(id);
+    }
+
+    private void validateLuckLotteryRecordExists(Long id) {
+        if (luckLotteryRecordMapper.selectById(id) == null) {
+            throw exception(LUCK_LOTTERY_RECORD_NOT_EXISTS);
+        }
+    }
+
+    @Override
+    public LuckLotteryRecordDO getLuckLotteryRecord(Long id) {
+        return luckLotteryRecordMapper.selectById(id);
+    }
+
+    @Override
+    public PageResult<LuckLotteryRecordDO> getLuckLotteryRecordPage(LuckLotteryRecordPageReqVO pageReqVO) {
+        return luckLotteryRecordMapper.selectPage(pageReqVO);
+    }
+
+    @Override
+    @Lock4j(keys = {"#lotteryId", "#userId"}, acquireTimeout = 6000)
+    public LuckLotteryRecordRespVO raffle(Long lotteryId, Long userId) {
+        // 获取活动
+        LuckLotteryDO luckLottery = luckLotteryService.valid(lotteryId);
+
+        // TODO 待效验抽奖次数 根据抽奖记录和LuckLotteryDO对象的lotteryNumTerm和lotteryNum判断
+
+        // 获取奖品
+        List<LuckPrizeDO> luckPrizeList = luckPrizeService.getListByLotteryId(luckLottery.getId());
+
+        // 计算总权重并随机选择奖品
+        int totalWeight = luckPrizeList.stream().mapToInt(prize -> prize.getChance() * prize.getTotal()).sum();
+        Random random = ThreadLocalRandom.current();
+        int randomNumber = random.nextInt(totalWeight);
+
+        LuckPrizeDO selectedPrize = luckPrizeService.selectPrizeByWeight(randomNumber, luckPrizeList);
+
+        // 扣除奖品剩余数量
+        if (null == selectedPrize) {
+            // 炸了
+            return null;
+        }
+
+        if (selectedPrize.getTotal() <= 0) {
+            // 没数了
+            return null;
+        }
+
+        selectedPrize.setTotal(selectedPrize.getTotal() - 1);
+        luckPrizeService.updateById(selectedPrize);
+
+        // 插入抽奖记录
+        LuckLotteryRecordDO luckLotteryRecord = LuckLotteryRecordDO.builder()
+                .userId(userId)
+                .lotteryId(lotteryId)
+                .prizeId(selectedPrize.getId())
+                .type(selectedPrize.getType())
+                .extend(selectedPrize.getExtend())
+                .isReceive(false)
+                .isDeliver(false)
+                .build();
+        luckLotteryRecordMapper.insert(luckLotteryRecord);
+        return LuckLotteryRecordConvert.INSTANCE.convert(luckLotteryRecord);
+    }
+
+
+
+    @Override
+    public List<LuckLotteryRecordDetailRespVO> getLuckLotteryRecordList(Long lotteryId, Long userId) {
+        // 查询记录
+        List<LuckLotteryRecordDO> luckLotteryRecordList =
+                luckLotteryRecordMapper.selectListByLotteryIdAndUserId(lotteryId, userId);
+        if (CollUtil.isEmpty(luckLotteryRecordList)) {
+            return null;
+        }
+        List<LuckLotteryRecordDetailRespVO> list = new ArrayList<>();
+        // 查询用户
+        UserInfoRespDTO user = mendunerUserApi.getUser(userId).getCheckedData();
+        for (LuckLotteryRecordDO record : luckLotteryRecordList) {
+
+            list.add(LuckLotteryRecordConvert.INSTANCE.convertDetail(
+                    LuckLotteryRecordConvert.INSTANCE.convert(record),
+                    luckLotteryService.detail(record.getLotteryId()),
+                    luckPrizeService.detail(record.getPrizeId()),
+                    user)
+            );
+        }
+        return list;
+    }
+
+    @Override
+    public PageResult<LuckLotteryRecordDetailRespVO> page(LuckLotteryRecordPageReqVO pageReqVO) {
+        PageResult<LuckLotteryRecordDO> pageResult = luckLotteryRecordMapper.selectPage(pageReqVO);
+        if (CollUtil.isEmpty(pageResult.getList())) {
+            return null;
+        }
+        PageResult<LuckLotteryRecordDetailRespVO> result = new PageResult<>();
+        result.setTotal(pageResult.getTotal());
+        List<LuckLotteryRecordDetailRespVO> list = new ArrayList<>();
+
+        // 转成userId集合批量查询
+        List<Long> userIdList = pageResult.getList().stream().distinct()
+                .map(LuckLotteryRecordDO::getUserId).collect(Collectors.toList());
+        // 查询
+        List<UserInfoRespDTO> user = mendunerUserApi.getUserList(userIdList).getCheckedData();
+        for (LuckLotteryRecordDO record : pageResult.getList()) {
+            // 查询数据拼接对象
+            LuckLotteryRecordDetailRespVO resp = LuckLotteryRecordConvert.INSTANCE.convertDetail(
+                    LuckLotteryRecordConvert.INSTANCE.convert(record),
+                    luckLotteryService.detail(record.getLotteryId()),
+                    luckPrizeService.detail(record.getPrizeId()),
+                    user.stream().filter(userInfo ->
+                            userInfo.getUserId().equals(record.getUserId())
+                    ).findFirst().orElse(null)
+            );
+            list.add(resp);
+        }
+
+        result.setList(list);
+
+        return result;
+    }
+}

+ 94 - 0
citu-module-mall/citu-module-promotion-biz/src/main/java/com/citu/module/promotion/service/luck/LuckLotteryService.java

@@ -0,0 +1,94 @@
+package com.citu.module.promotion.service.luck;
+
+import com.citu.framework.common.pojo.PageResult;
+import com.citu.module.promotion.controller.admin.luck.vo.LuckLotteryDetailRespVO;
+import com.citu.module.promotion.controller.admin.luck.vo.LuckLotteryPageReqVO;
+import com.citu.module.promotion.controller.admin.luck.vo.LuckLotterySaveReqVO;
+import com.citu.module.promotion.dal.dataobject.luck.LuckLotteryDO;
+
+import javax.validation.Valid;
+import java.time.LocalDateTime;
+import java.util.List;
+
+/**
+ * 幸运抽奖-活动 Service 接口
+ *
+ * @author Rayson
+ */
+public interface LuckLotteryService {
+
+    /**
+     * 创建幸运抽奖-活动
+     *
+     * @param createReqVO 创建信息
+     * @return 编号
+     */
+    Long createLuckLottery(@Valid LuckLotterySaveReqVO createReqVO);
+
+    /**
+     * 更新幸运抽奖-活动
+     *
+     * @param updateReqVO 更新信息
+     */
+    void updateLuckLottery(@Valid LuckLotterySaveReqVO updateReqVO);
+
+    /**
+     * 删除幸运抽奖-活动
+     *
+     * @param id 编号
+     */
+    void deleteLuckLottery(Long id);
+
+    /**
+     * 获得幸运抽奖-活动
+     *
+     * @param id 编号
+     * @return 幸运抽奖-活动
+     */
+    LuckLotteryDO getLuckLottery(Long id);
+
+    /**
+     * 获得幸运抽奖-活动
+     *
+     * @param id 编号
+     * @return 幸运抽奖-活动
+     */
+    LuckLotteryDO valid(Long id);
+
+    /**
+     * 获得幸运抽奖-活动详情
+     *
+     * @param id 编号
+     * @return 幸运抽奖-活动详情
+     */
+    LuckLotteryDetailRespVO detail(Long id);
+
+    /**
+     * 获得幸运抽奖-活动分页
+     *
+     * @param pageReqVO 分页查询
+     * @return 幸运抽奖-活动分页
+     */
+    PageResult<LuckLotteryDO> getLuckLotteryPage(LuckLotteryPageReqVO pageReqVO);
+
+    /**
+     * 获得时间段内有效的抽奖活动
+     * @param startTime 开始时间
+     * @param endTime 结束时间
+     */
+    List<LuckLotteryDO> getLuckLotteryListByTime(LocalDateTime startTime, LocalDateTime endTime);
+
+    /**
+     * 获得时间段内有效的抽奖活动
+     * @param spuId 商品id
+     * @param startTime 开始时间
+     * @param endTime 结束时间
+     */
+    List<LuckLotteryDO> getLuckLotteryListByTime(Long spuId,LocalDateTime startTime, LocalDateTime endTime);
+
+    /**
+     * 获得抽奖活动
+     * @param name 活动名称
+     */
+    LuckLotteryDO getByName(String name);
+}

+ 143 - 0
citu-module-mall/citu-module-promotion-biz/src/main/java/com/citu/module/promotion/service/luck/LuckLotteryServiceImpl.java

@@ -0,0 +1,143 @@
+package com.citu.module.promotion.service.luck;
+
+
+import com.citu.framework.common.pojo.PageResult;
+import com.citu.framework.common.util.object.BeanUtils;
+import com.citu.module.product.api.spu.ProductSpuApi;
+import com.citu.module.product.api.spu.dto.ProductSpuRespDTO;
+import com.citu.module.promotion.controller.admin.luck.vo.LuckLotteryDetailRespVO;
+import com.citu.module.promotion.controller.admin.luck.vo.LuckLotteryPageReqVO;
+import com.citu.module.promotion.controller.admin.luck.vo.LuckLotterySaveReqVO;
+import com.citu.module.promotion.convert.luck.LuckLotteryConvert;
+import com.citu.module.promotion.dal.dataobject.luck.LuckLotteryDO;
+import com.citu.module.promotion.dal.mysql.luck.LuckLotteryMapper;
+import com.citu.module.promotion.enums.luck.LuckLotteryFactorEnum;
+import org.springframework.stereotype.Service;
+import org.springframework.validation.annotation.Validated;
+
+import javax.annotation.Resource;
+import java.time.LocalDateTime;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import static com.citu.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static com.citu.module.promotion.enums.ErrorCodeConstants.*;
+
+/**
+ * 幸运抽奖-活动 Service 实现类
+ *
+ * @author Rayson
+ */
+@Service
+@Validated
+public class LuckLotteryServiceImpl implements LuckLotteryService {
+
+    @Resource
+    private LuckLotteryMapper luckLotteryMapper;
+
+    @Resource
+    private ProductSpuApi productSpuApi;
+
+    @Override
+    public Long createLuckLottery(LuckLotterySaveReqVO createReqVO) {
+        // 插入
+        LuckLotteryDO luckLotteryDO = luckLotteryMapper.selectByName(createReqVO.getName());
+        if (null != luckLotteryDO) {
+            throw exception(LUCK_LOTTERY_NAME_USED, createReqVO.getName());
+        }
+        LuckLotteryDO luckLottery = BeanUtils.toBean(createReqVO, LuckLotteryDO.class);
+        luckLotteryMapper.insert(luckLottery);
+        // 返回
+        return luckLottery.getId();
+    }
+
+    @Override
+    public void updateLuckLottery(LuckLotterySaveReqVO updateReqVO) {
+        // 校验存在
+        validateLuckLotteryExists(updateReqVO.getId());
+        // 更新
+        LuckLotteryDO updateObj = BeanUtils.toBean(updateReqVO, LuckLotteryDO.class);
+        luckLotteryMapper.updateById(updateObj);
+    }
+
+    @Override
+    public void deleteLuckLottery(Long id) {
+        // 校验存在
+        validateLuckLotteryExists(id);
+        // 删除
+        luckLotteryMapper.deleteById(id);
+    }
+
+    private LuckLotteryDO validateLuckLotteryExists(Long id) {
+        LuckLotteryDO luckLottery = luckLotteryMapper.selectById(id);
+        if (null == luckLottery) {
+            throw exception(LUCK_LOTTERY_NOT_EXISTS);
+        }
+        return luckLottery;
+    }
+
+    @Override
+    public LuckLotteryDO getLuckLottery(Long id) {
+        return validateLuckLotteryExists(id);
+    }
+
+    @Override
+    public LuckLotteryDO valid(Long id) {
+        LuckLotteryDO luckLottery = validateLuckLotteryExists(id);
+        LocalDateTime now = LocalDateTime.now();
+        // 判断活动有没有开始,没有开始抛出异常
+        if (luckLottery.getStartTime().isAfter(now)) {
+            throw exception(LUCK_LOTTERY_NOT_START);
+        }
+        // 判断活动有没有结束,结束抛出异常
+        if (luckLottery.getEndTime().isBefore(now)) {
+            throw exception(LUCK_LOTTERY_END);
+        }
+        return luckLottery;
+    }
+
+    @Override
+    public LuckLotteryDetailRespVO detail(Long id) {
+        LuckLotteryDO luckLottery = valid(id);
+        LuckLotteryDetailRespVO resp = LuckLotteryConvert.INSTANCE.convert2(luckLottery);
+
+        // 下单指定商品支付成功类型
+        if (LuckLotteryFactorEnum.ORDER_PRODUCT_PAY_SUCCESS
+                .getFactor().equals(luckLottery.getFactor())) {
+            // 获取商品信息
+            List<ProductSpuRespDTO> productSpuRespDTOList =
+                    productSpuApi.getSpuList(
+                            luckLottery.getFactorInfo().stream()
+                                    .map(Long::parseLong)
+                                    .collect(Collectors.toList()
+                                    )
+                    ).getCheckedData();
+            resp.setSpuList(productSpuRespDTOList);
+        }
+        return resp;
+    }
+
+    @Override
+    public PageResult<LuckLotteryDO> getLuckLotteryPage(LuckLotteryPageReqVO pageReqVO) {
+        return luckLotteryMapper.selectPage(pageReqVO);
+    }
+
+    @Override
+    public List<LuckLotteryDO> getLuckLotteryListByTime(LocalDateTime startTime, LocalDateTime endTime) {
+        return luckLotteryMapper.getLuckLotteryListByTime(startTime, endTime);
+    }
+
+    @Override
+    public List<LuckLotteryDO> getLuckLotteryListByTime(Long spuId, LocalDateTime startTime, LocalDateTime endTime) {
+        return luckLotteryMapper.getLuckLotteryListByTime(spuId,startTime, endTime);
+    }
+
+    @Override
+    public LuckLotteryDO getByName(String name) {
+        LuckLotteryDO luckLottery = luckLotteryMapper.selectByName(name);
+        if (null == luckLottery) {
+            throw exception(LUCK_LOTTERY_NOT_EXISTS);
+        }
+        return luckLottery;
+    }
+}

+ 302 - 0
citu-module-mall/citu-module-promotion-biz/src/main/java/com/citu/module/promotion/service/luck/LuckPrizeServiceImpl.java

@@ -0,0 +1,302 @@
+package com.citu.module.promotion.service.luck;
+
+
+import cn.hutool.core.collection.CollUtil;
+import com.alibaba.fastjson.JSON;
+import com.baomidou.dynamic.datasource.annotation.DSTransactional;
+import com.citu.framework.common.pojo.PageResult;
+import com.citu.framework.common.util.object.BeanUtils;
+import com.citu.module.menduner.system.api.area.MendunerAreaApi;
+import com.citu.module.product.api.spu.ProductSpuApi;
+import com.citu.module.product.api.spu.dto.ProductSpuRespDTO;
+import com.citu.module.promotion.controller.admin.luck.vo.prize.LuckPrizeDetailRespVO;
+import com.citu.module.promotion.controller.admin.luck.vo.prize.LuckPrizeImportExcelVO;
+import com.citu.module.promotion.controller.admin.luck.vo.prize.LuckPrizePageReqVO;
+import com.citu.module.promotion.controller.admin.luck.vo.prize.LuckPrizeSaveReqVO;
+import com.citu.module.promotion.convert.luck.LuckPrizeConvert;
+import com.citu.module.promotion.dal.dataobject.luck.LuckLotteryDO;
+import com.citu.module.promotion.dal.dataobject.luck.LuckPrizeDO;
+import com.citu.module.promotion.dal.dataobject.luck.LuckPrizeExtend;
+import com.citu.module.promotion.dal.dataobject.luck.LuckPrizeExtendDO;
+import com.citu.module.promotion.dal.mysql.luck.LuckPrizeExtendMapper;
+import com.citu.module.promotion.dal.mysql.luck.LuckPrizeMapper;
+import com.citu.module.promotion.enums.luck.LuckPrizeTypeEnum;
+import org.springframework.stereotype.Service;
+import org.springframework.util.StringUtils;
+import org.springframework.validation.annotation.Validated;
+
+import javax.annotation.Resource;
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.util.List;
+
+import static com.citu.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static com.citu.module.promotion.enums.ErrorCodeConstants.*;
+
+/**
+ * 幸运抽奖-奖品 Service 实现类
+ *
+ * @author Rayson
+ */
+@Service
+@Validated
+public class LuckPrizeServiceImpl implements LuckPrizeService {
+
+    /**
+     * 奖品数量
+     */
+    private static final Integer num = 8;
+    @Resource
+    private LuckLotteryService luckLotteryService;
+
+    @Resource
+    private LuckPrizeMapper luckPrizeMapper;
+
+    @Resource
+    private LuckPrizeExtendMapper prizeExtendMapper;
+
+    @Resource
+    private ProductSpuApi productSpuApi;
+
+    @Resource
+    private MendunerAreaApi mendunerAreaApi;
+
+    @Override
+    @DSTransactional
+    public Long createLuckPrize(LuckPrizeSaveReqVO createReqVO) {
+        // 插入
+//        List<LuckPrizeDO> list = luckPrizeMapper.getListByLotteryId(createReqVO.getLotteryId());
+//        if (list.size() >= num) {
+//            throw exception(LUCK_LOTTERY_PRIZE_COUNT_EXCEED);
+//        }
+        LuckPrizeDO luckPrize = BeanUtils.toBean(createReqVO, LuckPrizeDO.class);
+        luckPrizeMapper.insert(luckPrize);
+
+        if (LuckPrizeTypeEnum.CUSTOM.getType().equals(luckPrize.getType())) {
+            // 自定义奖品
+            LuckPrizeExtend extend = luckPrize.getExtend();
+            // 保存扩展信息
+            LuckPrizeExtendDO prizeExtend = BeanUtils.toBean(extend, LuckPrizeExtendDO.class);
+            prizeExtend.setLotteryId(luckPrize.getLotteryId());
+            prizeExtend.setLuckPrizeId(luckPrize.getId());
+            prizeExtendMapper.insert(prizeExtend);
+        }
+        // 返回
+        return luckPrize.getId();
+    }
+
+    @Override
+    @DSTransactional
+    public void updateLuckPrize(LuckPrizeSaveReqVO updateReqVO) {
+        // 校验存在
+        LuckPrizeDO oldLuckPrize = validateLuckPrizeExists(updateReqVO.getId());
+        // 更新
+        LuckPrizeDO updateObj = BeanUtils.toBean(updateReqVO, LuckPrizeDO.class);
+        // 判断是否自定义
+        if (LuckPrizeTypeEnum.CUSTOM.getType().equals(updateObj.getType())) {
+            // 自定义奖品
+            if (null == updateObj.getExtend()) {
+                throw exception(LUCK_LOTTERY_PRIZE_EXTEND_NOT_COMPLETE);
+            }
+            // 查询扩展信息
+            LuckPrizeExtendDO prizeExtend = prizeExtendMapper.selectByLuckPrizeId(updateObj.getId());
+            // 解析对象
+            LuckPrizeExtend extend = updateObj.getExtend();
+            // 转换
+            LuckPrizeExtendDO newObj = BeanUtils.toBean(extend, LuckPrizeExtendDO.class);
+            newObj.setLotteryId(updateObj.getLotteryId());
+            newObj.setLuckPrizeId(updateObj.getId());
+            if (null == prizeExtend) {
+                // 新增扩展
+                prizeExtendMapper.insert(newObj);
+            } else {
+                // 修改扩展
+                newObj.setId(prizeExtend.getId());
+                prizeExtendMapper.updateById(newObj);
+            }
+        } else {
+            // 判断之前是不是自定义奖品
+            if (LuckPrizeTypeEnum.CUSTOM.getType().equals(oldLuckPrize.getType())) {
+                // 删除
+                prizeExtendMapper.deleteByLuckPrizeId(oldLuckPrize.getId());
+            }
+            // 清空
+            updateObj.setExtend(null);
+        }
+        luckPrizeMapper.updateById(updateObj);
+    }
+
+
+    @Override
+    @DSTransactional
+    public void deleteLuckPrize(Long id) {
+        // 校验存在
+        validateLuckPrizeExists(id);
+        // 删除
+        luckPrizeMapper.deleteById(id);
+        prizeExtendMapper.deleteByLuckPrizeId(id);
+    }
+
+    private LuckPrizeDO validateLuckPrizeExists(Long id) {
+        LuckPrizeDO luckPrize = getLuckPrize(id);
+        if (null == luckPrize) {
+            throw exception(LUCK_PRIZE_NOT_EXISTS);
+        }
+        return luckPrize;
+    }
+
+    @Override
+    public LuckPrizeDO getLuckPrize(Long id) {
+        return luckPrizeMapper.selectById(id);
+    }
+
+    @Override
+    public LuckPrizeDetailRespVO detail(Long id) {
+        LuckPrizeDetailRespVO respVO =
+                LuckPrizeConvert.INSTANCE.convert2(luckPrizeMapper.selectById(id));
+        if (LuckPrizeTypeEnum.PRODUCT.getType().equals(respVO.getType())
+                || null != respVO.getProductId()) {
+            // 站内商品
+            ProductSpuRespDTO spuResp =
+                    productSpuApi.getSpu(respVO.getProductId()).getCheckedData();
+            respVO.setSpu(spuResp);
+        }
+        return respVO;
+    }
+
+    @Override
+    public PageResult<LuckPrizeDO> getLuckPrizePage(LuckPrizePageReqVO pageReqVO) {
+        return luckPrizeMapper.selectPage(pageReqVO);
+    }
+
+    @Override
+    public List<LuckPrizeDO> getListByLotteryId(Long lotteryId) {
+        List<LuckPrizeDO> list = luckPrizeMapper.getListByLotteryId(lotteryId);
+        if (null == list) {
+            throw exception(LUCK_LOTTERY_NOT_ADD_PRIZE);
+        }
+        return list;
+    }
+
+    @Override
+    @DSTransactional
+    public void importData(List<LuckPrizeImportExcelVO> list) {
+        list.forEach(vo -> {
+            LuckLotteryDO lottery = luckLotteryService.getByName(vo.getLotteryName());
+
+            LuckPrizeExtend extend = new LuckPrizeExtend();
+            extend.setBloc(vo.getBloc());
+            extend.setBrand(vo.getBrand());
+
+            if (StringUtils.hasText(vo.getProvinceName())) {
+                Long provinceId = mendunerAreaApi.getAreaByNameAndType(vo.getProvinceName(), MendunerAreaApi.PROVIDER)
+                        .getCheckedData();
+                if (null == provinceId) {
+                    throw exception(LUCK_PRIZE_EXTEND_PROVINCE_INCORRECT);
+                }
+                extend.setProvinceId(provinceId);
+                extend.setProvinceName(vo.getProvinceName());
+            }
+
+            if (StringUtils.hasText(vo.getCityName())) {
+                Long cityId = mendunerAreaApi.getAreaByNameAndType(vo.getCityName(), MendunerAreaApi.CITY)
+                        .getCheckedData();
+                if (null == cityId) {
+                    throw exception(LUCK_PRIZE_EXTEND_CITY_INCORRECT);
+                }
+                extend.setCityId(cityId);
+                extend.setCityName(vo.getCityName());
+            }
+
+            if (StringUtils.hasText(vo.getDistrictName())) {
+                Long districtId = mendunerAreaApi.getAreaByNameAndType(vo.getDistrictName(), MendunerAreaApi.DISTRICT)
+                        .getCheckedData();
+                if (null == districtId) {
+                    throw exception(LUCK_PRIZE_EXTEND_COUNTY_INCORRECT);
+                }
+                extend.setDistrictId(districtId);
+                extend.setDistrictName(vo.getDistrictName());
+            }
+
+            createLuckPrize(LuckPrizeSaveReqVO.builder()
+                    .lotteryId(lottery.getId())
+                    .name(vo.getName())
+                    .type(vo.getType())
+                    .image(vo.getImage())
+                    .prompt(vo.getPrompt())
+                    .total(vo.getTotal())
+                    .chance(vo.getChance())
+                    .extend(extend)
+                    .sort(1)
+                    .status(vo.getStatus())
+                    .build());
+        });
+    }
+
+    @Override
+    public void updateById(LuckPrizeDO luckPrizeDO) {
+        luckPrizeMapper.updateById(luckPrizeDO);
+    }
+
+    /**
+     * 根据权重随机选择奖品
+     *
+     * @param randomNumber  随机数
+     * @param luckPrizeList 奖品列表
+     * @return 随机选择的奖品
+     */
+    @Override
+    public LuckPrizeDO selectPrizeByWeight(int randomNumber, List<LuckPrizeDO> luckPrizeList) {
+        int cumulativeWeight = 0;
+
+        for (LuckPrizeDO prize : luckPrizeList) {
+            // 获取奖品的总数
+            Integer total = prize.getTotal();
+
+            // 检查total是否为空或无效(奖品是不是无限量?)
+            if (total == null || total <= 0) {
+                // 跳过总数无效的奖品
+                continue;
+            }
+
+            // 计算当前奖品的权重
+            int prizeWeight = prize.getChance() * total;
+
+            // 如果随机数落在当前奖品的权重范围内,则选择该奖品
+            if (randomNumber < cumulativeWeight + prizeWeight) {
+                return prize;
+            }
+
+            // 累加权重
+            cumulativeWeight += prizeWeight;
+        }
+
+        // 如果没有符合条件的奖品返回null,理论上不应该发生,除非所有奖品的总数都是无效的
+        return null;
+    }
+
+    @Override
+    public PageResult<LuckPrizeDetailRespVO> page(LuckPrizePageReqVO pageReqVO) {
+        PageResult<LuckPrizeDetailRespVO> pageResult =
+                LuckPrizeConvert.INSTANCE.convertPage(luckPrizeMapper.selectPage(pageReqVO));
+        if (CollUtil.isEmpty(pageResult.getList())) {
+            return pageResult;
+        }
+        // 计算总权重 商品权重n*总数n
+        int totalWeight = pageResult.getList().stream().mapToInt(prize -> prize.getChance() * prize.getTotal()).sum();
+        for (LuckPrizeDetailRespVO resp : pageResult.getList()) {
+            // 计算概率赋值
+            if (resp.getChance() != null && resp.getTotal() != null && totalWeight > 0) {
+                double probability = (double) (resp.getChance() * resp.getTotal()) / totalWeight;
+                // 使用BigDecimal进行精确计算,设置小数位数和舍入模式
+                BigDecimal bd = new BigDecimal(probability * 100);
+                bd = bd.setScale(2, RoundingMode.HALF_UP);
+                resp.setProbability(bd.doubleValue());
+            } else {
+                resp.setProbability(0.00);
+            }
+
+        }
+        return pageResult;
+    }
+}

+ 1 - 0
citu-module-mall/citu-module-promotion-biz/src/main/resources/application.yaml

@@ -47,6 +47,7 @@ knife4j:
 mybatis-plus:
   configuration:
     map-underscore-to-camel-case: true # 虽然默认为 true ,但是还是显示去指定下。
+    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
   global-config:
     db-config:
       id-type: NONE # “智能”模式,基于 IdTypeEnvironmentPostProcessor + 数据源的类型,自动适配成 AUTO、INPUT 模式。

+ 21 - 0
citu-module-mall/citu-module-trade-biz/src/main/java/com/citu/module/trade/service/order/handler/TradeLotteryOrderHandler.java

@@ -0,0 +1,21 @@
+package com.citu.module.trade.service.order.handler;
+
+import com.citu.module.trade.dal.dataobject.order.TradeOrderDO;
+import com.citu.module.trade.dal.dataobject.order.TradeOrderItemDO;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+
+/**
+ * 抽奖 {@link TradeOrderHandler} 实现类
+ *
+ * @author Rayson
+ */
+@Component
+public class TradeLotteryOrderHandler implements TradeOrderHandler {
+
+    @Override
+    public void afterPayOrder(TradeOrderDO order, List<TradeOrderItemDO> orderItems) {
+        // 订单支付后
+    }
+}

+ 2 - 1
menduner/menduner-common/src/main/java/com/citu/module/menduner/common/db/CituTransformDataSourceAutoConfiguration.java

@@ -12,10 +12,11 @@ import org.springframework.context.annotation.Bean;
  **/
 @AutoConfiguration
 @EnableConfigurationProperties(DBTransformProperties.class)
-@ConditionalOnProperty(prefix = "citu.db.transform", name = "enable", havingValue = "true", matchIfMissing = true)
+@ConditionalOnProperty(prefix = "citu.db.transform", name = "enable", havingValue = "true", matchIfMissing = false)
 public class CituTransformDataSourceAutoConfiguration {
 
     @Bean
+    @ConditionalOnProperty(value = "citu.db.transform.enable", havingValue = "true")
     public TransformDataSourceInterceptor transformDataSourceInterceptor() {
         return new TransformDataSourceInterceptor();
     }

+ 2 - 6
menduner/menduner-im-biz/src/main/java/com/citu/module/menduner/im/framework/rpc/config/RpcConfiguration.java

@@ -1,15 +1,11 @@
 package com.citu.module.menduner.im.framework.rpc.config;
 
 import com.citu.module.menduner.im.service.wukong.WuKongApiService;
-import com.citu.module.menduner.system.api.user.UserApi;
-import com.citu.module.system.api.logger.LoginLogApi;
-import com.citu.module.system.api.sms.SmsCodeApi;
-import com.citu.module.system.api.social.SocialClientApi;
-import com.citu.module.system.api.social.SocialUserApi;
+import com.citu.module.menduner.system.api.user.MendunerUserApi;
 import org.springframework.cloud.openfeign.EnableFeignClients;
 import org.springframework.context.annotation.Configuration;
 
 @Configuration(proxyBeanMethods = false)
-@EnableFeignClients(clients = {WuKongApiService.class, UserApi.class})
+@EnableFeignClients(clients = {WuKongApiService.class, MendunerUserApi.class})
 public class RpcConfiguration {
 }

+ 5 - 6
menduner/menduner-im-biz/src/main/java/com/citu/module/menduner/im/service/UserServiceImpl.java

@@ -13,14 +13,13 @@ import com.citu.module.menduner.im.convert.UserConvert;
 import com.citu.module.menduner.im.dal.dataobject.UserDO;
 import com.citu.module.menduner.im.dal.mysql.UserMapper;
 import com.citu.module.menduner.im.service.wukong.WuKongUserService;
-import com.citu.module.menduner.system.api.user.UserApi;
+import com.citu.module.menduner.system.api.user.MendunerUserApi;
 import com.citu.module.menduner.system.api.user.UserInfoReqDTO;
 import com.citu.module.menduner.system.api.user.UserInfoRespDTO;
 import com.citu.module.menduner.system.enums.user.MdeUserTypeEnum;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.dao.DuplicateKeyException;
 import org.springframework.stereotype.Service;
-import org.springframework.transaction.annotation.Transactional;
 
 import java.time.LocalDateTime;
 import java.util.*;
@@ -34,7 +33,7 @@ public class UserServiceImpl implements UserService{
     WuKongUserService wuKongUserService;
 
 
-    UserApi userApi;
+    MendunerUserApi mendunerUserApi;
 
     private static final Long DEFAULT_ENTERPRISE_ID = -999L;
 
@@ -176,7 +175,7 @@ public class UserServiceImpl implements UserService{
         }
 //        System.out.println("DEBUG ============>");
 //        System.out.println(JSON.toJSONString(userDOS));
-        List<UserInfoRespDTO> result = userApi.getUserInfo(list).getCheckedData();
+        List<UserInfoRespDTO> result = mendunerUserApi.getUserInfo(list).getCheckedData();
 //        System.out.println(JSON.toJSONString(result));
 //        System.out.println("DEBUG ============>");
 
@@ -214,7 +213,7 @@ public class UserServiceImpl implements UserService{
         this.mapper = mapper;
     }
     @Autowired
-    public void setUserApi(UserApi userApi) {
-        this.userApi = userApi;
+    public void setUserApi(MendunerUserApi mendunerUserApi) {
+        this.mendunerUserApi = mendunerUserApi;
     }
 }

+ 2 - 2
menduner/menduner-reward-biz/src/main/java/com/citu/module/menduner/reward/framework/rpc/config/RpcConfiguration.java

@@ -2,7 +2,7 @@ package com.citu.module.menduner.reward.framework.rpc.config;
 
 import com.citu.module.menduner.system.api.url.MendunerSystemUrlApi;
 import com.citu.module.menduner.system.api.account.UserAccountApi;
-import com.citu.module.menduner.system.api.user.UserApi;
+import com.citu.module.menduner.system.api.user.MendunerUserApi;
 import org.springframework.cloud.openfeign.EnableFeignClients;
 import org.springframework.context.annotation.Configuration;
 
@@ -10,7 +10,7 @@ import org.springframework.context.annotation.Configuration;
 @EnableFeignClients(clients = {
         MendunerSystemUrlApi.class,
         UserAccountApi.class,
-        UserApi.class
+        MendunerUserApi.class
 })
 public class RpcConfiguration {
 }

+ 40 - 0
menduner/menduner-system-api/src/main/java/com/citu/module/menduner/system/api/area/MendunerAreaApi.java

@@ -0,0 +1,40 @@
+package com.citu.module.menduner.system.api.area;
+
+import com.citu.framework.common.pojo.CommonResult;
+import com.citu.module.menduner.system.enums.ApiConstants;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.cloud.openfeign.FeignClient;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+
+import java.util.Collection;
+import java.util.Map;
+
+@FeignClient(name = ApiConstants.NAME)
+@Tag(name = "RPC 服务 - 区域")
+public interface MendunerAreaApi {
+
+    String PREFIX = ApiConstants.PREFIX + "/area";
+
+    String PROVIDER = "2";
+    String CITY = "3";
+    String DISTRICT = "4";
+
+
+    @GetMapping(PREFIX + "/list")
+    @Operation(summary = "根据区域id获取区域名称")
+    @Parameter(name = "ids", description = "区域id 编号列表", required = true, example = "1,3,5")
+    CommonResult<Map<Long, String>> getAreaList(@RequestParam("ids") Collection<Long> ids);
+
+    @GetMapping(PREFIX + "/get")
+    @Operation(summary = "根据区域id获取区域信息")
+    @Parameter(name = "id", description = "区域id", required = true, example = "1,3,5")
+    CommonResult<String> getArea(@RequestParam("id") Long id);
+
+    @GetMapping(PREFIX + "/get/by/name")
+    @Operation(summary = "根据区域名称和类型获取id")
+    CommonResult<Long> getAreaByNameAndType(@RequestParam("name") String name, @RequestParam("type") String type);
+
+}

+ 14 - 1
menduner/menduner-system-api/src/main/java/com/citu/module/menduner/system/api/user/UserApi.java → menduner/menduner-system-api/src/main/java/com/citu/module/menduner/system/api/user/MendunerUserApi.java

@@ -3,17 +3,20 @@ package com.citu.module.menduner.system.api.user;
 import com.citu.framework.common.pojo.CommonResult;
 import com.citu.module.menduner.system.enums.ApiConstants;
 import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
 import io.swagger.v3.oas.annotations.tags.Tag;
 import org.springframework.cloud.openfeign.FeignClient;
+import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestParam;
 
 import java.util.Collection;
 import java.util.List;
 
 @FeignClient(name = ApiConstants.NAME)
 @Tag(name = "RPC 服务 - 门墩儿用户url")
-public interface UserApi {
+public interface MendunerUserApi {
 
     String PREFIX = ApiConstants.PREFIX + "/user";
 
@@ -22,4 +25,14 @@ public interface UserApi {
     @Operation(summary = "获取用户信息")
     CommonResult<List<UserInfoRespDTO>> getUserInfo(@RequestBody Collection<UserInfoReqDTO> req);
 
+
+    @GetMapping(PREFIX + "/list")
+    @Operation(summary = "根据用户id获取用户信息")
+    @Parameter(name = "ids", description = "用户id 编号列表", required = true, example = "1,3,5")
+    CommonResult<List<UserInfoRespDTO>> getUserList(@RequestParam("ids") Collection<Long> ids);
+
+    @GetMapping(PREFIX + "/get")
+    @Operation(summary = "根据用户id获取用户信息")
+    @Parameter(name = "id", description = "用户id 编号列表", required = true, example = "1,3,5")
+    CommonResult<UserInfoRespDTO> getUser(@RequestParam("id") Long id);
 }

+ 45 - 0
menduner/menduner-system-biz/src/main/java/com/citu/module/menduner/system/api/area/MendunerAreaApiImpl.java

@@ -0,0 +1,45 @@
+package com.citu.module.menduner.system.api.area;
+
+import com.citu.framework.common.pojo.CommonResult;
+import com.citu.module.menduner.system.dal.dataobject.area.AreaDO;
+import com.citu.module.menduner.system.service.area.AreaService;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Map;
+import java.util.Set;
+
+import static com.citu.framework.common.pojo.CommonResult.success;
+
+@RestController // 提供 RESTful API 接口,给 Feign 调用
+@Validated
+public class MendunerAreaApiImpl implements MendunerAreaApi {
+    @Resource
+    private AreaService areaService;
+
+    @Override
+    public CommonResult<Map<Long, String>> getAreaList(Collection<Long> ids) {
+        return success(areaService.getNameByIds((Set<Long>) ids));
+    }
+
+    @Override
+    public CommonResult<String> getArea(Long id) {
+        Map<Long, String> areaMap = areaService.getNameByIds(Collections.singleton(id));
+        if (areaMap.containsKey(id)) {
+            return success(areaMap.get(id));
+        }
+        return success(null);
+    }
+
+    @Override
+    public CommonResult<Long> getAreaByNameAndType(String name, String type) {
+        AreaDO area = areaService.getAreaByNameAndType(name, type);
+        if (null == area) {
+            return success(null);
+        }
+        return success(area.getId());
+    }
+}

+ 40 - 1
menduner/menduner-system-biz/src/main/java/com/citu/module/menduner/system/api/user/UserApiImpl.java → menduner/menduner-system-biz/src/main/java/com/citu/module/menduner/system/api/user/MendunerUserApiImpl.java

@@ -17,7 +17,7 @@ import java.util.List;
 
 @RestController // 提供 RESTful API 接口,给 Feign 调用
 @Validated
-public class UserApiImpl implements UserApi {
+public class MendunerUserApiImpl implements MendunerUserApi {
 
     @Resource
     private PersonInfoMapper personMapper;
@@ -69,4 +69,43 @@ public class UserApiImpl implements UserApi {
         }
         return CommonResult.success(list);
     }
+
+    @Override
+    public CommonResult<List<UserInfoRespDTO>> getUserList(Collection<Long> ids) {
+        List<UserInfoRespDTO> list = new ArrayList<>();
+        for (Long id : ids) {
+            UserInfoRespDTO respDTO = get(id);
+            if (null != respDTO.getUserId()) {
+                list.add(respDTO);
+            }
+        }
+        return CommonResult.success(list);
+    }
+
+    @Override
+    public CommonResult<UserInfoRespDTO> getUser(Long id) {
+        return CommonResult.success(get(id));
+    }
+
+    public UserInfoRespDTO get(Long id) {
+        UserInfoRespDTO respDTO = new UserInfoRespDTO();
+        MdeUserDO user = userMapper.selectOne(MdeUserDO::getId, id);
+        if (null != user) {
+            respDTO.setUserId(id);
+            respDTO.setPhone(user.getPhone());
+            respDTO.setVipFlag(user.getVipFlag());
+            respDTO.setVipExpireDate(user.getVipExpireDate());
+            respDTO.setLoginIp(user.getLoginIp());
+            respDTO.setLoginDate(user.getLoginDate());
+        }
+        // 平台用户
+        PersonInfoDO personInfo = personMapper.selectOne(PersonInfoDO::getUserId, id);
+        if (null != personInfo) {
+            respDTO.setUserId(id);
+            respDTO.setAvatar(personInfo.getAvatar());
+            respDTO.setName(personInfo.getName());
+            respDTO.setSex(personInfo.getSex());
+        }
+        return respDTO;
+    }
 }

+ 21 - 0
menduner/menduner-system-biz/src/main/java/com/citu/module/menduner/system/controller/admin/enterprise/EnterpriseController.java

@@ -6,10 +6,13 @@ import com.citu.framework.common.pojo.PageParam;
 import com.citu.framework.common.pojo.PageResult;
 import com.citu.framework.common.util.object.BeanUtils;
 import com.citu.framework.excel.core.util.ExcelUtils;
+import com.citu.module.menduner.system.controller.base.enterprise.vip.EnterpriseEntitlementRespVO;
+import com.citu.module.menduner.system.controller.base.enterprise.vip.EnterpriseVipReqVO;
 import com.citu.module.menduner.system.controller.base.enterprise.vo.*;
 import com.citu.module.menduner.system.dal.dataobject.enterprise.EnterpriseDO;
 import com.citu.module.menduner.system.enums.MendunerStatusEnum;
 import com.citu.module.menduner.system.service.enterprise.EnterpriseService;
+import com.citu.module.menduner.system.service.enterprise.vip.EnterpriseEntitlementService;
 import io.swagger.v3.oas.annotations.Operation;
 import io.swagger.v3.oas.annotations.Parameter;
 import io.swagger.v3.oas.annotations.tags.Tag;
@@ -35,6 +38,9 @@ public class EnterpriseController {
     @Resource
     private EnterpriseService enterpriseService;
 
+    @Resource
+    private EnterpriseEntitlementService entitlementService;
+
     @PostMapping("/create")
     @Operation(summary = "创建企业信息")
     @PreAuthorize("@ss.hasPermission('menduner:system:enterprise:create')")
@@ -118,5 +124,20 @@ public class EnterpriseController {
         return success(true);
     }
 
+    @PostMapping("/activate/vip")
+    @Operation(summary = "开通激活vip")
+    @PreAuthorize("@ss.hasPermission('menduner:system:enterprise:update')")
+    public CommonResult<Boolean> activateVip(@Valid @RequestBody EnterpriseVipReqVO reqVO) {
+        entitlementService.activateVip(reqVO);
+        return success(true);
+    }
+
+    @PostMapping("/entitlement/by/id")
+    @Operation(summary = "获取企业的所有权益列表")
+    @PreAuthorize("@ss.hasPermission('menduner:system:enterprise:query')")
+    public CommonResult<List<EnterpriseEntitlementRespVO>> getEntitlementListByEnterpriseId(@RequestParam("id") Long id) {
+        return success(entitlementService.getListByEnterpriseId(id));
+    }
+
 
 }

+ 9 - 0
menduner/menduner-system-biz/src/main/java/com/citu/module/menduner/system/controller/admin/enterprise/EnterprisePackageController.java

@@ -7,6 +7,7 @@ import com.citu.framework.common.pojo.PageParam;
 import com.citu.framework.common.pojo.PageResult;
 import com.citu.framework.common.util.object.BeanUtils;
 import com.citu.framework.excel.core.util.ExcelUtils;
+import com.citu.framework.security.core.annotations.PreAuthenticated;
 import com.citu.module.menduner.system.controller.base.enterprise.vip.EnterprisePackagePageReqVO;
 import com.citu.module.menduner.system.controller.base.enterprise.vip.EnterprisePackageRespVO;
 import com.citu.module.menduner.system.controller.base.enterprise.vip.EnterprisePackageSaveReqVO;
@@ -92,4 +93,12 @@ public class EnterprisePackageController {
                 BeanUtils.toBean(list, EnterprisePackageRespVO.class));
     }
 
+
+    @GetMapping("/list")
+    @Operation(summary = "获得用户套餐列表")
+    public CommonResult<List<EnterprisePackageRespVO>> list() {
+        List<EnterprisePackageDO> list = enterprisePackageService.getListAll();
+        return success(BeanUtils.toBean(list, EnterprisePackageRespVO.class));
+    }
+
 }

+ 16 - 0
menduner/menduner-system-biz/src/main/java/com/citu/module/menduner/system/controller/base/enterprise/vip/EnterpriseVipReqVO.java

@@ -0,0 +1,16 @@
+package com.citu.module.menduner.system.controller.base.enterprise.vip;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+@Schema(description = "管理后台 - 开通修改企业会员 Request VO")
+@Data
+public class EnterpriseVipReqVO {
+
+    @Schema(description = "企业id")
+    private Long enterpriseId;
+
+    @Schema(description = "企业套餐")
+    private Long packageId;
+
+}

+ 5 - 0
menduner/menduner-system-biz/src/main/java/com/citu/module/menduner/system/dal/mysql/area/AreaMapper.java

@@ -7,6 +7,7 @@ import com.citu.module.menduner.system.controller.base.area.AreaListReqVO;
 import com.citu.module.menduner.system.controller.base.area.AreaPageReqVO;
 import com.citu.module.menduner.system.controller.app.jobhunt.area.vo.AppAreaListReqVO;
 import com.citu.module.menduner.system.dal.dataobject.area.AreaDO;
+import com.citu.module.menduner.system.dal.dataobject.area.AreaHotDO;
 import com.citu.module.menduner.system.dal.dataobject.position.PositionDO;
 import org.apache.ibatis.annotations.Mapper;
 
@@ -61,4 +62,8 @@ public interface AreaMapper extends BaseMapperX<AreaDO> {
     default List<AreaDO> selectListByNameList(String name) {
         return selectList(AreaDO::getName, name);
     }
+
+    default AreaDO selectByNameAndType(String name, String type) {
+        return selectOne(AreaDO::getName, name, AreaDO::getType, type);
+    }
 }

+ 7 - 0
menduner/menduner-system-biz/src/main/java/com/citu/module/menduner/system/dal/mysql/enterprise/EnterpriseEntitlementMapper.java

@@ -8,6 +8,8 @@ import com.citu.module.menduner.system.controller.base.enterprise.vip.Enterprise
 import com.citu.module.menduner.system.dal.dataobject.enterprise.EnterpriseEntitlementDO;
 import org.apache.ibatis.annotations.Mapper;
 
+import java.util.List;
+
 /**
  * 企业权益记录 Mapper
  *
@@ -24,4 +26,9 @@ public interface EnterpriseEntitlementMapper extends BaseMapperX<EnterpriseEntit
                 .orderByDesc(EnterpriseEntitlementDO::getId));
     }
 
+    default List<EnterpriseEntitlementDO> selectListByEnterpriseId(Long enterpriseId) {
+        return selectList(new LambdaQueryWrapperX<EnterpriseEntitlementDO>()
+                .eq(EnterpriseEntitlementDO::getEnterpriseId, enterpriseId));
+    }
+
 }

+ 2 - 2
menduner/menduner-system-biz/src/main/java/com/citu/module/menduner/system/dal/mysql/enterprise/EnterprisePackageMapper.java

@@ -30,9 +30,9 @@ public interface EnterprisePackageMapper extends BaseMapperX<EnterprisePackageDO
                 .orderByDesc(EnterprisePackageDO::getId));
     }
 
-    default List<EnterprisePackageDO> list() {
+    default List<EnterprisePackageDO> list(Boolean defaultPackage) {
         return selectList(new LambdaQueryWrapperX<EnterprisePackageDO>()
-                .eq(EnterprisePackageDO::getDefaultPackage, false)
+                .eqIfPresent(EnterprisePackageDO::getDefaultPackage, defaultPackage)
                 .eq(EnterprisePackageDO::getStatus, CommonStatusEnum.ENABLE.getStatus())
         );
     }

+ 1 - 0
menduner/menduner-system-biz/src/main/java/com/citu/module/menduner/system/dal/mysql/job/JobAdvertisedMapper.java

@@ -155,6 +155,7 @@ public interface JobAdvertisedMapper extends BaseMapperX<JobAdvertisedDO> {
         if (AppJobAdvertisedPageReqVO.NEW.equals(reqVO.getMark())) {
             // 最新
             // query.orderByDesc(JobAdvertisedDO::getUpdateTime);
+            query.orderByDesc(JobAdvertisedDO::getCreateTime);
         }
         if (AppJobAdvertisedPageReqVO.HIRE.equals(reqVO.getMark())) {
             // 众聘

+ 0 - 1
menduner/menduner-system-biz/src/main/java/com/citu/module/menduner/system/mq/consumer/UserMemberConsumer.java

@@ -54,7 +54,6 @@ public class UserMemberConsumer implements RocketMQListener<Long> {
     public static boolean isExpired(LocalDateTime expiryTime) {
         // 获取当前时间
         LocalDateTime now = LocalDateTime.now();
-
         // 比较当前时间和到期时间
         return now.isAfter(expiryTime);
     }

+ 5 - 0
menduner/menduner-system-biz/src/main/java/com/citu/module/menduner/system/service/area/AreaService.java

@@ -130,4 +130,9 @@ public interface AreaService {
      * 根据id集合获取名称集合
      **/
     Map<Long, String> getNameByIds(Set<Long> ids);
+
+    /**
+     * 根据名称和类型获取地区
+     **/
+    AreaDO getAreaByNameAndType(String name, String type);
 }

+ 5 - 0
menduner/menduner-system-biz/src/main/java/com/citu/module/menduner/system/service/area/AreaServiceImpl.java

@@ -289,4 +289,9 @@ public class AreaServiceImpl implements AreaService {
         List<AreaDO> areaList = areaMapper.selectBatchIds(ids);
         return areaList.stream().collect(Collectors.toMap(AreaDO::getId, AreaDO::getName));
     }
+
+    @Override
+    public AreaDO getAreaByNameAndType(String name, String type) {
+        return areaMapper.selectByNameAndType(name, type);
+    }
 }

+ 12 - 1
menduner/menduner-system-biz/src/main/java/com/citu/module/menduner/system/service/enterprise/EnterpriseService.java

@@ -7,10 +7,12 @@ import com.citu.module.menduner.system.controller.app.jobhunt.enterprise.vo.AppE
 import com.citu.module.menduner.system.controller.app.jobhunt.enterprise.vo.AppEnterpriseDetailRespVO;
 import com.citu.module.menduner.system.controller.app.recruit.enterprise.vo.*;
 import com.citu.module.menduner.system.controller.base.CommonRespVO;
+import com.citu.module.menduner.system.controller.base.enterprise.vip.EnterpriseVipReqVO;
 import com.citu.module.menduner.system.controller.base.enterprise.vo.*;
 import com.citu.module.menduner.system.dal.dataobject.enterprise.EnterpriseDO;
 
 import javax.validation.Valid;
+import java.time.LocalDateTime;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -192,7 +194,10 @@ public interface EnterpriseService {
      **/
     void syncGraph();
 
-
+    /**
+     * 修改vip
+     **/
+    void updateVip(Long id, String vipFlag, LocalDateTime vipExpireDate);
     // ========== 招聘端 ==========
 
     /**
@@ -248,6 +253,12 @@ public interface EnterpriseService {
      **/
     AppRecruitEnterpriseTreeRespVO getTree(Long id);
 
+    /**
+     * 获取企业详情
+     *
+     * @param ids 企业编号
+     * @return List<AppEnterpriseDetailRespVO>
+     **/
     List<AppEnterpriseDetailRespVO> getEnterpriseDetails(String ids);
 
 }

+ 7 - 1
menduner/menduner-system-biz/src/main/java/com/citu/module/menduner/system/service/enterprise/EnterpriseServiceImpl.java

@@ -297,7 +297,7 @@ public class EnterpriseServiceImpl implements EnterpriseService {
     @Override
     public List<AppEnterpriseDetailRespVO> getEnterpriseDetails(String ids) {
         List<AppEnterpriseDetailRespVO> appEnterpriseDetailRespVOS = new ArrayList<>();
-        List<Long> enterpriseIds =  Arrays.stream(ids.split(","))
+        List<Long> enterpriseIds = Arrays.stream(ids.split(","))
                 .filter(StringUtils::hasText)
                 .map(Long::parseLong)
                 .collect(Collectors.toList());
@@ -386,6 +386,12 @@ public class EnterpriseServiceImpl implements EnterpriseService {
 
     }
 
+    @Override
+    public void updateVip(Long id, String vipFlag, LocalDateTime vipExpireDate) {
+        EnterpriseDO enterprise = validateEnterpriseExists(id);
+        enterpriseMapper.updateById(EnterpriseDO.builder().id(id).vipFlag(vipFlag).vipExpireDate(vipExpireDate).build());
+    }
+
     @Override
     @DSTransactional
     public void uploadLogo(String logoUrl) {

+ 15 - 0
menduner/menduner-system-biz/src/main/java/com/citu/module/menduner/system/service/enterprise/vip/EnterpriseEntitlementService.java

@@ -5,9 +5,11 @@ import com.citu.framework.common.pojo.PageResult;
 import com.citu.module.menduner.system.controller.base.enterprise.vip.EnterpriseEntitlementPageReqVO;
 import com.citu.module.menduner.system.controller.base.enterprise.vip.EnterpriseEntitlementRespVO;
 import com.citu.module.menduner.system.controller.base.enterprise.vip.EnterpriseEntitlementSaveReqVO;
+import com.citu.module.menduner.system.controller.base.enterprise.vip.EnterpriseVipReqVO;
 import com.citu.module.menduner.system.dal.dataobject.enterprise.EnterpriseEntitlementDO;
 
 import javax.validation.Valid;
+import java.util.List;
 
 /**
  * 企业权益记录 Service 接口
@@ -65,4 +67,17 @@ public interface EnterpriseEntitlementService {
 
     /** 修改 **/
     void update(EnterpriseEntitlementDO entitlementDO);
+
+    /**
+     * 开通激活vip
+     **/
+    void activateVip(EnterpriseVipReqVO reqVO);
+
+    /**
+     * 根据企业编号获得企业权益记录
+     *
+     * @param enterpriseId 企业编号
+     * @return 企业权益记录
+     */
+    List<EnterpriseEntitlementRespVO>  getListByEnterpriseId(Long enterpriseId);
 }

+ 86 - 7
menduner/menduner-system-biz/src/main/java/com/citu/module/menduner/system/service/enterprise/vip/EnterpriseEntitlementServiceImpl.java

@@ -1,23 +1,23 @@
 package com.citu.module.menduner.system.service.enterprise.vip;
 
+import com.baomidou.dynamic.datasource.annotation.DSTransactional;
 import com.citu.framework.common.pojo.PageResult;
 import com.citu.framework.common.util.object.BeanUtils;
-import com.citu.module.menduner.system.controller.base.enterprise.vip.EnterpriseEntitlementPageReqVO;
-import com.citu.module.menduner.system.controller.base.enterprise.vip.EnterpriseEntitlementRespVO;
-import com.citu.module.menduner.system.controller.base.enterprise.vip.EnterpriseEntitlementSaveReqVO;
-import com.citu.module.menduner.system.controller.base.enterprise.vip.EnterprisePackageRespVO;
+import com.citu.module.menduner.system.controller.base.enterprise.vip.*;
 import com.citu.module.menduner.system.dal.dataobject.enterprise.EnterpriseDO;
 import com.citu.module.menduner.system.dal.dataobject.enterprise.EnterpriseEntitlementDO;
 import com.citu.module.menduner.system.dal.dataobject.enterprise.EnterprisePackageDO;
 import com.citu.module.menduner.system.dal.dataobject.enterprise.EnterpriseUserBindDO;
 import com.citu.module.menduner.system.dal.mysql.enterprise.EnterpriseEntitlementMapper;
-import com.citu.module.menduner.system.dal.mysql.enterprise.EnterpriseMapper;
+import com.citu.module.menduner.system.service.enterprise.EnterpriseService;
 import com.citu.module.menduner.system.service.enterprise.bind.EnterpriseUserBindService;
 import org.springframework.stereotype.Service;
+import org.springframework.util.StringUtils;
 import org.springframework.validation.annotation.Validated;
 
 import javax.annotation.Resource;
 import java.time.LocalDateTime;
+import java.util.List;
 
 import static com.citu.framework.common.exception.util.ServiceExceptionUtil.exception;
 import static com.citu.module.menduner.system.enums.ErrorCodeConstants.ENTERPRISE_ENTITLEMENT_NOT_EXISTS;
@@ -41,7 +41,17 @@ public class EnterpriseEntitlementServiceImpl implements EnterpriseEntitlementSe
     private EnterpriseUserBindService enterpriseBindService;
 
     @Resource
-    private EnterpriseMapper enterpriseMapper;
+    private EnterpriseService enterpriseService;
+
+    /**
+     * 判断给定的时间是否已过期
+     **/
+    public static boolean isExpired(LocalDateTime expiryTime) {
+        // 获取当前时间
+        LocalDateTime now = LocalDateTime.now();
+        // 比较当前时间和到期时间
+        return now.isAfter(expiryTime);
+    }
 
     @Override
     public Long createEnterpriseEntitlement(EnterpriseEntitlementSaveReqVO createReqVO) {
@@ -105,7 +115,7 @@ public class EnterpriseEntitlementServiceImpl implements EnterpriseEntitlementSe
         if (enterpriseBindService.checkIsAdmin(userBind)) {
             // 管理员
 
-            EnterpriseDO enterprise = enterpriseMapper.selectById(enterpriseId);
+            EnterpriseDO enterprise = enterpriseService.getEnterprise(enterpriseId);
 
             // 创建权益
             EnterpriseEntitlementDO insert = EnterpriseEntitlementDO.builder()
@@ -147,4 +157,73 @@ public class EnterpriseEntitlementServiceImpl implements EnterpriseEntitlementSe
     public void update(EnterpriseEntitlementDO entitlementDO) {
         mapper.updateById(entitlementDO);
     }
+
+    @Override
+    @DSTransactional
+    public void activateVip(EnterpriseVipReqVO reqVO) {
+        EnterpriseDO enterprise = enterpriseService.getEnterprise(reqVO.getEnterpriseId());
+        EnterprisePackageDO packageDO = enterprisePackageService.getEnterprisePackage(reqVO.getPackageId());
+        // 不算今天
+        long day = packageDO.getDay() + 1;
+
+        if (!StringUtils.hasText(enterprise.getVipFlag())) {
+            // 没有开过会员
+            enterprise.setVipFlag(String.valueOf(packageDO.getId()));
+            enterprise.setVipExpireDate(LocalDateTime.now().plusDays(day));
+        } else {
+            // 开过会员
+            if (isExpired(enterprise.getVipExpireDate())) {
+                // 过期值覆盖
+                enterprise.setVipFlag(String.valueOf(packageDO.getId()));
+                // 不算今天
+                enterprise.setVipExpireDate(LocalDateTime.now().plusDays(day));
+            } else {
+                // 没有过期
+                //  累加时间,如果当前权益大于user.getVipFlag()则覆盖,并且累加时间
+                // TODO 不允许小于当前权益
+                Long currentVipFlag = Long.parseLong(enterprise.getVipFlag());
+                Long newVipFlag = packageDO.getId();
+
+                if (currentVipFlag == Long.parseLong(enterprise.getVipFlag())) {
+                    // 买一样的,加天数
+                    enterprise.setVipExpireDate(enterprise.getVipExpireDate().plusDays(day));
+                } else if (newVipFlag > currentVipFlag) {
+                    // 新套餐大于套餐
+                    enterprise.setVipFlag(String.valueOf(packageDO.getId()));
+                    enterprise.setVipExpireDate(enterprise.getVipExpireDate().plusDays(day));
+                } else {
+                    // 新套餐小于套餐
+                    return;
+                }
+            }
+        }
+        // 修改会员
+        enterpriseService.updateVip(enterprise.getId(), enterprise.getVipFlag(), enterprise.getVipExpireDate());
+
+        // 找出管理员
+        EnterpriseUserBindDO userBind = enterpriseBindService.getByEnterpriseAdmin(enterprise.getId());
+        if (enterpriseBindService.checkIsAdmin(userBind)) {
+            // 管理员
+
+            // 创建权益
+            EnterpriseEntitlementDO insert = EnterpriseEntitlementDO.builder()
+                    .enterpriseId(userBind.getEnterpriseId())
+                    .userId(userBind.getUserId())
+                    .publishJobCount(packageDO.getPublishJobCount())
+                    .searchCount(packageDO.getSearchCount())
+                    .lookCvCount(packageDO.getLookCvCount())
+                    .personMap(packageDO.getPersonMap())
+                    .hireJob(packageDO.getHireJob())
+                    .build();
+
+            mapper.insert(insert);
+        }
+
+
+    }
+
+    @Override
+    public List<EnterpriseEntitlementRespVO> getListByEnterpriseId(Long enterpriseId) {
+        return  BeanUtils.toBean(mapper.selectListByEnterpriseId(enterpriseId), EnterpriseEntitlementRespVO.class);
+    }
 }

+ 7 - 0
menduner/menduner-system-biz/src/main/java/com/citu/module/menduner/system/service/enterprise/vip/EnterprisePackageService.java

@@ -68,4 +68,11 @@ public interface EnterprisePackageService {
      * @return 用户套餐列表
      */
     List<EnterprisePackageDO> getList();
+
+    /**
+     * 获得所有企业套餐列表
+     *
+     * @return 用户套餐列表
+     */
+    List<EnterprisePackageDO> getListAll();
 }

+ 6 - 1
menduner/menduner-system-biz/src/main/java/com/citu/module/menduner/system/service/enterprise/vip/EnterprisePackageServiceImpl.java

@@ -81,6 +81,11 @@ public class EnterprisePackageServiceImpl implements EnterprisePackageService {
 
     @Override
     public List<EnterprisePackageDO> getList() {
-        return mapper.list();
+        return mapper.list(true);
+    }
+
+    @Override
+    public List<EnterprisePackageDO> getListAll() {
+        return mapper.list(null);
     }
 }

+ 3 - 3
menduner/menduner-system-biz/src/test/java/com/citu/module/menduner/system/service/userapi/UserApiTest.java → menduner/menduner-system-biz/src/test/java/com/citu/module/menduner/system/service/userapi/MendunerUserApiTest.java

@@ -2,7 +2,7 @@ package com.citu.module.menduner.system.service.userapi;
 
 import com.citu.framework.common.pojo.CommonResult;
 import com.citu.framework.test.core.ut.BaseMockitoUnitTest;
-import com.citu.module.menduner.system.api.user.UserApi;
+import com.citu.module.menduner.system.api.user.MendunerUserApi;
 import com.citu.module.menduner.system.api.user.UserInfoReqDTO;
 import com.citu.module.menduner.system.api.user.UserInfoRespDTO;
 import com.citu.module.menduner.system.enums.user.MdeUserTypeEnum;
@@ -12,10 +12,10 @@ import java.util.ArrayList;
 import java.util.List;
 
 
-public class UserApiTest extends BaseMockitoUnitTest {
+public class MendunerUserApiTest extends BaseMockitoUnitTest {
 
     @Mock
-    private UserApi usersApi;
+    private MendunerUserApi usersApi;
 
 
     @org.junit.jupiter.api.Test