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

Merge branch 'master' of http://81.70.224.233:10080/slambb/FragrantTown_Server_Local

slambb 4 лет назад
Родитель
Сommit
977b194b67
37 измененных файлов с 1466 добавлено и 28 удалено
  1. 27 2
      pom.xml
  2. 2 0
      src/main/java/com/td/boss/BossApplication.java
  3. 29 0
      src/main/java/com/td/boss/game/comcnttosnb/controller/ComCntToSnbController.java
  4. 55 0
      src/main/java/com/td/boss/game/comcnttosnb/pojo/ComCntToSnb.java
  5. 14 0
      src/main/java/com/td/boss/game/comcnttosnb/repository/ComCntToSnbRespository.java
  6. 29 0
      src/main/java/com/td/boss/game/comcnttosnb/service/ComCntToSnbService.java
  7. 146 0
      src/main/java/com/td/boss/game/comcnttosnb/service/ComCntToSnbServiceImpl.java
  8. 52 0
      src/main/java/com/td/boss/game/comcnttosnb/vo/ComCntToSnbVo.java
  9. 22 6
      src/main/java/com/td/boss/game/complayerland/controller/ComPlayerLandController.java
  10. 23 0
      src/main/java/com/td/boss/game/complayerland/pojo/ComPlayerDisaster.java
  11. 60 0
      src/main/java/com/td/boss/game/complayerland/pojo/ComPlayerDisasterLog.java
  12. 30 0
      src/main/java/com/td/boss/game/complayerland/pojo/ComPlayerDisasterProtected.java
  13. 22 0
      src/main/java/com/td/boss/game/complayerland/repository/ComPlayerDisasterLogRepository.java
  14. 13 0
      src/main/java/com/td/boss/game/complayerland/repository/ComPlayerDisasterProtectedRepository.java
  15. 10 0
      src/main/java/com/td/boss/game/complayerland/repository/ComPlayerDisasterRepository.java
  16. 39 0
      src/main/java/com/td/boss/game/complayerland/scheduled/ComPlayerDisasterDateUtil.java
  17. 49 0
      src/main/java/com/td/boss/game/complayerland/scheduled/ComPlayerDisasterDayTask.java
  18. 53 0
      src/main/java/com/td/boss/game/complayerland/scheduled/ComPlayerDisasterWeekTask.java
  19. 66 0
      src/main/java/com/td/boss/game/complayerland/scheduled/QuartzConfig.java
  20. 37 0
      src/main/java/com/td/boss/game/complayerland/service/ComPlayerDisasterLogService.java
  21. 237 0
      src/main/java/com/td/boss/game/complayerland/service/ComPlayerDisasterLogServiceImpl.java
  22. 12 0
      src/main/java/com/td/boss/game/complayerland/service/ComPlayerDisasterProtectedService.java
  23. 27 0
      src/main/java/com/td/boss/game/complayerland/service/ComPlayerDisasterProtectedServiceImpl.java
  24. 18 0
      src/main/java/com/td/boss/game/complayerland/service/ComPlayerDisasterService.java
  25. 93 0
      src/main/java/com/td/boss/game/complayerland/service/ComPlayerDisasterServiceImpl.java
  26. 18 0
      src/main/java/com/td/boss/game/complayerland/vo/ComPlayerDisasterEnum.java
  27. 58 0
      src/main/java/com/td/boss/game/complayerland/vo/ComPlayerDisasterLogVo.java
  28. 26 0
      src/main/java/com/td/boss/game/complayerland/vo/ComPlayerDisasterProtectedVo.java
  29. 15 0
      src/main/java/com/td/boss/game/complayerland/vo/ComPlayerDisasterVo.java
  30. 5 0
      src/main/java/com/td/boss/game/complayers/repository/ComPlayersRepository.java
  31. 3 1
      src/main/java/com/td/boss/game/complayers/service/ComPlayersService.java
  32. 9 2
      src/main/java/com/td/boss/game/complayers/service/ComPlayersServiceImpl.java
  33. 37 0
      src/main/java/com/td/boss/util/DappUtil.java
  34. 16 0
      src/main/java/com/td/boss/util/RedisData.java
  35. 5 4
      src/main/resources/application.yml
  36. 0 13
      src/test/java/com/td/boss/BossApplicationTests.java
  37. 109 0
      src/test/java/com/td/boss/ComPlayerDisasterLogTests.java

+ 27 - 2
pom.xml

@@ -22,17 +22,37 @@
             <artifactId>spring-boot-starter</artifactId>
         </dependency>
 
+        <dependency>
+            <groupId>cn.hutool</groupId>
+            <artifactId>hutool-all</artifactId>
+            <version>5.3.2</version>
+        </dependency>
         <dependency>
             <groupId>org.projectlombok</groupId>
             <artifactId>lombok</artifactId>
-            <optional>true</optional>
+            <version>1.18.20</version>
+            <scope>provided</scope>
         </dependency>
         <dependency>
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-starter-test</artifactId>
             <scope>test</scope>
+            <exclusions>
+                <exclusion>
+                    <groupId>com.vaadin.external.google</groupId>
+                    <artifactId>android-json</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-quartz</artifactId>
         </dependency>
-		
 		        <!--热部署工具dev-tools-->
         <dependency>
             <groupId>org.springframework.boot</groupId>
@@ -135,6 +155,11 @@
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-starter-data-redis</artifactId>
         </dependency>
+        <dependency>
+            <groupId>cn.hutool</groupId>
+            <artifactId>hutool-all</artifactId>
+            <version>5.7.22</version>
+        </dependency>
 
     </dependencies>
 

+ 2 - 0
src/main/java/com/td/boss/BossApplication.java

@@ -20,6 +20,7 @@ import org.springframework.cache.annotation.EnableCaching;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.scheduling.annotation.EnableAsync;
+import org.springframework.scheduling.annotation.EnableScheduling;
 import org.springframework.security.core.session.SessionRegistry;
 import org.springframework.security.core.session.SessionRegistryImpl;
 import org.springframework.stereotype.Controller;
@@ -39,6 +40,7 @@ import java.util.List;
 
 @EnableAsync//开启异步调用
 @EnableCaching// 开启缓存,需要显示的指定
+@EnableScheduling
 @SpringBootApplication
 public class BossApplication {
 

+ 29 - 0
src/main/java/com/td/boss/game/comcnttosnb/controller/ComCntToSnbController.java

@@ -0,0 +1,29 @@
+package com.td.boss.game.comcnttosnb.controller;
+
+import com.td.boss.common.controller.CommonController;
+import com.td.boss.common.pojo.Result;
+import com.td.boss.game.comcnttosnb.pojo.ComCntToSnb;
+import com.td.boss.game.comcnttosnb.service.ComCntToSnbService;
+import com.td.boss.game.comcnttosnb.vo.ComCntToSnbVo;
+import org.springframework.beans.factory.annotation.Autowired;
+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;
+
+@RestController
+@RequestMapping("/game/comCntToSnb/")
+public class ComCntToSnbController extends CommonController<ComCntToSnbVo, ComCntToSnb, Integer> {
+    @Autowired
+    private ComCntToSnbService comCntToSnbService;
+
+    @GetMapping("get")
+    public Result<ComCntToSnbVo> get(@RequestParam(value = "userId") String userId) {
+        return Result.of(comCntToSnbService.findByUserId(userId));
+    }
+
+    @GetMapping("receive")
+    public Result<String> receive(@RequestParam(value = "userId") String userId) {
+        return comCntToSnbService.receiveByUserId(userId);
+    }
+}

+ 55 - 0
src/main/java/com/td/boss/game/comcnttosnb/pojo/ComCntToSnb.java

@@ -0,0 +1,55 @@
+package com.td.boss.game.comcnttosnb.pojo;
+
+import lombok.Data;
+
+import javax.persistence.*;
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.util.Date;
+
+/**
+ * cnt转snb
+ *
+ * @author why
+ * @date 2022/03/05
+ */
+@Data
+@Entity
+@Table(name = "com_cnt_to_snb")
+public class ComCntToSnb implements Serializable {
+    @Id
+    @GeneratedValue(strategy= GenerationType.IDENTITY)
+    private Integer id;
+    /**
+     * 用户id
+     */
+    private String userId;
+    /**
+     * 需要返还的总数
+     */
+    private BigDecimal totalQuantity;
+    /**
+     * 已领取数量
+     */
+    private BigDecimal receivedQuantity;
+    /**
+     * 单位数量(每天可领取量)
+     */
+    private BigDecimal unitQuantity;
+    /**
+     * 领取总天数
+     */
+    private Integer totalDay;
+    /**
+     * 已领取天数
+     */
+    private Integer receivedDay;
+    /**
+     * 开始时间
+     */
+    private Date beginTime;
+    /**
+     * 状态(0=不可领取,1=可以领取)
+     */
+    private Integer status;
+}

+ 14 - 0
src/main/java/com/td/boss/game/comcnttosnb/repository/ComCntToSnbRespository.java

@@ -0,0 +1,14 @@
+package com.td.boss.game.comcnttosnb.repository;
+
+import com.td.boss.common.repository.CommonRepository;
+import com.td.boss.game.comcnttosnb.pojo.ComCntToSnb;
+import org.springframework.stereotype.Repository;
+
+import java.util.Optional;
+
+@Repository
+public interface ComCntToSnbRespository extends CommonRepository<ComCntToSnb, Integer> {
+
+    Optional<ComCntToSnb> findByUserId(String userId);
+
+}

+ 29 - 0
src/main/java/com/td/boss/game/comcnttosnb/service/ComCntToSnbService.java

@@ -0,0 +1,29 @@
+package com.td.boss.game.comcnttosnb.service;
+
+import com.td.boss.common.pojo.Result;
+import com.td.boss.common.service.CommonService;
+import com.td.boss.game.comcnttosnb.pojo.ComCntToSnb;
+import com.td.boss.game.comcnttosnb.vo.ComCntToSnbVo;
+
+/**
+ * Cnt转Snb服务实现
+ *
+ * @author why
+ * @date 2022/03/05
+ */
+public interface ComCntToSnbService extends CommonService<ComCntToSnbVo, ComCntToSnb, Integer> {
+    /**
+     * 通过userid查看snb领取情况
+     *
+     * @param userId 用户id
+     * @return {@link ComCntToSnbVo}
+     */
+    ComCntToSnbVo findByUserId(String userId);
+
+    /**
+     * 通过userid领取snb
+     *
+     * @param userId 用户id
+     */
+    Result<String> receiveByUserId(String userId);
+}

+ 146 - 0
src/main/java/com/td/boss/game/comcnttosnb/service/ComCntToSnbServiceImpl.java

@@ -0,0 +1,146 @@
+package com.td.boss.game.comcnttosnb.service;
+
+import cn.hutool.core.convert.Convert;
+import cn.hutool.core.date.DateUtil;
+import cn.hutool.core.util.NumberUtil;
+import cn.hutool.core.util.StrUtil;
+import com.td.boss.common.pojo.Result;
+import com.td.boss.common.service.CommonServiceImpl;
+import com.td.boss.config.enums.ResultEnum;
+import com.td.boss.game.comcnttosnb.pojo.ComCntToSnb;
+import com.td.boss.game.comcnttosnb.repository.ComCntToSnbRespository;
+import com.td.boss.game.comcnttosnb.vo.ComCntToSnbVo;
+import com.td.boss.game.comsnbtran.service.ComSnbTranService;
+import com.td.boss.game.comsnbtran.vo.ComSnbTranVo;
+import com.td.boss.game.comusers.service.ComUsersService;
+import com.td.boss.game.comusers.vo.ComUsersVo;
+import com.td.boss.util.CopyUtil;
+import com.td.boss.util.RedisData;
+import com.td.boss.util.RedisLock;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.math.BigDecimal;
+import java.util.Date;
+
+@Slf4j
+@Service
+public class ComCntToSnbServiceImpl extends CommonServiceImpl<ComCntToSnbVo, ComCntToSnb, Integer> implements ComCntToSnbService {
+
+    @Autowired
+    private ComCntToSnbRespository comCntToSnbRespository;
+    @Autowired
+    private ComUsersService comUsersService;
+    @Autowired
+    private ComSnbTranService comSnbTranService;
+    @Autowired
+    private RedisLock redisLock;
+
+    /**
+     * 通过userid查看snb领取情况
+     *
+     * @param userId 用户id
+     * @return {@link ComCntToSnbVo}
+     */
+    @Override
+    public ComCntToSnbVo findByUserId(String userId) {
+        ComCntToSnb comCntToSnb = comCntToSnbRespository.findByUserId(userId).orElse(null);
+        return comCntToSnb == null ? null : CopyUtil.copy(comCntToSnb, ComCntToSnbVo.class);
+    }
+
+    /**
+     * 通过userid领取snb
+     *
+     * @param userId 用户id
+     * @return {@link Result}<{@link String}>
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Result<String> receiveByUserId(String userId) {
+
+        ComCntToSnb comCntToSnb = comCntToSnbRespository.findByUserId(userId).orElse(null);
+        if (comCntToSnb == null || comCntToSnb.getStatus().equals(0)) {
+            return Result.of(null, false, "非法领取");
+        }
+        if (comCntToSnb.getReceivedDay() >= comCntToSnb.getTotalDay()) {
+            return Result.of(null, false, "已全部领取完毕");
+        }
+        // 服务器时间
+        Date serverDate = new Date();
+        // 未到领取时间
+        if (DateUtil.compare(comCntToSnb.getBeginTime(), serverDate) > 0) {
+            return Result.of(null, false, "未到领取时间");
+        }
+        // 计算本次可领天数. 服务器时间 - 开始时间 - 已领取天数
+        Integer day = Convert.toInt(DateUtil.betweenDay(comCntToSnb.getBeginTime(), serverDate, true)) - comCntToSnb.getReceivedDay() + 1;
+        log.info("领取人:" + userId);
+        log.info("领取开始时间:" + DateUtil.format(comCntToSnb.getBeginTime(), "yyyy-MM-dd"));
+        log.info("服务器时间:" + DateUtil.format(serverDate, "yyyy-MM-dd"));
+        log.info("已领取:" + comCntToSnb.getReceivedDay() + "天,本次领取天数:" + day + "天");
+        if (day <= 0) {
+            return Result.of(null, false, "领取失败,今日已领取");
+        }
+        // 特例:领取周期100天,这个人间隔100以后上线
+        if (day > comCntToSnb.getTotalDay() - comCntToSnb.getReceivedDay()) {
+            day = comCntToSnb.getTotalDay() - comCntToSnb.getReceivedDay();
+            log.info("由于本次领取天数大于剩余领取天数,所以最终领取天数:" + day);
+        }
+        long time = System.currentTimeMillis() + RedisData.getSnbTimeout();
+        String redisKey = StrUtil.format("SNB_SAVE_{}", userId);
+
+        try {
+            // redis锁
+            if (!redisLock.lock(redisKey, String.valueOf(time))) {
+                return Result.of(null, false, ResultEnum.SEED_SALE_SAVE_LOCK.getMessage(), ResultEnum.SEED_SALE_SAVE_LOCK.getCode());
+            }
+
+            // 本次领取量
+            BigDecimal thisReceiveQuantity = NumberUtil.mul(comCntToSnb.getUnitQuantity(), day);
+            comCntToSnb.setReceivedQuantity(comCntToSnb.getReceivedQuantity().add(thisReceiveQuantity));
+            // 本次领取天数
+            comCntToSnb.setReceivedDay(comCntToSnb.getReceivedDay() + day);
+            // 更新领取信息
+            comCntToSnbRespository.save(comCntToSnb);
+
+            // 更新comUsers snb+
+            ComUsersVo comUsersVo = comUsersService.findByUserId(userId);
+            comUsersVo.setSnbPart(comUsersVo.getSnbPart() + Convert.toDouble(thisReceiveQuantity));
+            comUsersService.save(comUsersVo);
+
+            // 插入comSnbTran
+            ComSnbTranVo snbTran = new ComSnbTranVo();
+            //记录兑换id
+            snbTran.setTranId(Convert.toStr(comCntToSnb.getId()));
+            snbTran.setUserId(userId);
+            snbTran.setTranName("领取SNB");
+//            snbTran.setTranType();
+            snbTran.setTranAmount(Convert.toInt(thisReceiveQuantity));
+//            snbTran.setTranPrice();
+            snbTran.setTranDescribe(StrUtil.format("user领取SNB、本次领取:{},剩余:{}", thisReceiveQuantity, comCntToSnb.getTotalQuantity().subtract(comCntToSnb.getReceivedQuantity())));
+            snbTran.setIsAdd(1);
+            snbTran.setBeforeSnb(0);
+            snbTran.setTranSnb(0);
+            snbTran.setAfterSnb(0);
+            // 交易的部分数据
+//            snbTran.setTranAmountPart(0d);
+            // 交易的snb
+            snbTran.setTranSnbPart(Convert.toDouble(thisReceiveQuantity));
+            // 交易之前的snb
+            snbTran.setBeforeSnbPart(Convert.toDouble(comCntToSnb.getReceivedQuantity().subtract(thisReceiveQuantity)));
+            // 交易完成后的snb
+            snbTran.setAfterSnbPart(Convert.toDouble(comCntToSnb.getReceivedQuantity()));
+            snbTran.setCreateTime(serverDate);
+            comSnbTranService.save(snbTran);
+
+            return Result.of(null, false, "领取成功");
+
+        } catch (Exception e) {
+            throw new RuntimeException(e.getMessage());
+        } finally {
+            // redis解锁
+            redisLock.unlock(redisKey, String.valueOf(time));
+        }
+    }
+}

+ 52 - 0
src/main/java/com/td/boss/game/comcnttosnb/vo/ComCntToSnbVo.java

@@ -0,0 +1,52 @@
+package com.td.boss.game.comcnttosnb.vo;
+
+import lombok.Data;
+
+import javax.persistence.*;
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.util.Date;
+
+/**
+ * cnt转snb
+ *
+ * @author why
+ * @date 2022/03/05
+ */
+@Data
+public class ComCntToSnbVo implements Serializable {
+
+    private Integer id;
+    /**
+     * 用户id
+     */
+    private String userId;
+    /**
+     * 需要返还的总数
+     */
+    private BigDecimal totalQuantity;
+    /**
+     * 已领取数量
+     */
+    private BigDecimal receivedQuantity;
+    /**
+     * 单位数量(每天可领取量)
+     */
+    private BigDecimal unitQuantity;
+    /**
+     * 领取总天数
+     */
+    private Integer totalDay;
+    /**
+     * 已领取天数
+     */
+    private Integer receivedDay;
+    /**
+     * 开始时间
+     */
+    private Date beginTime;
+    /**
+     * 状态(0=不可领取,1=可以领取)
+     */
+    private Integer status;
+}

+ 22 - 6
src/main/java/com/td/boss/game/complayerland/controller/ComPlayerLandController.java

@@ -7,6 +7,8 @@ import com.td.boss.game.comexplainland.service.ComExplainLandService;
 import com.td.boss.game.comexplainland.vo.ComExplainLandVo;
 import com.td.boss.game.commallseed.service.ComMallSeedService;
 import com.td.boss.game.commallseed.vo.ComMallSeedVo;
+import com.td.boss.game.complayerland.pojo.ComPlayerDisasterLog;
+import com.td.boss.game.complayerland.service.ComPlayerDisasterLogService;
 import com.td.boss.game.complayergoods.pojo.ComPlayerGoods;
 import com.td.boss.game.complayergoods.service.ComPlayerGoodsService;
 import com.td.boss.game.complayergoods.vo.ComPlayerGoodsVo;
@@ -19,9 +21,7 @@ import com.td.boss.game.complayerland.vo.ComPlayerLandVo;
 import com.td.boss.game.complayerland.service.ComPlayerLandService;
 import com.td.boss.game.complayerlog.service.ComPlayerLogService;
 import com.td.boss.game.complayerlog.vo.ComPlayerLogVo;
-import com.td.boss.util.CopyUtil;
-import com.td.boss.util.DateUtil;
-import com.td.boss.util.UUIDUtil;
+import com.td.boss.util.*;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.data.domain.PageRequest;
@@ -53,6 +53,9 @@ public class ComPlayerLandController extends CommonController<ComPlayerLandVo, C
     @Autowired
     private ComExplainLandService comExplainLandService;
 
+    @Autowired
+    private ComPlayerDisasterLogService comPlayerDisasterLogService;
+
 
     /**
      * 获取用户土地
@@ -153,10 +156,10 @@ public class ComPlayerLandController extends CommonController<ComPlayerLandVo, C
      */
     @GetMapping("getCanStealDetailList")
     public Result<List<ComPlayerLandAndPlantVo>> getCanStealListFunction(
-                                                                 @RequestParam(value = "userId") String userId,
-                                                                 @RequestParam(value = "otherUserId") String otherUserId) {
+            @RequestParam(value = "userId") String userId,
+            @RequestParam(value = "otherUserId") String otherUserId) {
 
-        List<ComPlayerLandAndCanSteal> comPlayerLands = comPlayerLandService.findCanStealByUserIdAndOtherUserId(userId,otherUserId);
+        List<ComPlayerLandAndCanSteal> comPlayerLands = comPlayerLandService.findCanStealByUserIdAndOtherUserId(userId, otherUserId);
         List<ComPlayerLandAndPlantVo> _simpleVoList = CopyUtil.copyList(comPlayerLands, ComPlayerLandAndPlantVo.class);
         List<ComPlayerLandAndPlantVo> _list = new ArrayList<>();
         try {
@@ -438,4 +441,17 @@ public class ComPlayerLandController extends CommonController<ComPlayerLandVo, C
 
         return Result.of(comPlayerLands);
     }
+
+
+    /**
+     * 获得某个用个 灾难情况
+     * @param userId
+     * @return
+     */
+    @GetMapping("getDisasterHistory")
+    @Transactional(rollbackFor = Exception.class)
+    public Result<List<ComPlayerDisasterLog>> getDisasterHistory(@RequestParam(value = "userId") String userId) {
+        List<ComPlayerDisasterLog> history = comPlayerDisasterLogService.getHistory(userId);
+        return Result.of(history);
+    }
 }

+ 23 - 0
src/main/java/com/td/boss/game/complayerland/pojo/ComPlayerDisaster.java

@@ -0,0 +1,23 @@
+package com.td.boss.game.complayerland.pojo;
+
+import lombok.Data;
+
+import javax.persistence.*;
+import java.io.Serializable;
+import java.util.Date;
+
+@Entity
+@Table(name = "com_player_dsaster")
+@Data
+public class ComPlayerDisaster implements Serializable {
+    @Id
+    @GeneratedValue(strategy= GenerationType.IDENTITY)
+    private long id;
+    private Double income;
+    private Double payment;
+    private String log;
+    private String userId;
+    private Date createTime;
+    private Date beginTime;
+    private Date endTime;
+}

+ 60 - 0
src/main/java/com/td/boss/game/complayerland/pojo/ComPlayerDisasterLog.java

@@ -0,0 +1,60 @@
+package com.td.boss.game.complayerland.pojo;
+
+import lombok.Data;
+
+import javax.persistence.*;
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * 自然灾害与防护包功能模块
+ */
+@Entity
+@Table(name = "com_player_dsaster_log")
+@Data
+public class ComPlayerDisasterLog implements Serializable {
+    @Id
+    @GeneratedValue(strategy= GenerationType.IDENTITY)
+    private long id;
+
+    /**
+     * 主表id
+     */
+    private long dsasterId;
+    /**
+     * 灾难名称
+     */
+    private String dsasterName;
+    private Integer dsasterType;
+    /**
+     * 伤害 会减产50%
+     */
+    private int damage;
+
+    /**
+     * 防御 90%概率防御灾难
+     */
+    private double defend;
+
+    /**
+     * 防护截止时间
+     */
+    private Date protectTime;
+
+    /**
+     * 本次灾难是否激活防护
+     */
+    private boolean isProtect;
+    private String userId;
+    private Date createTime;
+    private Date updateTime;
+    /**
+     * 前端 是否以显示
+     */
+    private boolean isShow;
+    /**
+     * 是否已经使用,灾害是预先生成的
+     */
+    private boolean isEnabled;
+    private Date disasterTime;
+}

+ 30 - 0
src/main/java/com/td/boss/game/complayerland/pojo/ComPlayerDisasterProtected.java

@@ -0,0 +1,30 @@
+package com.td.boss.game.complayerland.pojo;
+
+import lombok.Data;
+
+import javax.persistence.*;
+import java.io.Serializable;
+import java.util.Date;
+
+@Entity
+@Table(name = "com_player_dsaster_protected")
+@Data
+public class ComPlayerDisasterProtected implements Serializable {
+    @Id
+    @GeneratedValue(strategy= GenerationType.IDENTITY)
+    private long id;
+    /**
+     * 灾难名称
+     */
+    private String dsasterName;
+    private Integer dsasterType;
+
+    /**
+     * 保护时间
+     */
+    private Date protectTime;
+    private String userId;
+    private Date createTime;
+    private Date updateTime;
+    private String orderId;
+}

+ 22 - 0
src/main/java/com/td/boss/game/complayerland/repository/ComPlayerDisasterLogRepository.java

@@ -0,0 +1,22 @@
+package com.td.boss.game.complayerland.repository;
+
+import com.td.boss.common.repository.CommonRepository;
+import com.td.boss.game.complayerland.pojo.ComPlayerDisasterLog;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.stereotype.Repository;
+
+import java.util.List;
+
+@Repository
+public interface ComPlayerDisasterLogRepository extends CommonRepository<ComPlayerDisasterLog, String> {
+
+    /**
+     * 获取已发生未读的灾难集合
+     * @param userId
+     * @return
+     */
+    @Query(value = "select * from com_player_dsaster_log where user_id = ?1 and `is_show`=0 and `is_enabled`=1",nativeQuery=true)
+    List<ComPlayerDisasterLog> getUnShowAndEnabled(String userId);
+
+    ComPlayerDisasterLog findByUserId(String userId);
+}

+ 13 - 0
src/main/java/com/td/boss/game/complayerland/repository/ComPlayerDisasterProtectedRepository.java

@@ -0,0 +1,13 @@
+package com.td.boss.game.complayerland.repository;
+
+import com.td.boss.common.repository.CommonRepository;
+import com.td.boss.game.complayerland.pojo.ComPlayerDisasterProtected;
+import org.springframework.stereotype.Repository;
+
+import java.util.List;
+
+@Repository
+public interface ComPlayerDisasterProtectedRepository extends CommonRepository<ComPlayerDisasterProtected, String> {
+
+    public List<ComPlayerDisasterProtected> getComPlayerDisasterProtectedsByUserId(String userId);
+}

+ 10 - 0
src/main/java/com/td/boss/game/complayerland/repository/ComPlayerDisasterRepository.java

@@ -0,0 +1,10 @@
+package com.td.boss.game.complayerland.repository;
+
+import com.td.boss.common.repository.CommonRepository;
+import com.td.boss.game.complayerland.pojo.ComPlayerDisaster;
+import org.springframework.stereotype.Repository;
+
+@Repository
+public interface ComPlayerDisasterRepository extends CommonRepository<ComPlayerDisaster, String> {
+
+}

+ 39 - 0
src/main/java/com/td/boss/game/complayerland/scheduled/ComPlayerDisasterDateUtil.java

@@ -0,0 +1,39 @@
+package com.td.boss.game.complayerland.scheduled;
+
+import cn.hutool.core.date.DateField;
+import cn.hutool.core.date.DateUtil;
+import cn.hutool.core.date.Week;
+
+import java.util.Date;
+
+/**
+ * 每周是从周日到下周六
+ */
+public class ComPlayerDisasterDateUtil {
+
+    /**
+     * 获取本周开始时间
+     * @return
+     */
+    public static Date getBegin() {
+        Date now = new Date();
+        if (Week.SUNDAY == DateUtil.dayOfWeekEnum(now)) {
+            return DateUtil.beginOfDay(now);
+        } else {
+            return DateUtil.beginOfWeek(now).offset(DateField.DAY_OF_WEEK, -1);
+        }
+    }
+
+    /**
+     * 获取本周截止时间
+     * @return
+     */
+    public static Date getEnd() {
+        Date now = new Date();
+        if (Week.SUNDAY == DateUtil.dayOfWeekEnum(now)) {
+            return DateUtil.endOfDay(now).offset(DateField.DAY_OF_WEEK, 6);
+        } else {
+            return DateUtil.endOfWeek(now).offset(DateField.DAY_OF_WEEK, -1);
+        }
+    }
+}

+ 49 - 0
src/main/java/com/td/boss/game/complayerland/scheduled/ComPlayerDisasterDayTask.java

@@ -0,0 +1,49 @@
+package com.td.boss.game.complayerland.scheduled;
+
+import cn.hutool.core.date.DateUtil;
+import com.td.boss.game.complayerland.pojo.ComPlayerDisasterLog;
+import com.td.boss.game.complayerland.service.ComPlayerDisasterLogService;
+import com.td.boss.util.RedisData;
+import com.td.boss.util.RedisLock;
+import lombok.extern.slf4j.Slf4j;
+import org.quartz.JobExecutionContext;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.scheduling.annotation.EnableScheduling;
+import org.springframework.scheduling.quartz.QuartzJobBean;
+
+import java.util.Date;
+import java.util.List;
+
+@Slf4j
+@EnableScheduling
+public class ComPlayerDisasterDayTask extends QuartzJobBean {
+
+    @Autowired
+    private ComPlayerDisasterLogService comPlayerDisasterLogService;
+    @Autowired
+    private RedisLock redisLock;
+
+    @Override
+    protected void executeInternal(JobExecutionContext jobExecutionContext) {
+        log.info("触发灾难周期任务开始");
+        long time = System.currentTimeMillis() + RedisData.getDisastersDayTimeout();
+        String _redisKey = "LOCK:COM_PLAYER_DISASTER:DAY:" + DateUtil.format(new Date(), "yyyyMMdd");
+
+        if (!redisLock.lock(_redisKey, String.valueOf(time))) {
+            log.info("触发每天灾难任务加锁失败!");
+            return;
+        }
+        //把今天灾难的明细取出来。按照用户编号计算是否有防护。
+        List<ComPlayerDisasterLog> disasterLogList = comPlayerDisasterLogService.getTodayDisasterUnEnabledList();
+        log.info("触发每天灾难任务:{}个", disasterLogList.size());
+        for (ComPlayerDisasterLog disasterLog : disasterLogList) {
+            try {
+                comPlayerDisasterLogService.ComPlayerDisasterDayTask(disasterLog);
+            } catch (Exception e) {
+                log.error("触发灾难周期任务异常(天):" + e.getMessage());
+            }
+        }
+        redisLock.unlock(_redisKey, String.valueOf(time));
+        log.info("触发灾难周期任务结束");
+    }
+}

+ 53 - 0
src/main/java/com/td/boss/game/complayerland/scheduled/ComPlayerDisasterWeekTask.java

@@ -0,0 +1,53 @@
+package com.td.boss.game.complayerland.scheduled;
+
+import cn.hutool.core.date.DateUtil;
+import com.td.boss.game.complayerland.service.ComPlayerDisasterLogService;
+import com.td.boss.game.complayers.service.ComPlayersService;
+import com.td.boss.util.RedisData;
+import com.td.boss.util.RedisLock;
+import lombok.extern.slf4j.Slf4j;
+import org.quartz.JobExecutionContext;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.scheduling.annotation.EnableScheduling;
+import org.springframework.scheduling.quartz.QuartzJobBean;
+
+import java.util.Date;
+import java.util.List;
+
+@Slf4j
+@EnableScheduling
+public class ComPlayerDisasterWeekTask extends QuartzJobBean {
+
+    @Autowired
+    private ComPlayerDisasterLogService disasterLogService;
+    @Autowired
+    private ComPlayersService comPlayersService;
+    @Autowired
+    private RedisLock redisLock;
+
+    @Override
+    protected void executeInternal(JobExecutionContext jobExecutionContext) {
+        log.info("每周拉取灾难数据周期任务开始");
+
+        long time = System.currentTimeMillis() + RedisData.getDisastersWeekTimeout();
+        String _redisKey = "LOCK:COM_PLAYER_DISASTER:WEEK:" + DateUtil.format(new Date(), "yyyyMMdd");
+
+        if (!redisLock.lock(_redisKey, String.valueOf(time))) {
+            log.info("每周拉取灾难数据周期任务加锁失败!");
+            return;
+        }
+
+        List<String> userIds = comPlayersService.findUserIds();
+        log.info("拉取灾难接口数据周期任务数量:{}个", userIds.size());
+        for (String userId : userIds) {
+            try {
+                disasterLogService.asyncDisaster(userId);
+            } catch (Exception e) {
+                log.error("触发灾难周期任务异常(周):" + e.getMessage());
+            }
+        }
+
+        redisLock.unlock(_redisKey, String.valueOf(time));
+        log.info("每周拉取灾难数据周期任务结束");
+    }
+}

+ 66 - 0
src/main/java/com/td/boss/game/complayerland/scheduled/QuartzConfig.java

@@ -0,0 +1,66 @@
+package com.td.boss.game.complayerland.scheduled;
+
+import org.quartz.*;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+public class QuartzConfig {
+
+//    private static String JOB_GROUP_NAME = "JOBGROUP_ComPlayerDisaster";
+//    private static String TRIGGER_GROUP_NAME = "TRIGGERGROUP_ComPlayerDisaster";
+
+    private static String WeekTrigger = "0 0/1 * * * ?";
+    private static String DayTrigger = "0/5 * * * * ?";
+//    //每周日1点
+//    private static String WeekTrigger = "0 0 1 ? * SUN";
+//    //每天6点
+//    private static String DayTrigger = "0 0 6 * * ? *";
+
+    @Bean
+    public JobDetail syncDisasterWeekDetail() {
+        JobDetail jobDetail = JobBuilder.newJob(ComPlayerDisasterWeekTask.class)
+//                .withIdentity("syncUserJobDetail", JOB_GROUP_NAME)
+                .storeDurably() //即使没有Trigger关联时,也不需要删除该JobDetail
+                .build();
+        return jobDetail;
+    }
+
+    @Bean
+    public Trigger syncDisasterWeekTrigger() {
+        //每隔5秒执行一次
+        CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(WeekTrigger);
+
+        //创建触发器
+        Trigger trigger = TriggerBuilder.newTrigger()
+                .forJob(syncDisasterWeekDetail())
+//                .withIdentity("syncUserJobTrigger", TRIGGER_GROUP_NAME)
+                .withSchedule(cronScheduleBuilder)
+                .build();
+        return trigger;
+    }
+
+
+    @Bean
+    public JobDetail syncDisasterDayJobDetail() {
+        JobDetail jobDetail = JobBuilder.newJob(ComPlayerDisasterDayTask.class)
+//                .withIdentity("syncDisasterDayJobDetail", JOB_GROUP_NAME)
+                .storeDurably()
+                .build();
+        return jobDetail;
+    }
+
+    @Bean
+    public Trigger syncDisasterDayTrigger() {
+        //每隔5秒执行一次
+        CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(DayTrigger);
+
+        //创建触发器
+        Trigger trigger = TriggerBuilder.newTrigger()
+                .forJob(syncDisasterDayJobDetail())
+//                .withIdentity("syncDisasterDayTrigger", TRIGGER_GROUP_NAME)
+                .withSchedule(cronScheduleBuilder)
+                .build();
+        return trigger;
+    }
+}

+ 37 - 0
src/main/java/com/td/boss/game/complayerland/service/ComPlayerDisasterLogService.java

@@ -0,0 +1,37 @@
+package com.td.boss.game.complayerland.service;
+
+import com.td.boss.common.service.CommonService;
+import com.td.boss.game.complayerland.pojo.ComPlayerDisasterLog;
+import com.td.boss.game.complayerland.vo.ComPlayerDisasterLogVo;
+
+import java.util.List;
+
+public interface ComPlayerDisasterLogService extends CommonService<ComPlayerDisasterLogVo, ComPlayerDisasterLog, String> {
+
+    /**
+     * 定时任务核心方法 同步每个用户上周收入支出
+     * 灾难模式每周统计一次,如果这个期间新用户也需要这个功能。新注册的用户直接调用该方法。
+     */
+    void asyncDisaster(String userId);
+
+
+    /**
+     * 获取今天的灾难,并且没有触发过的灾难
+     *
+     * @return
+     */
+    List<ComPlayerDisasterLog> getTodayDisasterUnEnabledList();
+
+    /**
+     * 灾难模式天任务:触发所有用户今日灾难和保护机制
+     */
+    void ComPlayerDisasterDayTask(ComPlayerDisasterLog disasterLog);
+
+    /**
+     * 获取经历的灾难记录
+     *
+     * @param userId
+     * @return
+     */
+    List<ComPlayerDisasterLog> getHistory(String userId);
+}

+ 237 - 0
src/main/java/com/td/boss/game/complayerland/service/ComPlayerDisasterLogServiceImpl.java

@@ -0,0 +1,237 @@
+package com.td.boss.game.complayerland.service;
+
+import cn.hutool.core.date.DateField;
+import cn.hutool.core.date.DateRange;
+import cn.hutool.core.date.DateTime;
+import cn.hutool.core.date.DateUtil;
+import cn.hutool.core.util.EnumUtil;
+import cn.hutool.core.util.NumberUtil;
+import cn.hutool.core.util.RandomUtil;
+import cn.hutool.json.JSONUtil;
+import com.td.boss.common.service.CommonServiceImpl;
+import com.td.boss.game.complayerland.pojo.ComPlayerDisaster;
+import com.td.boss.game.complayerland.pojo.ComPlayerDisasterLog;
+import com.td.boss.game.complayerland.pojo.ComPlayerDisasterProtected;
+import com.td.boss.game.complayerland.repository.ComPlayerDisasterLogRepository;
+import com.td.boss.game.complayerland.scheduled.ComPlayerDisasterDateUtil;
+import com.td.boss.game.complayerland.vo.ComPlayerDisasterEnum;
+import com.td.boss.game.complayerland.vo.ComPlayerDisasterLogVo;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.jpa.domain.Specification;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import javax.persistence.criteria.CriteriaBuilder;
+import javax.persistence.criteria.CriteriaQuery;
+import javax.persistence.criteria.Predicate;
+import javax.persistence.criteria.Root;
+import java.util.*;
+import java.util.stream.Collectors;
+
+@Slf4j
+@Service
+@Transactional
+public class ComPlayerDisasterLogServiceImpl extends CommonServiceImpl<ComPlayerDisasterLogVo, ComPlayerDisasterLog, String> implements ComPlayerDisasterLogService {
+    @Autowired
+    private ComPlayerDisasterLogRepository disasterLogRepository;
+
+    @Autowired
+    private ComPlayerDisasterProtectedService disasterProtectedService;
+
+    @Autowired
+    private ComPlayerDisasterService disasterService;
+
+    /**
+     * 伤害 会减产50%
+     */
+    private int damage = 50;
+
+    /**
+     * 防御 90%概率防御灾难
+     */
+    private double defend = 90;
+
+    /**
+     * 获取经历的灾难记录
+     *
+     * @param userId
+     * @return
+     */
+    @Override
+    public List<ComPlayerDisasterLog> getHistory(String userId) {
+        //获取已发生未读的灾难集合
+        List<ComPlayerDisasterLog> list = disasterLogRepository.getUnShowAndEnabled(userId).stream().sorted(Comparator.comparing(ComPlayerDisasterLog::getCreateTime)).collect(Collectors.toList());
+        log.info("获取灾难记录:{}", JSONUtil.toJsonStr(list));
+        //设置成已读
+        list.forEach(a -> a.setShow(true));
+        disasterLogRepository.saveAll(list);
+        return list;
+    }
+
+    //region 灾难模式周任务:同步每个用户上周收入支出
+
+    /**
+     * 定时任务核心方法 同步每个用户上周收入支出
+     * 灾难模式每周统计一次,如果这个期间新用户也需要这个功能。新注册的用户直接调用该方法。
+     *
+     * @param userId
+     */
+    @Transactional(rollbackFor = Exception.class)
+    @Override
+    public void asyncDisaster(String userId) {
+        //获取“收入支出数据”,下一步计算灾难场数
+        ComPlayerDisaster comPlayerDisaster = disasterService.getAndSave(userId);
+        //如果从链端接口拉到数据了。那么就计算灾难发生明细
+        if (comPlayerDisaster != null) {
+            //本周内应该出现的灾难次数
+            int disasterTimes = getDisasterTimes(comPlayerDisaster.getPayment(), comPlayerDisaster.getIncome());
+            log.info("用户编号:{}本周发生灾难:{}次", userId, disasterTimes);
+
+            //获得本周还剩下几天可以发生灾难,每周从周日到下周6
+            Date now = new Date();
+            DateRange dayRange = DateUtil.range(now, ComPlayerDisasterDateUtil.getEnd(), DateField.DAY_OF_WEEK);
+            List<Date> hasDisasterDay = new ArrayList<>();
+            while (dayRange.hasNext()) {
+                hasDisasterDay.add(dayRange.next());
+            }
+            //发生灾难的时间点(本周具体哪天灾难),从可发生灾难【时间集合】中随机取【x】个时间点进行灾难
+            List<Date> realDisasterDayList = RandomUtil.randomEleList(hasDisasterDay, disasterTimes);
+            log.info("用户编号:{}本周发生灾难时间点:{}", userId, JSONUtil.toJsonStr(realDisasterDayList));
+
+            //生成灾难明细记录
+            List<ComPlayerDisasterLog> disasterLogList = getComPlayerDisasterLogVoList(userId, comPlayerDisaster.getId(), realDisasterDayList);
+            log.info("用户编号:{}本周发生灾难明细:{}", userId, JSONUtil.toJsonStr(disasterLogList));
+
+            //灾难明细持久化
+            disasterLogRepository.saveAll(disasterLogList);
+        }
+    }
+
+    /**
+     * 获得本周灾难次数
+     * a)当某个村长所属农场的支出小于等于收入30%时,按照正常频率,每周出现1次
+     * b)当某个村长所属农场的支出大于收入30%时,每周出现2次
+     * c)当某个村长所属农场的支出大于收入50%时,每周出现4次
+     * d)当某个村长所属农场的支出大于收入80%时,每周出现6次
+     * 支出对应pay_amount,收入对应swap_amount
+     *
+     * @param pay_amount  支出对应
+     * @param swap_amount 收入对应
+     */
+    private int getDisasterTimes(double pay_amount, double swap_amount) {
+        if (pay_amount > NumberUtil.mul(swap_amount, 0.8)) {
+            return 6;
+        } else if (pay_amount > NumberUtil.mul(swap_amount, 0.5)) {
+            return 4;
+        } else if (pay_amount > NumberUtil.mul(swap_amount, 0.3)) {
+            return 2;
+        } else {
+            return 1;
+        }
+    }
+
+    /**
+     * 根据用户编号和灾难时间点 生成灾难表
+     *
+     * @param userId                   用户id
+     * @param ComPlayerDisasterTableId 主表id
+     * @param realDisasterDayList      发生灾难的时间点(本周具体哪天灾难)
+     * @return
+     */
+    private List<ComPlayerDisasterLog> getComPlayerDisasterLogVoList(String userId, long ComPlayerDisasterTableId, List<Date> realDisasterDayList) {
+        List<ComPlayerDisasterLog> list = new ArrayList<>();
+        ComPlayerDisasterLog disasterLog;
+        for (Date disasterDay : realDisasterDayList) {
+            //随机获取一种灾难方式灾难对象
+            List<String> disasterEnumFields = (List) EnumUtil.getFieldValues(ComPlayerDisasterEnum.class, "msg");
+            ComPlayerDisasterEnum disasterEnum = EnumUtil.likeValueOf(ComPlayerDisasterEnum.class, RandomUtil.randomEle(disasterEnumFields));
+
+            disasterLog = new ComPlayerDisasterLog();
+            disasterLog.setDsasterId(ComPlayerDisasterTableId);
+            disasterLog.setDsasterName(disasterEnum.getMsg());
+            disasterLog.setDsasterType(disasterEnum.getCode());
+            disasterLog.setUserId(userId);
+            disasterLog.setDamage(damage);
+            disasterLog.setDefend(defend);
+            disasterLog.setCreateTime(new Date());
+            disasterLog.setShow(false);
+            disasterLog.setEnabled(false);
+            disasterLog.setDisasterTime(disasterDay);
+            list.add(disasterLog);
+        }
+        return list;
+    }
+    //endregion
+
+    //region 灾难模式天任务:触发所有用户今日灾难和保护机制
+
+    /**
+     * 灾难模式天任务:触发所有用户今日灾难和保护机制
+     */
+    @Transactional(rollbackFor = Exception.class)
+    @Override
+    public void ComPlayerDisasterDayTask(ComPlayerDisasterLog disasterLog) {
+        Date now = new Date();
+        //查询当前人员购买防护历史记录
+        List<ComPlayerDisasterProtected> protectList = disasterProtectedService.getComPlayerDisasterProtectedByUserIdOrderByProtectTimeDesc(disasterLog.getUserId());
+        log.info("用户编号:{},防护历史记录:{}", disasterLog.getUserId(), JSONUtil.toJsonStr(protectList));
+        //获得对应灾难类型的防护记录    并得到这个 防护到期时间
+        Date protectedDate = protectList.stream()
+                .filter(a -> disasterLog.getDsasterType().equals(a.getDsasterType()))
+                .sorted(Comparator.comparing(ComPlayerDisasterProtected::getProtectTime).reversed())
+                .map(ComPlayerDisasterProtected::getProtectTime)
+                .findFirst().orElse(DateUtil.parse(null));
+
+        log.info("用户编号:{},灾难:{},防护到期时间:{}", disasterLog.getUserId(), JSONUtil.toJsonStr(disasterLog), protectedDate);
+
+        //存储防护到期时间,可能是null代表没有购买过防护
+        disasterLog.setProtectTime(protectedDate);
+        //设置本次灾难已经发生
+        disasterLog.setEnabled(true);
+        //灾难具体触发时间,代表每天的周期任务时间
+        disasterLog.setUpdateTime(now);
+        //默认是没有防护的
+        disasterLog.setProtect(false);
+
+        //如果没有防护或者防护到期。则直接发生灾难进行减产
+        if (protectedDate != null && now.before(protectedDate)) {
+            int randomProtect = RandomUtil.randomInt(0, 101);
+            log.info("灾难几率:{}", randomProtect);
+            if (randomProtect > (100 - defend)) {
+                disasterLog.setProtect(true);
+            }
+        }
+
+        log.info("灾难日志:{}", JSONUtil.toJsonStr(disasterLog));
+        disasterLogRepository.save(disasterLog);
+        //todo 减产接口 减产逻辑
+        if (!disasterLog.isProtect()) {
+            log.info("灾难结果:减产");
+        } else {
+            log.info("灾难结果:已防御");
+        }
+    }
+
+    /**
+     * 获取今天的灾难,并且没有触发过的灾难
+     *
+     * @return
+     */
+    @Override
+    public List<ComPlayerDisasterLog> getTodayDisasterUnEnabledList() {
+        Date now = new Date();
+        DateTime begin = DateUtil.beginOfDay(now);
+        DateTime end = DateUtil.endOfDay(now);
+        Specification specification = new Specification<ComPlayerDisasterLog>() {
+            @Override
+            public Predicate toPredicate(Root<ComPlayerDisasterLog> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
+                List<Predicate> predicates = new ArrayList<>();
+                predicates.add(criteriaBuilder.between(root.get("disasterTime"), begin, end));
+                predicates.add(criteriaBuilder.equal(root.get("isEnabled"), 0));
+                return criteriaBuilder.and(predicates.toArray(new Predicate[predicates.size()]));
+            }
+        };
+        return disasterLogRepository.findAll(specification);
+    }
+    //endregion
+}

+ 12 - 0
src/main/java/com/td/boss/game/complayerland/service/ComPlayerDisasterProtectedService.java

@@ -0,0 +1,12 @@
+package com.td.boss.game.complayerland.service;
+
+import com.td.boss.common.service.CommonService;
+import com.td.boss.game.complayerland.pojo.ComPlayerDisasterProtected;
+import com.td.boss.game.complayerland.vo.ComPlayerDisasterProtectedVo;
+
+import java.util.List;
+
+public interface ComPlayerDisasterProtectedService extends CommonService<ComPlayerDisasterProtectedVo, ComPlayerDisasterProtected, String> {
+
+    List<ComPlayerDisasterProtected> getComPlayerDisasterProtectedByUserIdOrderByProtectTimeDesc(String userId);
+}

+ 27 - 0
src/main/java/com/td/boss/game/complayerland/service/ComPlayerDisasterProtectedServiceImpl.java

@@ -0,0 +1,27 @@
+package com.td.boss.game.complayerland.service;
+
+import com.td.boss.common.service.CommonServiceImpl;
+import com.td.boss.game.complayerland.pojo.ComPlayerDisasterProtected;
+import com.td.boss.game.complayerland.repository.ComPlayerDisasterProtectedRepository;
+import com.td.boss.game.complayerland.vo.ComPlayerDisasterProtectedVo;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+@Slf4j
+@Service
+public class ComPlayerDisasterProtectedServiceImpl extends CommonServiceImpl<ComPlayerDisasterProtectedVo, ComPlayerDisasterProtected, String> implements ComPlayerDisasterProtectedService {
+    @Autowired
+    private ComPlayerDisasterProtectedRepository repository;
+
+    /**
+     * 按照用户编号获取 防护灾难 记录
+     * @param userId
+     * @return
+     */
+    public List<ComPlayerDisasterProtected> getComPlayerDisasterProtectedByUserIdOrderByProtectTimeDesc(String userId) {
+        return repository.getComPlayerDisasterProtectedsByUserId(userId);
+    }
+}

+ 18 - 0
src/main/java/com/td/boss/game/complayerland/service/ComPlayerDisasterService.java

@@ -0,0 +1,18 @@
+package com.td.boss.game.complayerland.service;
+
+import com.td.boss.common.service.CommonService;
+import com.td.boss.game.complayerland.pojo.ComPlayerDisaster;
+import com.td.boss.game.complayerland.vo.ComPlayerDisasterVo;
+
+
+public interface ComPlayerDisasterService extends CommonService<ComPlayerDisasterVo, ComPlayerDisaster, String> {
+
+    /**
+     * 同步“链端接口”上周“收入支出数据”到数据库
+     * 本周开始时间为周日到周六,期间获取的不会变化,这周获取的是上周的数据
+     *
+     * @param userId
+     * @return
+     */
+    ComPlayerDisaster getAndSave(String userId);
+}

+ 93 - 0
src/main/java/com/td/boss/game/complayerland/service/ComPlayerDisasterServiceImpl.java

@@ -0,0 +1,93 @@
+package com.td.boss.game.complayerland.service;
+
+import cn.hutool.core.convert.Convert;
+import cn.hutool.core.date.DateField;
+import cn.hutool.core.date.DateUtil;
+import cn.hutool.json.JSONUtil;
+import com.td.boss.common.service.CommonServiceImpl;
+import com.td.boss.game.complayerland.pojo.ComPlayerDisaster;
+import com.td.boss.game.complayerland.repository.ComPlayerDisasterRepository;
+import com.td.boss.game.complayerland.scheduled.ComPlayerDisasterDateUtil;
+import com.td.boss.game.complayerland.vo.ComPlayerDisasterVo;
+import com.td.boss.util.DappUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.jpa.domain.Specification;
+import org.springframework.stereotype.Service;
+
+import javax.persistence.criteria.CriteriaBuilder;
+import javax.persistence.criteria.CriteriaQuery;
+import javax.persistence.criteria.Predicate;
+import javax.persistence.criteria.Root;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+
+@Slf4j
+@Service
+public class ComPlayerDisasterServiceImpl extends CommonServiceImpl<ComPlayerDisasterVo, ComPlayerDisaster, String> implements ComPlayerDisasterService {
+
+    @Autowired
+    private ComPlayerDisasterRepository repository;
+
+    /**
+     * 同步“链端接口”上周“收入支出数据”到数据库
+     * 本周开始时间为周日到周六,期间获取的不会变化,这周获取的是上周的数据
+     *
+     * @param userId
+     * @return
+     */
+    @Override
+    public ComPlayerDisaster getAndSave(String userId) {
+        Date begin = ComPlayerDisasterDateUtil.getBegin();
+        Date end = ComPlayerDisasterDateUtil.getEnd();
+        log.info("灾难模式周同步数据[{}],begin:{},end:{},now:{}", userId, begin, end, DateUtil.format(new Date(), "yyyy-MM-dd hh:mm:ss"));
+        if (exists(userId, begin, end)) {
+            log.info("灾难模式周同步数据[{}]已经同步过了", userId);
+            return null;
+        }
+        ComPlayerDisaster data = getData(userId, begin, end);
+        return repository.saveAndFlush(data);
+    }
+
+    /**
+     * 所以 支出对应pay_amount,收入对应swap_amount
+     * @param userId
+     * @param beginTime
+     * @param endTime
+     * @return
+     */
+    private ComPlayerDisaster getData(String userId, Date beginTime, Date endTime) {
+        Map response = DappUtil.getCntPayAndSwapAmount(userId);
+        log.info("接口返回支付兑换结果:{}", JSONUtil.toJsonStr(response));
+        Map<String, Object> cntPayAndSwapAmount = (Map) response.get("data");
+
+        // 总支付cnt
+        Double pay_amount = Convert.toDouble(cntPayAndSwapAmount.get("pay_amount"), 0d);
+        // 总兑换cnt
+        Double swap_amount = Convert.toDouble(cntPayAndSwapAmount.get("swap_amount"), 0d);
+        ComPlayerDisaster comPlayerDisaster = new ComPlayerDisaster();
+        comPlayerDisaster.setCreateTime(new Date());
+        comPlayerDisaster.setUserId(userId);
+        comPlayerDisaster.setIncome(swap_amount);
+        comPlayerDisaster.setPayment(pay_amount);
+        comPlayerDisaster.setLog(JSONUtil.toJsonStr(response));
+        comPlayerDisaster.setBeginTime(beginTime);
+        comPlayerDisaster.setEndTime(endTime);
+        return comPlayerDisaster;
+    }
+
+    private boolean exists(String userId, Date begin, Date end) {
+        Specification specification = new Specification<ComPlayerDisaster>() {
+            @Override
+            public Predicate toPredicate(Root<ComPlayerDisaster> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
+                List<Predicate> predicates = new ArrayList<>();
+                predicates.add(criteriaBuilder.between(root.get("createTime"), begin, end));
+                predicates.add(criteriaBuilder.equal(root.get("userId"), userId));
+                return criteriaBuilder.and(predicates.toArray(new Predicate[predicates.size()]));
+            }
+        };
+        return repository.count(specification) > 0;
+    }
+}

+ 18 - 0
src/main/java/com/td/boss/game/complayerland/vo/ComPlayerDisasterEnum.java

@@ -0,0 +1,18 @@
+package com.td.boss.game.complayerland.vo;
+
+import lombok.Data;
+import lombok.Getter;
+
+@Getter
+public enum ComPlayerDisasterEnum {
+    ziran(2, "自然灾害"),
+    yeshou(3, "野兽");
+
+    ComPlayerDisasterEnum(Integer code, String msg) {
+        this.code = code;
+        this.msg = msg;
+    }
+
+    private Integer code;
+    private String msg;
+}

+ 58 - 0
src/main/java/com/td/boss/game/complayerland/vo/ComPlayerDisasterLogVo.java

@@ -0,0 +1,58 @@
+package com.td.boss.game.complayerland.vo;
+
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * 灾难
+ */
+@Data
+public class ComPlayerDisasterLogVo implements Serializable {
+
+    /**
+     * 主表id
+     */
+    private long dsasterId;
+
+    /**
+     * 灾难名称
+     */
+    private String dsasterName;
+    private Integer dsasterType;
+    /**
+     * 伤害 会减产50%
+     */
+    private int damage;
+
+    /**
+     * 防御 90%概率防御灾难
+     */
+    private double defend;
+
+    /**
+     * 防护截止时间
+     */
+    private Date protectTime;
+
+    /**
+     * 本次灾难是否激活防护
+     */
+    private boolean activityProtect;
+
+    private String userId;
+
+    private Date createTime;
+
+    private Date disasterTime;
+    private Date updateTime;
+    /**
+     * 前端 是否以显示
+     */
+    private boolean isShow;
+    /**
+     * 是否已经使用,灾害是预先生成的
+     */
+    private boolean isEnabled;
+}

+ 26 - 0
src/main/java/com/td/boss/game/complayerland/vo/ComPlayerDisasterProtectedVo.java

@@ -0,0 +1,26 @@
+package com.td.boss.game.complayerland.vo;
+
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * 灾难防护
+ */
+@Data
+public class ComPlayerDisasterProtectedVo implements Serializable {
+    /**
+     * 灾难名称
+     */
+    private String dsasterName;
+    private Integer dsasterType;
+    /**
+     * 防护截止时间
+     */
+    private Date protectTime;
+
+    private String userId;
+
+    private Date createTime;
+}

+ 15 - 0
src/main/java/com/td/boss/game/complayerland/vo/ComPlayerDisasterVo.java

@@ -0,0 +1,15 @@
+package com.td.boss.game.complayerland.vo;
+
+import lombok.Data;
+
+import java.util.Date;
+
+@Data
+public class ComPlayerDisasterVo {
+    private long id;
+    private Double income;
+    private Double payment;
+    private String log;
+    private String userId;
+    private Date createTime;
+}

+ 5 - 0
src/main/java/com/td/boss/game/complayers/repository/ComPlayersRepository.java

@@ -2,12 +2,17 @@ package com.td.boss.game.complayers.repository;
 
 import com.td.boss.common.repository.*;
 import com.td.boss.game.complayers.pojo.ComPlayers;
+import org.springframework.data.jpa.repository.Query;
 import org.springframework.stereotype.Repository;
 
+import java.util.List;
 import java.util.Optional;
 
 @Repository
 public interface ComPlayersRepository extends CommonRepository<ComPlayers, Integer> {
 
     Optional<ComPlayers> findByUserId(String userId);
+
+    @Query(value = "select user_id from com_users", nativeQuery = true)
+    List<String> findUserIds();
 }

+ 3 - 1
src/main/java/com/td/boss/game/complayers/service/ComPlayersService.java

@@ -4,6 +4,8 @@ import com.td.boss.common.service.*;
 import com.td.boss.game.complayers.pojo.ComPlayers;
 import com.td.boss.game.complayers.vo.ComPlayersVo;
 
+import java.util.List;
+
 public interface ComPlayersService extends CommonService<ComPlayersVo, ComPlayers, Integer> {
 
     /**
@@ -15,5 +17,5 @@ public interface ComPlayersService extends CommonService<ComPlayersVo, ComPlayer
 
     ComPlayers addComPlayers(ComPlayers comPlayers);
 
-
+    List<String> findUserIds();
 }

+ 9 - 2
src/main/java/com/td/boss/game/complayers/service/ComPlayersServiceImpl.java

@@ -7,12 +7,14 @@ import com.td.boss.game.complayers.repository.ComPlayersRepository;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
+
 import javax.persistence.EntityManager;
 import javax.persistence.PersistenceContext;
+import java.util.List;
 
 @Service
 @Transactional
-public class ComPlayersServiceImpl extends CommonServiceImpl<ComPlayersVo, ComPlayers, Integer> implements ComPlayersService{
+public class ComPlayersServiceImpl extends CommonServiceImpl<ComPlayersVo, ComPlayers, Integer> implements ComPlayersService {
 
     @PersistenceContext
     private EntityManager em;
@@ -27,7 +29,12 @@ public class ComPlayersServiceImpl extends CommonServiceImpl<ComPlayersVo, ComPl
     @Override
     @Transactional
     public ComPlayers addComPlayers(ComPlayers comPlayers) {
-        ComPlayers player =  comPlayersRepository.saveAndFlush(comPlayers);
+        ComPlayers player = comPlayersRepository.saveAndFlush(comPlayers);
         return player;
     }
+
+    @Override
+    public List<String> findUserIds() {
+        return comPlayersRepository.findUserIds();
+    }
 }

+ 37 - 0
src/main/java/com/td/boss/util/DappUtil.java

@@ -23,6 +23,7 @@ import java.io.InputStreamReader;
 import java.net.HttpURLConnection;
 import java.net.URL;
 import java.text.SimpleDateFormat;
+import java.util.HashMap;
 import java.util.Map;
 import java.util.SortedMap;
 import java.util.TreeMap;
@@ -83,6 +84,42 @@ public class DappUtil {
         }
     }
 
+    /**
+     * 根据村民ID找到所属村的cnt总支付和总兑换数量(模块4)
+     * {
+     *     "code": 200,
+     *     "msg": "success",
+     *     "data": 0
+     * }
+     */
+    public static Map getCntPayAndSwapAmount(String userId){
+
+        MultiValueMap<String, Object> form = new LinkedMultiValueMap<>();
+        form.add("id", userId);
+        //验证地址
+        String onlineUrl = "https://yt.landownership.live/api/game/cntPayAndSwapAmount";
+        String testUrl = "https://wp.landownership.live/api/game/cntPayAndSwapAmount";
+        String DAppUrl = DappUtil.getEnv().equals("prod") ? onlineUrl : testUrl;
+        log.info("根据村民ID找到所属村的cnt总支付和总兑换数量:" + DAppUrl);
+        try {
+            RestTemplate restTemplate = new RestTemplate();
+            HttpHeaders headers = new HttpHeaders();
+            //设置content-type
+            MediaType type = MediaType.parseMediaType("multipart/form-data");
+            headers.setContentType(type);
+            // 以表单的方式提交
+            headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
+            //用HttpEntity封装整个请求报文
 
+            HttpEntity<MultiValueMap<String, Object>> files = new HttpEntity<>(form, headers);
+            Map response = restTemplate.postForObject(DAppUrl, files, Map.class);
+            log.info("response={}", response);
+            return response;
+        } catch (Exception e) {
+            log.error(e.getMessage());
+            return new HashMap<>();
+            //e.printStackTrace();
+        }
+    }
 
 }

+ 16 - 0
src/main/java/com/td/boss/util/RedisData.java

@@ -30,4 +30,20 @@ public class RedisData {
     public static int getPlayerGoodsTimeout() {
         return PLAYER_GOODS_TIMEOUT;
     }
+
+    /**
+     * 1h 灾难模块锁
+     */
+    private static final int PLAYER_DISASTERS_WEEK_TIMEOUT = 60 * 1000*60;
+    public static int getDisastersWeekTimeout() {
+        return PLAYER_DISASTERS_WEEK_TIMEOUT;
+    }
+
+    /**
+     * 1h 灾难模块锁
+     */
+    private static final int PLAYER_DISASTERS_DAY_TIMEOUT = 60 * 1000*60;
+    public static int getDisastersDayTimeout() {
+        return PLAYER_DISASTERS_DAY_TIMEOUT;
+    }
 }

+ 5 - 4
src/main/resources/application.yml

@@ -34,6 +34,7 @@ spring:
   jpa:
     show-sql: true
 
+
 # token 参数
 jwt:
   secret: test      # 密钥
@@ -47,9 +48,9 @@ spring:
 
   #数据库配置
   datasource:
-    url: jdbc:mysql://42.192.165.168:3306/dragon_town?serverTimezone=GMT%2B8&characterEncoding=utf-8
+    url: jdbc:mysql://123.57.252.53:6688/dragon_town?useSSL=false&serverTimezone=GMT%2B8&characterEncoding=utf-8
     username: root #dragon_town #root
-    password:  9ab8fad748dead93 #zddeiBmp8c5T6TR6 #9ab8fad748dead93
+    password:  FzCebFq6Xy0CDTXJ #zddeiBmp8c5T6TR6 #9ab8fad748dead93
     driver-class-name: com.mysql.cj.jdbc.Driver
     hikari:
       minimum-idle: 5
@@ -61,9 +62,9 @@ spring:
       connection-test-query: SELECT 1
 
   redis:
-    host: 42.192.165.168
+    host: 123.57.252.53
     port: 6379
-    password: abc123456abc-test
+    password: heihei
     data: #工程中只是把redis作为缓存,并未使用redis作为数据持久化存储源repository使用.
       redis:
         repositories:

+ 0 - 13
src/test/java/com/td/boss/BossApplicationTests.java

@@ -1,13 +0,0 @@
-package com.td.boss;
-
-import org.junit.jupiter.api.Test;
-import org.springframework.boot.test.context.SpringBootTest;
-
-@SpringBootTest
-class BossApplicationTests {
-
-    @Test
-    void contextLoads() {
-    }
-
-}

+ 109 - 0
src/test/java/com/td/boss/ComPlayerDisasterLogTests.java

@@ -0,0 +1,109 @@
+package com.td.boss;
+
+import cn.hutool.core.convert.Convert;
+import cn.hutool.core.date.DateField;
+import cn.hutool.core.date.DateUtil;
+import cn.hutool.json.JSONUtil;
+import com.td.boss.common.pojo.Result;
+import com.td.boss.game.comcnttosnb.service.ComCntToSnbService;
+import com.td.boss.game.complayerland.pojo.ComPlayerDisasterLog;
+import com.td.boss.game.complayerland.service.ComPlayerDisasterProtectedService;
+import com.td.boss.game.complayerland.service.ComPlayerDisasterLogService;
+import com.td.boss.game.complayerland.vo.ComPlayerDisasterEnum;
+import com.td.boss.game.complayerland.vo.ComPlayerDisasterProtectedVo;
+import org.junit.jupiter.api.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit4.SpringRunner;
+
+import java.util.Date;
+import java.util.List;
+
+@RunWith(SpringRunner.class)
+@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
+class ComPlayerDisasterLogTests {
+
+    @Autowired
+    private ComPlayerDisasterLogService comPlayerDisasterLogService;
+    @Autowired
+    private ComPlayerDisasterProtectedService comPlayerDisasterProtectedService;
+    @Autowired
+    private ComCntToSnbService comCntToSnbService;
+
+    private String userId = "1002";
+
+    /**
+     * 防护灾难
+     */
+    @Test
+    void playerAddProtected() {
+        ComPlayerDisasterProtectedVo comPlayerDisasterProtected = new ComPlayerDisasterProtectedVo();
+        comPlayerDisasterProtected.setCreateTime(new Date());
+        comPlayerDisasterProtected.setUserId(userId);
+        comPlayerDisasterProtected.setDsasterType(ComPlayerDisasterEnum.ziran.getCode());
+        comPlayerDisasterProtected.setDsasterName(ComPlayerDisasterEnum.ziran.getMsg());
+        comPlayerDisasterProtected.setProtectTime(DateUtil.date(new Date()).offset(DateField.DAY_OF_WEEK, 30));
+        comPlayerDisasterProtectedService.save(comPlayerDisasterProtected);
+
+        comPlayerDisasterProtected = new ComPlayerDisasterProtectedVo();
+        comPlayerDisasterProtected.setCreateTime(new Date());
+        comPlayerDisasterProtected.setUserId(userId);
+        comPlayerDisasterProtected.setDsasterType(ComPlayerDisasterEnum.yeshou.getCode());
+        comPlayerDisasterProtected.setDsasterName(ComPlayerDisasterEnum.yeshou.getMsg());
+        comPlayerDisasterProtected.setProtectTime(DateUtil.date(new Date()).offset(DateField.DAY_OF_WEEK, -30));
+        comPlayerDisasterProtectedService.save(comPlayerDisasterProtected);
+    }
+
+    /**
+     * 获取灾难经历
+     */
+    @Test
+    void getHistory() {
+        List<ComPlayerDisasterLog> history = comPlayerDisasterLogService.getHistory(userId);
+        System.out.println(history);
+    }
+
+    /**
+     * 测试灾难模式
+     */
+    @Test
+    void ComPlayerDisasterWeekTask() {
+        comPlayerDisasterLogService.asyncDisaster(userId);
+    }
+
+    @Test
+    void ComPlayerDisasterDayTask() {
+        for (ComPlayerDisasterLog disasterLog : comPlayerDisasterLogService.getTodayDisasterUnEnabledList()) {
+            comPlayerDisasterLogService.ComPlayerDisasterDayTask(disasterLog);
+        }
+    }
+
+    /**
+     * 获取userid snb领取情况,如果不在特定的列表,data为null
+     */
+    @Test
+    void getCntToSnb() {
+        // 情况一,在名单中
+        String json = JSONUtil.toJsonStr(Result.of(comCntToSnbService.findByUserId("952")));
+        System.out.println(json);
+        // 情况二,不在名单中
+        String json2 = JSONUtil.toJsonStr(Result.of(comCntToSnbService.findByUserId("9527")));
+        System.out.println(json2);
+    }
+
+    /**
+     * userid领取snb
+     */
+    @Test
+    void receiveCntToSnb() {
+//        Date begin = DateUtil.parse("2022-03-01");
+//        Date end = DateUtil.parse("2022-03-05");
+//
+//        Integer day = Convert.toInt(DateUtil.betweenDay(begin, end, true));
+//        System.out.println(DateUtil.format(begin, "yyyy-MM-dd") + " 至 " + DateUtil.format(end, "yyyy-MM-dd") + "相差:" + day + "天");
+
+        String json = JSONUtil.toJsonStr(comCntToSnbService.receiveByUserId("952"));
+        System.out.println(json);
+    }
+}