Przeglądaj źródła

Merge branch 'master' of http://git.izouma.com/xiongzhu/raex_back into dev

 Conflicts:
	src/main/java/com/izouma/nineth/service/AssetService.java
sunkean 2 lat temu
rodzic
commit
1c298dacb6
41 zmienionych plików z 1615 dodań i 468 usunięć
  1. 33 0
      src/main/java/com/izouma/nineth/domain/MetaAtomTask.java
  2. 60 0
      src/main/java/com/izouma/nineth/domain/MetaAwardDrop.java
  3. 0 2
      src/main/java/com/izouma/nineth/domain/MetaObjectMove.java
  4. 4 0
      src/main/java/com/izouma/nineth/domain/MetaTaskBind.java
  5. 30 0
      src/main/java/com/izouma/nineth/domain/MetaTaskNew.java
  6. 6 1
      src/main/java/com/izouma/nineth/domain/MetaUserPropRecord.java
  7. 17 0
      src/main/java/com/izouma/nineth/dto/MetaAwardDropJsonDTO.java
  8. 1 1
      src/main/java/com/izouma/nineth/dto/MetaObjectMoveCoordinateDTO.java
  9. 8 0
      src/main/java/com/izouma/nineth/repo/MetaAwardDropRepo.java
  10. 1 1
      src/main/java/com/izouma/nineth/repo/MetaObjectMoveCoordinateRepo.java
  11. 6 0
      src/main/java/com/izouma/nineth/repo/MetaObjectMoveRepo.java
  12. 3 0
      src/main/java/com/izouma/nineth/repo/MetaTaskBindRepo.java
  13. 9 3
      src/main/java/com/izouma/nineth/repo/MetaTaskNewRepo.java
  14. 9 2
      src/main/java/com/izouma/nineth/repo/MetaTaskToUserNewRepo.java
  15. 0 1
      src/main/java/com/izouma/nineth/security/WebSecurityConfig.java
  16. 13 16
      src/main/java/com/izouma/nineth/service/AssetService.java
  17. 101 0
      src/main/java/com/izouma/nineth/service/MetaAwardDropService.java
  18. 4 2
      src/main/java/com/izouma/nineth/service/MetaAwardReceiveService.java
  19. 198 1
      src/main/java/com/izouma/nineth/service/MetaObjectMoveService.java
  20. 11 8
      src/main/java/com/izouma/nineth/service/MetaStoreService.java
  21. 88 3
      src/main/java/com/izouma/nineth/service/MetaTaskNewService.java
  22. 73 76
      src/main/java/com/izouma/nineth/service/MetaTaskToUserNewService.java
  23. 2 2
      src/main/java/com/izouma/nineth/service/MetaUserPropRecordService.java
  24. 17 13
      src/main/java/com/izouma/nineth/service/MetaUserPropService.java
  25. 19 9
      src/main/java/com/izouma/nineth/service/MetaUserTaskAwardReceivedRecordNewService.java
  26. 26 13
      src/main/java/com/izouma/nineth/service/MetaUserTaskProgressNewService.java
  27. 14 7
      src/main/java/com/izouma/nineth/service/UserService.java
  28. 48 0
      src/main/java/com/izouma/nineth/utils/OSSClientUtil.java
  29. 48 0
      src/main/java/com/izouma/nineth/web/MetaAwardDropController.java
  30. 11 57
      src/main/java/com/izouma/nineth/web/MetaObjectMoveController.java
  31. 6 4
      src/main/java/com/izouma/nineth/web/MetaTaskToUserNewController.java
  32. 12 3
      src/main/java/com/izouma/nineth/web/MetaUserPropController.java
  33. 4 3
      src/main/java/com/izouma/nineth/web/UserAssetSummaryController.java
  34. 15 13
      src/main/java/com/izouma/nineth/web/UserController.java
  35. 1 0
      src/main/resources/genjson/MetaAwardDrop.json
  36. 16 0
      src/main/vue/src/router.js
  37. 148 0
      src/main/vue/src/views/MetaAwardDropEdit.vue
  38. 133 0
      src/main/vue/src/views/MetaAwardDropList.vue
  39. 258 84
      src/main/vue/src/views/MetaObjectMoveEdit.vue
  40. 114 143
      src/main/vue/src/views/MetaObjectMoveList.vue
  41. 48 0
      src/test/java/com/izouma/nineth/service/MetaTest.java

+ 33 - 0
src/main/java/com/izouma/nineth/domain/MetaAtomTask.java

@@ -3,6 +3,7 @@ package com.izouma.nineth.domain;
 
 import com.alibaba.excel.annotation.ExcelProperty;
 import com.izouma.nineth.annotations.Searchable;
+import com.izouma.nineth.dto.MetaServiceResult;
 import com.izouma.nineth.enums.MetaAwardTypeEnum;
 import com.izouma.nineth.enums.MetaTaskTarget;
 import io.swagger.annotations.ApiModel;
@@ -10,11 +11,13 @@ import io.swagger.annotations.ApiModelProperty;
 import lombok.AllArgsConstructor;
 import lombok.Data;
 import lombok.NoArgsConstructor;
+import org.apache.commons.lang3.StringUtils;
 
 import javax.persistence.Column;
 import javax.persistence.Entity;
 import javax.persistence.EnumType;
 import javax.persistence.Enumerated;
+import java.util.Objects;
 
 @Data
 @AllArgsConstructor
@@ -51,4 +54,34 @@ public class MetaAtomTask extends BaseEntity {
     @ExcelProperty("奖励配置")
     private String awardConfig;
 
+    /**
+     * 校验基础任务
+     *
+     * @param metaAtomTask 基础任务
+     * @return result
+     */
+    public static MetaServiceResult checkMetaAtomTask(MetaAtomTask metaAtomTask) {
+        if (Objects.isNull(metaAtomTask)) {
+            return MetaServiceResult.returnError("基础任务不存在");
+        }
+        if (StringUtils.isBlank(metaAtomTask.getName())) {
+            return MetaServiceResult.returnError(String.format("基础任务[%S]缺少任务名称", metaAtomTask.getId()));
+        }
+        if (Objects.isNull(metaAtomTask.getDetail())) {
+            return MetaServiceResult.returnError(String.format("基础任务[%S]缺少任务详情", metaAtomTask.getId()));
+        }
+        if (Objects.isNull(metaAtomTask.getTargetType())) {
+            return MetaServiceResult.returnError(String.format("基础任务[%S]缺少目标", metaAtomTask.getId()));
+        }
+        if (StringUtils.isBlank(metaAtomTask.getTargetConfig())) {
+            return MetaServiceResult.returnError(String.format("基础任务[%S]缺少目标配置", metaAtomTask.getId()));
+        }
+        if (Objects.isNull(metaAtomTask.getAwardType())) {
+            return MetaServiceResult.returnError(String.format("基础任务[%S]缺少奖励类型", metaAtomTask.getId()));
+        }
+        if (!metaAtomTask.getAwardType().equals(MetaAwardTypeEnum.NULL) && StringUtils.isBlank(metaAtomTask.getAwardConfig())) {
+            return MetaServiceResult.returnError(String.format("基础任务[%S]缺少奖励配置", metaAtomTask.getId()));
+        }
+        return MetaServiceResult.returnSuccess();
+    }
 }

+ 60 - 0
src/main/java/com/izouma/nineth/domain/MetaAwardDrop.java

@@ -0,0 +1,60 @@
+package com.izouma.nineth.domain;
+
+import com.alibaba.excel.annotation.ExcelProperty;
+import com.izouma.nineth.dto.MetaServiceResult;
+import com.izouma.nineth.enums.MetaAwardTypeEnum;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import jodd.util.StringUtil;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import javax.persistence.*;
+import java.time.LocalDateTime;
+import java.util.Objects;
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+@Entity
+@ApiModel("元宇宙奖励空投记录")
+public class MetaAwardDrop extends BaseEntity {
+
+    @ApiModelProperty("操作人")
+    @ExcelProperty("操作人")
+    private String operator;
+
+    @ApiModelProperty("操作时间")
+    @ExcelProperty("操作时间")
+    private LocalDateTime operatingTime;
+
+    @ApiModelProperty("备注说明")
+    @ExcelProperty("备注说明")
+    private String remark;
+
+    @ApiModelProperty("奖励类型")
+    @ExcelProperty("奖励类型")
+    @Enumerated(EnumType.STRING)
+    private MetaAwardTypeEnum awardType;
+
+    @ApiModelProperty("文件地址")
+    @ExcelProperty("文件地址")
+    private String fileUrl;
+
+    public static MetaServiceResult checkMetaAtomTask(MetaAwardDrop metaAwardDrop) {
+        if (Objects.isNull(metaAwardDrop)) {
+            return MetaServiceResult.returnError("Illegal parameter : params can not be null");
+        }
+        if (Objects.isNull(metaAwardDrop.getAwardType())) {
+            return MetaServiceResult.returnError("Illegal parameter : awardType can not be null");
+        }
+        if (StringUtil.isBlank(metaAwardDrop.getRemark())) {
+            return MetaServiceResult.returnError("Illegal parameter : remark can not be null");
+        }
+        if (StringUtil.isBlank(metaAwardDrop.getFileUrl())) {
+            return MetaServiceResult.returnError("Illegal parameter : file can not be null");
+        }
+        return MetaServiceResult.returnSuccess();
+    }
+}

+ 0 - 2
src/main/java/com/izouma/nineth/domain/MetaObjectMove.java

@@ -12,7 +12,6 @@ import lombok.NoArgsConstructor;
 import javax.persistence.Column;
 import javax.persistence.Convert;
 import javax.persistence.Entity;
-import javax.persistence.Transient;
 import java.time.LocalDateTime;
 import java.util.List;
 
@@ -37,7 +36,6 @@ public class MetaObjectMove extends BaseEntity {
     @Convert(converter = MetaObjectMoveCoordinateListConverter.class)
     private List<MetaObjectMoveCoordinateDTO> metaObjectMoveCoordinateDTOS;
 
-    @Transient
     @ApiModelProperty("总移动时间")
     @ExcelProperty("总移动时间")
     private Long totalTime;

+ 4 - 0
src/main/java/com/izouma/nineth/domain/MetaTaskBind.java

@@ -11,6 +11,7 @@ import lombok.NoArgsConstructor;
 import javax.persistence.Entity;
 import javax.persistence.EnumType;
 import javax.persistence.Enumerated;
+import javax.persistence.Transient;
 
 @Data
 @AllArgsConstructor
@@ -35,4 +36,7 @@ public class MetaTaskBind extends BaseEntity {
     @ExcelProperty("任务分类")
     @Enumerated(EnumType.STRING)
     private MetaTaskType type;
+
+    @Transient
+    private MetaAtomTask metaAtomTask;
 }

+ 30 - 0
src/main/java/com/izouma/nineth/domain/MetaTaskNew.java

@@ -2,15 +2,18 @@ package com.izouma.nineth.domain;
 
 import com.alibaba.excel.annotation.ExcelProperty;
 import com.izouma.nineth.annotations.Searchable;
+import com.izouma.nineth.dto.MetaServiceResult;
 import com.izouma.nineth.enums.MetaTaskType;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 import lombok.AllArgsConstructor;
 import lombok.Data;
 import lombok.NoArgsConstructor;
+import org.apache.commons.lang3.StringUtils;
 
 import javax.persistence.*;
 import java.util.List;
+import java.util.Objects;
 
 @Data
 @AllArgsConstructor
@@ -56,4 +59,31 @@ public class MetaTaskNew extends BaseEntity {
     @Transient
     private List<MetaTaskBind> metaDailyTask;
 
+    /**
+     * 校验任务
+     *
+     * @param metaTaskNew 任务信息
+     * @return result
+     */
+    public static MetaServiceResult checkMetaTaskNew(MetaTaskNew metaTaskNew) {
+        if (Objects.isNull(metaTaskNew)) {
+            return MetaServiceResult.returnError("任务不存在");
+        }
+        if (!metaTaskNew.isPublish()) {
+            return MetaServiceResult.returnError("status error : task has not been published");
+        }
+        if (StringUtils.isBlank(metaTaskNew.getName())) {
+            return MetaServiceResult.returnError(String.format("任务[%S]缺少任务名称", metaTaskNew.getId()));
+        }
+        if (Objects.isNull(metaTaskNew.getDetail())) {
+            return MetaServiceResult.returnError(String.format("任务[%S]缺少任务详情", metaTaskNew.getId()));
+        }
+        if (Objects.isNull(metaTaskNew.getType())) {
+            return MetaServiceResult.returnError(String.format("任务[%S]缺少任务类型", metaTaskNew.getId()));
+        }
+        if (Objects.isNull(metaTaskNew.getChannelId())) {
+            return MetaServiceResult.returnError(String.format("任务[%S]缺少频道id", metaTaskNew.getId()));
+        }
+        return MetaServiceResult.returnSuccess();
+    }
 }

+ 6 - 1
src/main/java/com/izouma/nineth/domain/MetaUserPropRecord.java

@@ -57,7 +57,11 @@ public class MetaUserPropRecord extends BaseEntity {
     @ExcelProperty("操作道具数量")
     private int num;
 
-    public static MetaUserPropRecord create(Long userId, MetaProp metaProp, MetaPropOperationType operationType, int num) {
+    @ApiModelProperty("备注")
+    @ExcelProperty("备注")
+    private String remark;
+
+    public static MetaUserPropRecord create(Long userId, MetaProp metaProp, MetaPropOperationType operationType, int num, String remark) {
         return MetaUserPropRecord.builder()
                 .userId(userId)
                 .metaPropId(metaProp.getId())
@@ -67,6 +71,7 @@ public class MetaUserPropRecord extends BaseEntity {
                 .operatingTime(LocalDateTime.now())
                 .usedType(metaProp.getUsedType())
                 .num(num)
+                .remark(remark)
                 .build();
     }
 }

+ 17 - 0
src/main/java/com/izouma/nineth/dto/MetaAwardDropJsonDTO.java

@@ -0,0 +1,17 @@
+package com.izouma.nineth.dto;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class MetaAwardDropJsonDTO {
+
+    private Long userId;
+
+    private int value;
+
+    private Long propId;
+}

+ 1 - 1
src/main/java/com/izouma/nineth/dto/MetaObjectMoveCoordinateDTO.java

@@ -23,5 +23,5 @@ public class MetaObjectMoveCoordinateDTO {
 
     private float eulerZ;
 
-    private Long time;
+    private long time;
 }

+ 8 - 0
src/main/java/com/izouma/nineth/repo/MetaAwardDropRepo.java

@@ -0,0 +1,8 @@
+package com.izouma.nineth.repo;
+
+import com.izouma.nineth.domain.MetaAwardDrop;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
+
+public interface MetaAwardDropRepo extends JpaRepository<MetaAwardDrop, Long>, JpaSpecificationExecutor<MetaAwardDrop> {
+}

+ 1 - 1
src/main/java/com/izouma/nineth/repo/MetaObjectMoveCoordinateRepo.java

@@ -6,5 +6,5 @@ import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
 
 public interface MetaObjectMoveCoordinateRepo extends JpaRepository<MetaObjectMoveCoordinate, Long>, JpaSpecificationExecutor<MetaObjectMoveCoordinate> {
 
-    MetaObjectMoveCoordinate findByObjectIdAndCoordinateIndexAndDel(Long objectId, Long coordinateIndex, boolean del);
+    MetaObjectMoveCoordinate findByObjectIdAndCoordinateIndexAndDel(Long objectId, int coordinateIndex, boolean del);
 }

+ 6 - 0
src/main/java/com/izouma/nineth/repo/MetaObjectMoveRepo.java

@@ -1,6 +1,7 @@
 package com.izouma.nineth.repo;
 
 import com.izouma.nineth.domain.MetaObjectMove;
+import com.izouma.nineth.domain.MetaResourceVersion;
 import org.springframework.data.jpa.repository.JpaRepository;
 import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
 import org.springframework.data.jpa.repository.Modifying;
@@ -14,5 +15,10 @@ public interface MetaObjectMoveRepo extends JpaRepository<MetaObjectMove, Long>,
     @Transactional
     void softDelete(Long id);
 
+    MetaObjectMove findByIdAndDel(Long id, boolean del);
+
     MetaObjectMove findByObjectIdAndDel(Long objectId, boolean del);
+
+    @Query(value = "select * from meta_object_move a where a.object_id like ?1 and a.del = false", nativeQuery = true)
+    MetaObjectMove findByObjectId(Long objectId);
 }

+ 3 - 0
src/main/java/com/izouma/nineth/repo/MetaTaskBindRepo.java

@@ -10,6 +10,9 @@ import java.util.List;
 
 public interface MetaTaskBindRepo extends JpaRepository<MetaTaskBind, Long>, JpaSpecificationExecutor<MetaTaskBind> {
 
+    @Query(value = "select * from meta_task_bind m where m.task_id = ?1 and type = ?2 and m.del = false and m.atom_task_id not in (select m2.atom_task_id from meta_task_to_user_new m2 where m2.task_id = ?1 and m2.user_id = ?3 and m2.del = false)", nativeQuery = true)
+    List<MetaTaskBind> findUnReceived(Long taskId, String type, Long userId);
+
     List<MetaTaskBind> findByTaskIdAndTypeAndDel(Long taskId, MetaTaskType type, boolean del);
 
     @Query(value = "select m.atom_task_id from meta_task_bind m where m.task_id = ?1 and m.type = ?2 and m.del = false order by m.atom_task_index asc limit 1", nativeQuery = true)

+ 9 - 3
src/main/java/com/izouma/nineth/repo/MetaTaskNewRepo.java

@@ -1,6 +1,7 @@
 package com.izouma.nineth.repo;
 
 import com.izouma.nineth.domain.MetaTaskNew;
+import com.izouma.nineth.enums.MetaTaskType;
 import org.springframework.data.jpa.repository.JpaRepository;
 import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
 import org.springframework.data.jpa.repository.Modifying;
@@ -17,11 +18,16 @@ public interface MetaTaskNewRepo extends JpaRepository<MetaTaskNew, Long>, JpaSp
 
     MetaTaskNew findByIdAndDel(Long id, boolean del);
 
-    @Query(value = "select m1 from MetaTaskNew m1 where m1.autoReceive = true and m1.del = false and m1.id not in (select m2.taskId from MetaTaskToUserNew m2 where m2.userId = ?1 and m2.del = false)")
+    @Query(value = "select m1 from MetaTaskNew m1 where m1.autoReceive = true and m1.publish = true and m1.del = false and m1.id not in (select m2.taskId from MetaTaskToUserNew m2 where m2.userId = ?1 and m2.del = false)")
     List<MetaTaskNew> findUnReceivedAndAutoReceivedTask(Long userId);
 
     List<MetaTaskNew> findAllByPublishAndDel(boolean publish, boolean del);
 
-    @Query(value = "select * from meta_task_new where finish = false and del = false and publish = true and channel_id = ?2 and id not in (select task_id from meta_task_to_user where user_id = ?1)", nativeQuery = true)
-    List<MetaTaskNew> canGet(Long userId, Long channelId);
+    List<MetaTaskNew> findAllByChannelIdAndPublishAndDel(Long channelId, boolean publish, boolean del);
+
+    @Query("select m.id from MetaTaskNew m where m.publish = true and m.del = false")
+    List<Long> findIdByPublishAndDel();
+
+    @Query("select m.id from MetaTaskNew m where m.type = ?1 and m.del = false and m.publish = true")
+    List<Long> findDailyTaskIds(MetaTaskType type);
 }

+ 9 - 2
src/main/java/com/izouma/nineth/repo/MetaTaskToUserNewRepo.java

@@ -5,17 +5,24 @@ import com.izouma.nineth.domain.MetaTaskToUserNew;
 import com.izouma.nineth.enums.MetaTaskStatus;
 import org.springframework.data.jpa.repository.JpaRepository;
 import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
+import org.springframework.data.jpa.repository.Modifying;
+import org.springframework.data.jpa.repository.Query;
 
+import javax.transaction.Transactional;
 import java.util.List;
 
 public interface MetaTaskToUserNewRepo extends JpaRepository<MetaTaskToUserNew, Long>, JpaSpecificationExecutor<MetaTaskToUserNew> {
 
-    MetaTaskToUserNew findByUserIdAndTaskIdAndAtomTaskIdAndDel(Long userId, Long taskId, Long atomTaskId, boolean del);
+    MetaTaskToUserNew findByUserIdAndTaskIdAndAtomTaskIdAndChannelIdAndDel(Long userId, Long taskId, Long atomTaskId, Long channelId, boolean del);
 
     List<MetaTaskToUserNew> findAllByUserIdAndStatusAndDelAndAtomTaskIdIn(Long userId, MetaTaskStatus status, boolean del, List<Long> atomTaskIds);
 
     MetaTaskToUserNew findByIdAndDel(Long id, boolean del);
 
-    List<MetaTaskToUserNew> findAllByUserIdAndChannelIdAndStatusAndDel(Long userId, Long channelId, MetaTaskStatus status, boolean del);
+    List<MetaTaskToUserNew> findAllByUserIdAndChannelIdAndStatusAndDelAndTaskIdIn(Long userId, Long channelId, MetaTaskStatus status, boolean del, List<Long> taskIds);
 
+    @Query("update MetaTaskToUserNew m set m.status = ?1 where m.taskId in ?2")
+    @Modifying
+    @Transactional
+    void updateStatus(MetaTaskStatus status, List<Long> taskIds);
 }

+ 0 - 1
src/main/java/com/izouma/nineth/security/WebSecurityConfig.java

@@ -153,7 +153,6 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
                 .antMatchers("/websocket/**").permitAll()
                 .antMatchers("/user/websocket/*").permitAll()
                 .antMatchers("/purchaseLevel/websocket/*").permitAll()
-                .antMatchers("/metaAdvertRecord/metaQuery").permitAll()
                 .antMatchers("/metaTask/**").permitAll()
                 .antMatchers("/asset/destroy").permitAll()
                 .antMatchers("/user/topTen").permitAll()

+ 13 - 16
src/main/java/com/izouma/nineth/service/AssetService.java

@@ -757,8 +757,6 @@ public class AssetService {
 
 
         asset.setConsignment(false);
-
-
         assetRepo.saveAndFlush(asset);
     }
 
@@ -811,10 +809,6 @@ public class AssetService {
 
         asset.setPublicShow(false);
         asset.setPublicCollectionId(null);
-
-
-
-
         assetRepo.saveAndFlush(asset);
     }
 
@@ -849,17 +843,20 @@ public class AssetService {
         Objects.requireNonNull(toUser, "转让人不能为空");
         Objects.requireNonNull(reason, "转让原因不能为空");
 
-        if (asset.getType() == CollectionType.DOMAIN) {
-            String domainName = asset.getName().substring(9);
-            DomainOrder domainOrder = domainOrderRepo
-                    .findFirstByDomainNameAndOrderStatus(domainName, OrderStatus.FINISH);
-            if (ObjectUtils.isNotEmpty(domainOrder)) {
-                domainOrder.setOpenHyperLink(false);
-                domainOrder.setHyperLinkType(null);
-                domainOrder.setAddress(null);
-                domainOrder.setCurrentOwnerId(null);
-
+        try {
+            if (asset.getType() == CollectionType.DOMAIN) {
+                if (asset.getCollectionId() != null) {
+                    Optional<DomainOrder> domainOrder = domainOrderRepo.findById(asset.getCollectionId());
+                    domainOrder.ifPresent(domainOrder1 -> {
+                        domainOrder1.setOpenHyperLink(false);
+                        domainOrder1.setHyperLinkType(null);
+                        domainOrder1.setAddress(null);
+                        domainOrder1.setCurrentOwnerId(null);
+                    });
+                }
             }
+        } catch (Exception e) {
+            log.error("超链报错:assetId" + asset.getId(), e);
         }
 
 

+ 101 - 0
src/main/java/com/izouma/nineth/service/MetaAwardDropService.java

@@ -0,0 +1,101 @@
+package com.izouma.nineth.service;
+
+import com.izouma.nineth.config.AliyunProperties;
+import com.izouma.nineth.config.Constants;
+import com.izouma.nineth.domain.MetaAwardDrop;
+import com.izouma.nineth.dto.MetaAwardDropJsonDTO;
+import com.izouma.nineth.dto.MetaRestResult;
+import com.izouma.nineth.dto.MetaServiceResult;
+import com.izouma.nineth.dto.PageQuery;
+import com.izouma.nineth.enums.MetaPropOperationType;
+import com.izouma.nineth.exception.BusinessException;
+import com.izouma.nineth.repo.MetaAwardDropRepo;
+import com.izouma.nineth.utils.JpaUtils;
+import com.izouma.nineth.utils.OSSClientUtil;
+import com.izouma.nineth.utils.SecurityUtils;
+import lombok.AllArgsConstructor;
+import org.apache.commons.collections.CollectionUtils;
+import org.springframework.data.domain.Page;
+import org.springframework.stereotype.Service;
+
+import javax.transaction.Transactional;
+import java.io.IOException;
+import java.time.LocalDateTime;
+import java.util.List;
+import java.util.function.BiFunction;
+
+@Service
+@AllArgsConstructor
+public class MetaAwardDropService {
+
+    private AliyunProperties    aliyunProperties;
+    private MetaAwardDropRepo   metaAwardDropRepo;
+    private MetaUserGoldService metaUserGoldService;
+    private MetaUserPropService metaUserPropService;
+
+    public Page<MetaAwardDrop> all(PageQuery pageQuery) {
+        return metaAwardDropRepo.findAll(JpaUtils.toSpecification(pageQuery, MetaAwardDrop.class), JpaUtils.toPageRequest(pageQuery));
+    }
+
+    @Transactional
+    public MetaAwardDrop save(MetaAwardDrop record) {
+        MetaServiceResult result = MetaAwardDrop.checkMetaAtomTask(record);
+        if (!result.isSuccess()) {
+            throw new BusinessException(result.getMessage());
+        }
+        String operator = SecurityUtils.getAuthenticatedUser().getNickname().concat("(").concat(SecurityUtils.getAuthenticatedUser().getId().toString()).concat(")");
+        record.setOperator(operator);
+        record.setOperatingTime(LocalDateTime.now());
+        MetaAwardDrop save = metaAwardDropRepo.save(record);
+        String s = "application";
+        String[] objectKeys = save.getFileUrl().split(s);
+        if (objectKeys.length != 2) {
+            throw new BusinessException("Illegal fileUrl");
+        }
+        List<MetaAwardDropJsonDTO> metaAwardDropJsonDTOS;
+        try {
+            metaAwardDropJsonDTOS = OSSClientUtil.getDataModel(aliyunProperties, s.concat(objectKeys[1]), MetaAwardDropJsonDTO.class);
+        } catch (IOException e) {
+            throw new BusinessException(e.getMessage());
+        }
+        if (CollectionUtils.isEmpty(metaAwardDropJsonDTOS)) {
+            throw new BusinessException("数据为空");
+        }
+        switch (record.getAwardType()) {
+            case GOLD:
+                dropGold(metaAwardDropJsonDTOS, save.getId());
+                break;
+            case META_PROP:
+                dropProp(metaAwardDropJsonDTOS, save.getId());
+                break;
+            default:
+                throw new BusinessException("不支持的奖励类型");
+        }
+        return save;
+    }
+
+    private void processDrop(List<MetaAwardDropJsonDTO> metaAwardDropJsonDTOS, Long dropId, BiFunction<MetaAwardDropJsonDTO, Long, MetaRestResult<?>> operation) {
+        metaAwardDropJsonDTOS.forEach(metaAwardDropJsonDTO -> {
+            MetaRestResult<?> restResult = operation.apply(metaAwardDropJsonDTO, dropId);
+            if (restResult.getCode() != Constants.MetaRestCode.success) {
+                throw new BusinessException(restResult.getMessage());
+            }
+        });
+    }
+
+    @Transactional
+    public void dropGold(List<MetaAwardDropJsonDTO> metaAwardDropJsonDTOS, Long dropId) {
+        processDrop(metaAwardDropJsonDTOS, dropId, (metaAwardDropJsonDTO, dId) -> {
+            String message = String.format("玩家[%S]于[%S]通过空投获得金币[%S]个,空投id[%S]", metaAwardDropJsonDTO.getUserId(), LocalDateTime.now(), metaAwardDropJsonDTO.getValue(), dId);
+            return metaUserGoldService.changeNum(metaAwardDropJsonDTO.getUserId(), metaAwardDropJsonDTO.getValue(), message);
+        });
+    }
+
+    @Transactional
+    public void dropProp(List<MetaAwardDropJsonDTO> metaAwardDropJsonDTOS, Long dropId) {
+        processDrop(metaAwardDropJsonDTOS, dropId, (metaAwardDropJsonDTO, dId) -> {
+            String message = String.format("玩家[%S]于[%S]通过空投获得道具[%S][%S]个,空投id[%S]", metaAwardDropJsonDTO.getUserId(), LocalDateTime.now(), metaAwardDropJsonDTO.getPropId(), metaAwardDropJsonDTO.getValue(), dId);
+            return metaUserPropService.operate(metaAwardDropJsonDTO.getUserId(), metaAwardDropJsonDTO.getPropId(), MetaPropOperationType.RECEIVE, metaAwardDropJsonDTO.getValue(), message);
+        });
+    }
+}

+ 4 - 2
src/main/java/com/izouma/nineth/service/MetaAwardReceiveService.java

@@ -13,6 +13,7 @@ import org.apache.commons.lang3.StringUtils;
 import org.springframework.stereotype.Service;
 
 import javax.transaction.Transactional;
+import java.time.LocalDateTime;
 import java.util.Objects;
 
 @Service
@@ -34,7 +35,7 @@ public class MetaAwardReceiveService {
                 MetaRestResult<MetaUserGold> restResult;
                 try {
                     int num = Integer.parseInt(metaAwardReceiveDTO.getConfig());
-                    restResult = metaUserGoldService.changeNum(metaAwardReceiveDTO.getUserId(), num, String.format("玩家[%S]通过[%S]获得[%S]个金币", metaAwardReceiveDTO.getUserId(), metaAwardReceiveDTO.getRemark(), num));
+                    restResult = metaUserGoldService.changeNum(metaAwardReceiveDTO.getUserId(), num, String.format("玩家[%S]于[%S]通过[%S]获得[%S]个金币", metaAwardReceiveDTO.getUserId(), LocalDateTime.now(), metaAwardReceiveDTO.getRemark(), num));
                 } catch (Exception e) {
                     return MetaServiceResult.returnError(String.format("金币奖励领取发生异常[%S]", e.getMessage()));
                 }
@@ -49,7 +50,8 @@ public class MetaAwardReceiveService {
                 MetaRestResult<MetaUserProp> operate;
                 try {
                     Long metaPropId = Long.parseLong(metaAwardReceiveDTO.getConfig());
-                    operate = metaUserPropService.operate(metaAwardReceiveDTO.getUserId(), metaPropId, MetaPropOperationType.RECEIVE, 1);
+                    int num = 1;
+                    operate = metaUserPropService.operate(metaAwardReceiveDTO.getUserId(), metaPropId, MetaPropOperationType.RECEIVE, num, String.format("玩家[%S]于[%S]通过[%S]获得[%S]个道具", metaAwardReceiveDTO.getUserId(), LocalDateTime.now(), metaAwardReceiveDTO.getRemark(), num));
                 } catch (Exception e) {
                     return MetaServiceResult.returnError(String.format("道具奖励领取发生异常[%S]", e.getMessage()));
                 }

+ 198 - 1
src/main/java/com/izouma/nineth/service/MetaObjectMoveService.java

@@ -1,20 +1,217 @@
 package com.izouma.nineth.service;
 
+import com.izouma.nineth.config.MetaConstants;
 import com.izouma.nineth.domain.MetaObjectMove;
+import com.izouma.nineth.domain.MetaObjectMoveCoordinate;
+import com.izouma.nineth.dto.MetaObjectMoveCoordinateDTO;
 import com.izouma.nineth.dto.PageQuery;
+import com.izouma.nineth.exception.BusinessException;
+import com.izouma.nineth.repo.MetaObjectMoveCoordinateRepo;
 import com.izouma.nineth.repo.MetaObjectMoveRepo;
 import com.izouma.nineth.utils.JpaUtils;
 import lombok.AllArgsConstructor;
+import org.apache.commons.collections.CollectionUtils;
 import org.springframework.data.domain.Page;
+import org.springframework.data.redis.core.RedisTemplate;
 import org.springframework.stereotype.Service;
 
+import javax.transaction.Transactional;
+import java.time.ZoneOffset;
+import java.util.*;
+import java.util.stream.Collectors;
+
 @Service
 @AllArgsConstructor
 public class MetaObjectMoveService {
 
-    private MetaObjectMoveRepo metaObjectMoveRepo;
+    private MetaObjectMoveRepo            metaObjectMoveRepo;
+    private MetaObjectMoveCoordinateRepo  metaObjectMoveCoordinateRepo;
+    private RedisTemplate<String, Object> redisTemplate;
 
     public Page<MetaObjectMove> all(PageQuery pageQuery) {
         return metaObjectMoveRepo.findAll(JpaUtils.toSpecification(pageQuery, MetaObjectMove.class), JpaUtils.toPageRequest(pageQuery));
     }
+
+    @Transactional
+    public MetaObjectMove save(MetaObjectMove record) {
+        if (Objects.isNull(record)) {
+            throw new BusinessException("params can not be null");
+        }
+        if (Objects.isNull(record.getObjectId())) {
+            throw new BusinessException("objectId can not be null");
+        }
+        if (Objects.isNull(record.getStartTime())) {
+            throw new BusinessException("startTime can not be null");
+        }
+        MetaObjectMove metaObjectMove = metaObjectMoveRepo.findByObjectIdAndDel(record.getObjectId(), false);
+        if (Objects.nonNull(metaObjectMove)) {
+            throw new BusinessException("objectId already exists");
+        }
+        List<MetaObjectMoveCoordinateDTO> metaObjectMoveCoordinateDTOS = record.getMetaObjectMoveCoordinateDTOS();
+        if (CollectionUtils.isEmpty(metaObjectMoveCoordinateDTOS)) {
+            throw new BusinessException("object movement coordinates can not be null");
+        }
+        if (metaObjectMoveCoordinateDTOS.size() < 2) {
+            throw new BusinessException("object moves with at least two coordinates");
+        }
+        for (int i = 0; i < metaObjectMoveCoordinateDTOS.size(); i++) {
+            if (Float.isNaN(metaObjectMoveCoordinateDTOS.get(i).getAxisX())) {
+                throw new BusinessException("coordinates are illegal,axisX can not be null");
+            }
+            if (Float.isNaN(metaObjectMoveCoordinateDTOS.get(i).getAxisY())) {
+                throw new BusinessException("coordinates are illegal,axisY can not be null");
+            }
+            if (Float.isNaN(metaObjectMoveCoordinateDTOS.get(i).getAxisZ())) {
+                throw new BusinessException("coordinates are illegal,axisZ can not be null");
+            }
+            if (Float.isNaN(metaObjectMoveCoordinateDTOS.get(i).getEulerX())) {
+                throw new BusinessException("coordinates are illegal,eulerX can not be null");
+            }
+            if (Float.isNaN(metaObjectMoveCoordinateDTOS.get(i).getEulerY())) {
+                throw new BusinessException("coordinates are illegal,eulerY can not be null");
+            }
+            if (Float.isNaN(metaObjectMoveCoordinateDTOS.get(i).getEulerZ())) {
+                throw new BusinessException("coordinates are illegal,eulerZ can not be null");
+            }
+            if (i > 0 && metaObjectMoveCoordinateDTOS.get(i).getTime() <= metaObjectMoveCoordinateDTOS.get(i - 1).getTime()) {
+                throw new BusinessException("coordinates are illegal,time must be incremented");
+            }
+        }
+        record.setTotalTime(metaObjectMoveCoordinateDTOS.get(metaObjectMoveCoordinateDTOS.size() - 1).getTime());
+        MetaObjectMove save = metaObjectMoveRepo.save(record);
+        String objectMoveKey = MetaConstants.META_OBJECT_MOVE_REDIS_KEY.concat(String.valueOf(save.getObjectId()));
+        // 缓存-物体移动配置
+        if (Boolean.FALSE.equals(redisTemplate.hasKey(objectMoveKey))) {
+            redisTemplate.opsForValue().set(objectMoveKey, save);
+            handleCoordinate(save.getId());
+            return save;
+        }
+        redisTemplate.delete(objectMoveKey);
+        redisTemplate.opsForValue().set(objectMoveKey, save);
+        handleCoordinate(save.getId());
+        return save;
+    }
+
+    @Transactional
+    public void handleCoordinate(Long id) {
+        MetaObjectMove metaObjectMove = metaObjectMoveRepo.findByIdAndDel(id, false);
+        if (Objects.isNull(metaObjectMove)) {
+            throw new BusinessException("物体移动配置为空");
+        }
+        List<MetaObjectMoveCoordinateDTO> metaObjectMoveCoordinateDTOS = metaObjectMove.getMetaObjectMoveCoordinateDTOS();
+        if (CollectionUtils.isEmpty(metaObjectMoveCoordinateDTOS)) {
+            throw new BusinessException("物体移动坐标配置为空");
+        }
+        int size = metaObjectMoveCoordinateDTOS.size();
+        if (size < 2) {
+            throw new BusinessException("物体移动最低配置两个坐标");
+        }
+        List<MetaObjectMoveCoordinate> list = new ArrayList<>();
+        for (int i = 0; i < size - 1; i++) {
+            MetaObjectMoveCoordinateDTO start = metaObjectMoveCoordinateDTOS.get(i);
+            // 开始时间(getTime取出来的值单位为秒)
+            int startTime = (int) start.getTime() * 24;
+            MetaObjectMoveCoordinateDTO end = metaObjectMoveCoordinateDTOS.get(i + 1);
+            // 到达时间(getTime取出来的值单位为秒)
+            int endTime = (int) end.getTime() * 24;
+            // 两个坐标间总共移动时间
+            int time = endTime - startTime;
+            if (time <= 0) {
+                throw new BusinessException("两个坐标间移动时间必须大于0");
+            }
+            float startAxisX = start.getAxisX();
+            float endAxisX = end.getAxisX();
+            float axisX = (endAxisX - startAxisX) / time;
+
+            float startAxisY = start.getAxisY();
+            float endAxisY = end.getAxisY();
+            float axisY = (endAxisY - startAxisY) / time;
+
+            float startAxisZ = start.getAxisZ();
+            float endAxisZ = end.getAxisZ();
+            float axisZ = (endAxisZ - startAxisZ) / time;
+
+            float startEulerX = start.getEulerX();
+            float endEulerX = end.getEulerX();
+            float eulerX = (endEulerX - startEulerX) / time;
+
+            float startEulerY = start.getEulerY();
+            float endEulerY = end.getEulerY();
+            float eulerY = (endEulerY - startEulerY) / time;
+
+            float startEulerZ = start.getEulerZ();
+            float endEulerZ = end.getEulerZ();
+            float eulerZ = (endEulerZ - startEulerZ) / time;
+
+            for (int a = startTime; a <= endTime; a++) {
+                MetaObjectMoveCoordinate dbExist = metaObjectMoveCoordinateRepo.findByObjectIdAndCoordinateIndexAndDel(metaObjectMove.getObjectId(), a, false);
+                if (Objects.isNull(dbExist)) {
+                    dbExist = new MetaObjectMoveCoordinate();
+                    dbExist.setObjectId(metaObjectMove.getObjectId());
+                    dbExist.setCoordinateIndex(a);
+                    dbExist.setAxisX(startAxisX + (a - startTime) * axisX);
+                    dbExist.setAxisY(startAxisY + (a - startTime) * axisY);
+                    dbExist.setAxisZ(startAxisZ + (a - startTime) * axisZ);
+                    dbExist.setEulerX(startEulerX + (a - startTime) * eulerX);
+                    dbExist.setEulerY(startEulerY + (a - startTime) * eulerY);
+                    dbExist.setEulerZ(startEulerZ + (a - startTime) * eulerZ);
+                    list.add(dbExist);
+                    // 查询缓存坐标信息
+                    String coordinateKey = MetaConstants.META_OBJECT_INDEX_REDIS_KEY.concat(String.valueOf(dbExist.getObjectId())).concat("_").concat(String.valueOf(dbExist.getCoordinateIndex()));
+                    if (Boolean.FALSE.equals(redisTemplate.hasKey(coordinateKey))) {
+                        redisTemplate.opsForValue().set(coordinateKey, dbExist);
+                    } else {
+                        redisTemplate.delete(coordinateKey);
+                        redisTemplate.opsForValue().set(coordinateKey, dbExist);
+                    }
+                }
+            }
+        }
+        // 多索引去重
+        List<MetaObjectMoveCoordinate> distinctList = list.stream()
+                                                          .collect(Collectors.collectingAndThen(Collectors.toCollection(() ->
+                                                                          new TreeSet<>(Comparator.comparing(MetaObjectMoveCoordinate::getCoordinateIndex))),
+                                                                  ArrayList::new));
+        metaObjectMoveCoordinateRepo.saveAll(distinctList);
+    }
+
+    public MetaObjectMoveCoordinate queryCoordinate(Long objectId) {
+        // 查询缓存-物体移动配置
+        String objectMoveKey = MetaConstants.META_OBJECT_MOVE_REDIS_KEY.concat(String.valueOf(objectId));
+        MetaObjectMove metaObjectMove = (MetaObjectMove) redisTemplate.opsForValue().get(objectMoveKey);
+        // 缓存不存在 查询数据库
+        if (Objects.isNull(metaObjectMove)) {
+            metaObjectMove = metaObjectMoveRepo.findByObjectIdAndDel(objectId, false);
+            if (Objects.isNull(metaObjectMove)) {
+                throw new BusinessException("物体配置不存在!");
+            }
+            // 重新缓存-物体移动配置
+            redisTemplate.delete(objectMoveKey);
+            redisTemplate.opsForValue().set(objectMoveKey, metaObjectMove);
+        }
+        // 开始时间戳(单位为秒)
+        long startTime = metaObjectMove.getStartTime().toInstant(ZoneOffset.of("+8")).toEpochMilli() / 1000;
+        // 当前时间戳(单位为秒)
+        long currentTime = System.currentTimeMillis() / 1000;
+        // 计算坐标索引
+        long index = (currentTime - startTime) % (metaObjectMove.getTotalTime() * 2L);
+        if (index > (metaObjectMove.getTotalTime())) {
+            index = metaObjectMove.getTotalTime() * 2L - index;
+        }
+        index = index * 24;
+        // 查询缓存坐标信息
+        String coordinateKey = MetaConstants.META_OBJECT_INDEX_REDIS_KEY.concat(String.valueOf(objectId)).concat("_").concat(String.valueOf(index));
+        MetaObjectMoveCoordinate metaObjectMoveCoordinate = (MetaObjectMoveCoordinate) redisTemplate.opsForValue().get(coordinateKey);
+        if (Objects.isNull(metaObjectMoveCoordinate)) {
+            // 查询数据库坐标信息
+            metaObjectMoveCoordinate = metaObjectMoveCoordinateRepo.findByObjectIdAndCoordinateIndexAndDel(objectId, (int) index, false);
+            if (Objects.isNull(metaObjectMoveCoordinate)) {
+                throw new BusinessException("坐标信息为空");
+            }
+            // 重新缓存坐标信息
+            redisTemplate.delete(coordinateKey);
+            redisTemplate.opsForValue().set(coordinateKey, metaObjectMoveCoordinate);
+        }
+        return metaObjectMoveCoordinate;
+    }
 }

+ 11 - 8
src/main/java/com/izouma/nineth/service/MetaStoreService.java

@@ -69,28 +69,31 @@ public class MetaStoreService {
             return MetaRestResult.returnError("道具信息为空");
         }
         MetaUserProp dbMetaUserProp = metaUserPropRepo.findByUserIdAndMetaPropIdAndDel(userId, metaProp.getId(), false);
+        LocalDateTime now = LocalDateTime.now();
+        int num = 1;
+        String msg = String.format("玩家[%S]于[%S]使用[%S]个金币,购买[%S]个道具,道具id[%S]", userId, now, price, num, metaProp.getId());
         if (Objects.isNull(dbMetaUserProp)) {
-            dbMetaUserProp = MetaUserProp.create(userId, metaProp, 1);
-            MetaRestResult<MetaUserGold> restResult = metaUserGoldService.changeNum(userId, -price, String.format("购买道具:[%S],消耗金币[%s]", metaProp.getId(), price));
+            dbMetaUserProp = MetaUserProp.create(userId, metaProp, num);
+            MetaRestResult<MetaUserGold> restResult = metaUserGoldService.changeNum(userId, -price, msg);
             if (restResult.getCode() != Constants.MetaRestCode.success) {
                 return MetaRestResult.returnError(restResult.getMessage());
             }
             metaUserPropRepo.save(dbMetaUserProp);
-            metaUserPropRecordService.save(userId, metaProp, MetaPropOperationType.RECEIVE, 1);
-            metaStorePurchaseRecordRepo.save(new MetaStorePurchaseRecord(metaStore.getId(), userId, LocalDateTime.now()));
+            metaUserPropRecordService.save(userId, metaProp, MetaPropOperationType.RECEIVE, num, msg);
+            metaStorePurchaseRecordRepo.save(new MetaStorePurchaseRecord(metaStore.getId(), userId, now));
             return MetaRestResult.returnSuccess("购买成功!");
         }
         if (MetaPropUsedType.PERMANENT.equals(metaProp.getUsedType()) && dbMetaUserProp.getNum() >= 1) {
             return MetaRestResult.returnError("已拥有永久道具,不可购买");
         }
-        MetaRestResult<MetaUserGold> restResult = metaUserGoldService.changeNum(userId, -price, String.format("购买道具:[%S],消耗金币[%s]", metaProp.getId(), price));
+        MetaRestResult<MetaUserGold> restResult = metaUserGoldService.changeNum(userId, -price, msg);
         if (restResult.getCode() != Constants.MetaRestCode.success) {
             return MetaRestResult.returnError(restResult.getMessage());
         }
-        dbMetaUserProp.setNum(dbMetaUserProp.getNum() + 1);
+        dbMetaUserProp.setNum(dbMetaUserProp.getNum() + num);
         metaUserPropRepo.save(dbMetaUserProp);
-        metaUserPropRecordService.save(userId, metaProp, MetaPropOperationType.RECEIVE, 1);
-        metaStorePurchaseRecordRepo.save(new MetaStorePurchaseRecord(metaStore.getId(), userId, LocalDateTime.now()));
+        metaUserPropRecordService.save(userId, metaProp, MetaPropOperationType.RECEIVE, num, msg);
+        metaStorePurchaseRecordRepo.save(new MetaStorePurchaseRecord(metaStore.getId(), userId, now));
         return MetaRestResult.returnSuccess("购买成功!");
 
     }

+ 88 - 3
src/main/java/com/izouma/nineth/service/MetaTaskNewService.java

@@ -1,11 +1,13 @@
 package com.izouma.nineth.service;
 
+import com.izouma.nineth.domain.MetaAtomTask;
 import com.izouma.nineth.domain.MetaTaskBind;
 import com.izouma.nineth.domain.MetaTaskNew;
 import com.izouma.nineth.dto.MetaRestResult;
 import com.izouma.nineth.dto.PageQuery;
 import com.izouma.nineth.enums.MetaTaskType;
 import com.izouma.nineth.exception.BusinessException;
+import com.izouma.nineth.repo.MetaAtomTaskRepo;
 import com.izouma.nineth.repo.MetaTaskBindRepo;
 import com.izouma.nineth.repo.MetaTaskNewRepo;
 import com.izouma.nineth.utils.JpaUtils;
@@ -15,7 +17,9 @@ import org.apache.commons.collections.CollectionUtils;
 import org.springframework.data.domain.Page;
 import org.springframework.stereotype.Service;
 
+import java.util.ArrayList;
 import java.util.List;
+import java.util.Objects;
 
 @Service
 @AllArgsConstructor
@@ -23,6 +27,7 @@ public class MetaTaskNewService {
 
     private MetaTaskNewRepo  metaTaskNewRepo;
     private MetaTaskBindRepo metaTaskBindRepo;
+    private MetaAtomTaskRepo metaAtomTaskRepo;
 
     public MetaTaskNew save(MetaTaskNew record) {
         if (record.getId() != null) {
@@ -75,19 +80,85 @@ public class MetaTaskNewService {
     }
 
     public MetaRestResult<List<MetaTaskNew>> canGet(Long userId, Long channelId) {
-        List<MetaTaskNew> metaTaskNews = metaTaskNewRepo.canGet(userId, channelId);
-        metaTaskNews.forEach(this::buildAtomTask);
-        return MetaRestResult.returnSuccess(metaTaskNews);
+        List<MetaTaskNew> metaTaskNews = metaTaskNewRepo.findAllByChannelIdAndPublishAndDel(channelId, true, false);
+        List<MetaTaskNew> newMetaTaskNews = new ArrayList<>();
+        try {
+            metaTaskNews.forEach(metaTaskNew -> {
+                buildAtomTaskUnReceived(metaTaskNew, userId);
+            });
+            metaTaskNews.forEach(metaTaskNew -> {
+                removeMetaTaskNew(metaTaskNew, newMetaTaskNews);
+            });
+        } catch (Exception e) {
+            return MetaRestResult.returnError(e.getMessage());
+        }
+        return MetaRestResult.returnSuccess(newMetaTaskNews);
+    }
+
+    private void removeMetaTaskNew(MetaTaskNew metaTaskNew, List<MetaTaskNew> newMetaTaskNews) {
+        if (MetaTaskType.MAIN_LINE.equals(metaTaskNew.getType())) {
+            if (CollectionUtils.isEmpty(metaTaskNew.getMetaNodeTask()) && CollectionUtils.isEmpty(metaTaskNew.getMetaBranchLineTask())) {
+                return;
+            }
+            newMetaTaskNews.add(metaTaskNew);
+            return;
+        }
+        if (MetaTaskType.BRANCH_LINE.equals(metaTaskNew.getType())) {
+            if (CollectionUtils.isEmpty(metaTaskNew.getMetaBranchLineTask())) {
+                return;
+            }
+            newMetaTaskNews.add(metaTaskNew);
+            return;
+        }
+        if (MetaTaskType.DAILY.equals(metaTaskNew.getType())) {
+            if (CollectionUtils.isEmpty(metaTaskNew.getMetaDailyTask())) {
+                return;
+            }
+            newMetaTaskNews.add(metaTaskNew);
+        }
+    }
+
+    private void buildAtomTaskUnReceived(MetaTaskNew metaTaskNew, Long userId) {
+        if (MetaTaskType.MAIN_LINE.equals(metaTaskNew.getType())) {
+            List<MetaTaskBind> metaNodeTask = metaTaskBindRepo.findUnReceived(metaTaskNew.getId(), MetaTaskType.NODE.toString(), userId);
+            if (CollectionUtils.isNotEmpty(metaNodeTask)) {
+                buildMetaAtomTask(metaNodeTask);
+                metaTaskNew.setMetaNodeTask(metaNodeTask);
+            }
+            List<MetaTaskBind> metaBranchLineTask = metaTaskBindRepo.findUnReceived(metaTaskNew.getId(), MetaTaskType.BRANCH_LINE.toString(), userId);
+            if (CollectionUtils.isNotEmpty(metaBranchLineTask)) {
+                buildMetaAtomTask(metaBranchLineTask);
+                metaTaskNew.setMetaBranchLineTask(metaBranchLineTask);
+            }
+            return;
+        }
+        if (MetaTaskType.BRANCH_LINE.equals(metaTaskNew.getType())) {
+            List<MetaTaskBind> metaBranchLineTask = metaTaskBindRepo.findUnReceived(metaTaskNew.getId(), MetaTaskType.BRANCH_LINE.toString(), userId);
+            if (CollectionUtils.isNotEmpty(metaBranchLineTask)) {
+                buildMetaAtomTask(metaBranchLineTask);
+                metaTaskNew.setMetaBranchLineTask(metaBranchLineTask);
+            }
+            return;
+        }
+        if (MetaTaskType.DAILY.equals(metaTaskNew.getType())) {
+            List<MetaTaskBind> metaDailyTask = metaTaskBindRepo.findUnReceived(metaTaskNew.getId(), MetaTaskType.DAILY.toString(), userId);
+            if (CollectionUtils.isNotEmpty(metaDailyTask)) {
+                buildMetaAtomTask(metaDailyTask);
+                metaTaskNew.setMetaDailyTask(metaDailyTask);
+            }
+        }
     }
 
     private void buildAtomTask(MetaTaskNew metaTaskNew) {
         if (MetaTaskType.MAIN_LINE.equals(metaTaskNew.getType())) {
             List<MetaTaskBind> metaNodeTask = metaTaskBindRepo.findByTaskIdAndTypeAndDel(metaTaskNew.getId(), MetaTaskType.NODE, false);
             if (CollectionUtils.isNotEmpty(metaNodeTask)) {
+                buildMetaAtomTask(metaNodeTask);
                 metaTaskNew.setMetaNodeTask(metaNodeTask);
             }
             List<MetaTaskBind> metaBranchLineTask = metaTaskBindRepo.findByTaskIdAndTypeAndDel(metaTaskNew.getId(), MetaTaskType.BRANCH_LINE, false);
             if (CollectionUtils.isNotEmpty(metaBranchLineTask)) {
+                buildMetaAtomTask(metaBranchLineTask);
                 metaTaskNew.setMetaBranchLineTask(metaBranchLineTask);
             }
             return;
@@ -95,6 +166,7 @@ public class MetaTaskNewService {
         if (MetaTaskType.BRANCH_LINE.equals(metaTaskNew.getType())) {
             List<MetaTaskBind> metaBranchLineTask = metaTaskBindRepo.findByTaskIdAndTypeAndDel(metaTaskNew.getId(), MetaTaskType.BRANCH_LINE, false);
             if (CollectionUtils.isNotEmpty(metaBranchLineTask)) {
+                buildMetaAtomTask(metaBranchLineTask);
                 metaTaskNew.setMetaBranchLineTask(metaBranchLineTask);
             }
             return;
@@ -102,8 +174,21 @@ public class MetaTaskNewService {
         if (MetaTaskType.DAILY.equals(metaTaskNew.getType())) {
             List<MetaTaskBind> metaDailyTask = metaTaskBindRepo.findByTaskIdAndTypeAndDel(metaTaskNew.getId(), MetaTaskType.DAILY, false);
             if (CollectionUtils.isNotEmpty(metaDailyTask)) {
+                buildMetaAtomTask(metaDailyTask);
                 metaTaskNew.setMetaDailyTask(metaDailyTask);
             }
         }
     }
+
+    private void buildMetaAtomTask(List<MetaTaskBind> metaTaskBinds) {
+        if (CollectionUtils.isNotEmpty(metaTaskBinds)) {
+            metaTaskBinds.forEach(metaTaskBind -> {
+                MetaAtomTask metaAtomTask = metaAtomTaskRepo.findByIdAndDel(metaTaskBind.getAtomTaskId(), false);
+                if (Objects.isNull(metaAtomTask)) {
+                    throw new BusinessException("原子任务不存在");
+                }
+                metaTaskBind.setMetaAtomTask(metaAtomTask);
+            });
+        }
+    }
 }

+ 73 - 76
src/main/java/com/izouma/nineth/service/MetaTaskToUserNewService.java

@@ -1,6 +1,7 @@
 package com.izouma.nineth.service;
 
 import cn.hutool.core.collection.CollectionUtil;
+import com.alibaba.druid.support.json.JSONUtils;
 import com.alibaba.excel.util.CollectionUtils;
 import com.izouma.nineth.config.Constants;
 import com.izouma.nineth.domain.*;
@@ -18,10 +19,12 @@ import lombok.AllArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang3.StringUtils;
 import org.springframework.data.domain.Page;
+import org.springframework.scheduling.annotation.Scheduled;
 import org.springframework.stereotype.Service;
 
 import javax.transaction.Transactional;
 import java.time.LocalDateTime;
+import java.util.ArrayList;
 import java.util.List;
 import java.util.Objects;
 
@@ -38,7 +41,8 @@ public class MetaTaskToUserNewService {
     private MetaUserTaskProgressNewRepo metaUserTaskProgressNewRepo;
 
     public Page<MetaTaskToUserNew> all(PageQuery pageQuery) {
-        return metaTaskToUserNewRepo.findAll(JpaUtils.toSpecification(pageQuery, MetaTaskToUserNew.class), JpaUtils.toPageRequest(pageQuery));
+        return metaTaskToUserNewRepo.findAll(JpaUtils.toSpecification(pageQuery, MetaTaskToUserNew.class), JpaUtils
+                .toPageRequest(pageQuery));
     }
 
     @Transactional
@@ -52,19 +56,22 @@ public class MetaTaskToUserNewService {
                 metaTaskToUserNew.setTaskId(metaTaskNew.getId());
                 // 设置主动领取第一个索引的基础任务
                 if (MetaTaskType.MAIN_LINE.equals(metaTaskNew.getType())) {
-                    Long atomTaskId = metaTaskBindRepo.findAtomTaskId(metaTaskNew.getId(), MetaTaskType.NODE.toString());
+                    Long atomTaskId = metaTaskBindRepo
+                            .findAtomTaskId(metaTaskNew.getId(), MetaTaskType.NODE.toString());
                     if (Objects.nonNull(atomTaskId)) {
                         metaTaskToUserNew.setAtomTaskId(atomTaskId);
                     }
                 }
                 if (MetaTaskType.BRANCH_LINE.equals(metaTaskNew.getType())) {
-                    Long atomTaskId = metaTaskBindRepo.findAtomTaskId(metaTaskNew.getId(), MetaTaskType.BRANCH_LINE.toString());
+                    Long atomTaskId = metaTaskBindRepo
+                            .findAtomTaskId(metaTaskNew.getId(), MetaTaskType.BRANCH_LINE.toString());
                     if (Objects.nonNull(atomTaskId)) {
                         metaTaskToUserNew.setAtomTaskId(atomTaskId);
                     }
                 }
                 if (MetaTaskType.DAILY.equals(metaTaskNew.getType())) {
-                    Long atomTaskId = metaTaskBindRepo.findAtomTaskId(metaTaskNew.getId(), MetaTaskType.DAILY.toString());
+                    Long atomTaskId = metaTaskBindRepo
+                            .findAtomTaskId(metaTaskNew.getId(), MetaTaskType.DAILY.toString());
                     if (Objects.nonNull(atomTaskId)) {
                         metaTaskToUserNew.setAtomTaskId(atomTaskId);
                     }
@@ -91,13 +98,13 @@ public class MetaTaskToUserNewService {
             return MetaRestResult.returnError("Illegal parameter : atomTaskId can not be null");
         }
         MetaTaskNew metaTaskNew = metaTaskNewRepo.findByIdAndDel(metaTaskToUserNew.getTaskId(), false);
-        MetaServiceResult checkMetaTaskNewResult = checkMetaTaskNew(metaTaskNew);
+        MetaServiceResult checkMetaTaskNewResult = MetaTaskNew.checkMetaTaskNew(metaTaskNew);
         if (!checkMetaTaskNewResult.isSuccess()) {
             return MetaRestResult.returnError(checkMetaTaskNewResult.getMessage());
         }
         metaTaskToUserNew.setMetaTaskNew(metaTaskNew);
         MetaAtomTask metaAtomTask = metaAtomTaskRepo.findByIdAndDel(metaTaskToUserNew.getAtomTaskId(), false);
-        MetaServiceResult checkMetaAtomTaskResult = checkMetaAtomTask(metaAtomTask);
+        MetaServiceResult checkMetaAtomTaskResult = MetaAtomTask.checkMetaAtomTask(metaAtomTask);
         if (!checkMetaAtomTaskResult.isSuccess()) {
             return MetaRestResult.returnError(checkMetaAtomTaskResult.getMessage());
         }
@@ -107,7 +114,9 @@ public class MetaTaskToUserNewService {
             return MetaRestResult.returnError(buildMetaPropResult.getMessage());
         }
         // 判断当前玩家是否领取过基础任务
-        MetaTaskToUserNew dbMetaTaskToUserNew = metaTaskToUserNewRepo.findByUserIdAndTaskIdAndAtomTaskIdAndDel(metaTaskToUserNew.getUserId(), metaTaskToUserNew.getTaskId(), metaTaskToUserNew.getAtomTaskId(), false);
+        MetaTaskToUserNew dbMetaTaskToUserNew = metaTaskToUserNewRepo
+                .findByUserIdAndTaskIdAndAtomTaskIdAndChannelIdAndDel(metaTaskToUserNew.getUserId(), metaTaskToUserNew
+                        .getTaskId(), metaTaskToUserNew.getAtomTaskId(), metaTaskNew.getChannelId(), false);
         if (Objects.nonNull(dbMetaTaskToUserNew)) {
             return MetaRestResult.returnError(String.format("当前用户已在[%S]领取过该任务", dbMetaTaskToUserNew.getGetTime()));
         }
@@ -117,7 +126,8 @@ public class MetaTaskToUserNewService {
         if (MetaAwardTypeEnum.META_PROP.equals(metaAtomTask.getAwardType())) {
             MetaProp metaProp = metaPropRepo.findByIdAndDel(Long.parseLong(metaAtomTask.getAwardConfig()), false);
             if (Objects.isNull(metaProp)) {
-                return MetaRestResult.returnError(String.format("基础任务[%S]奖励配置的道具不存在", metaTaskToUserNew.getAtomTaskId()));
+                return MetaRestResult
+                        .returnError(String.format("基础任务[%S]奖励配置的道具不存在", metaTaskToUserNew.getAtomTaskId()));
             }
             metaTaskToUserNew.setMetaProp(metaProp);
         }
@@ -134,20 +144,32 @@ public class MetaTaskToUserNewService {
     }
 
     public MetaRestResult<List<MetaTaskToUserNew>> findByStatus(Long userId, Long channelId, MetaTaskStatus status) {
-        List<MetaTaskToUserNew> metaTaskToUsers = metaTaskToUserNewRepo.findAllByUserIdAndChannelIdAndStatusAndDel(userId, channelId, status, false);
-        metaTaskToUsers.forEach(this::setSingleProgress);
+        List<Long> metaTaskNewIds = metaTaskNewRepo.findIdByPublishAndDel();
+        List<MetaTaskToUserNew> metaTaskToUsers = CollectionUtils.isEmpty(metaTaskNewIds) ? new ArrayList<>() :
+                metaTaskToUserNewRepo
+                        .findAllByUserIdAndChannelIdAndStatusAndDelAndTaskIdIn(userId, channelId, status, false, metaTaskNewIds);
+        try {
+            metaTaskToUsers.forEach(metaTaskToUserNew -> {
+                MetaRestResult<MetaTaskToUserNew> result = setSingleProgress(metaTaskToUserNew);
+                if (result.getCode() != Constants.MetaRestCode.success) {
+                    throw new BusinessException(result.getMessage());
+                }
+            });
+        } catch (Exception e) {
+            return MetaRestResult.returnError(e.getMessage());
+        }
         return MetaRestResult.returnSuccess(metaTaskToUsers);
     }
 
     public MetaRestResult<MetaTaskToUserNew> setSingleProgress(MetaTaskToUserNew metaTaskToUserNew) {
         MetaAtomTask metaAtomTask = metaAtomTaskRepo.findByIdAndDel(metaTaskToUserNew.getAtomTaskId(), false);
-        MetaServiceResult checkMetaAtomTaskResult = checkMetaAtomTask(metaAtomTask);
+        MetaServiceResult checkMetaAtomTaskResult = MetaAtomTask.checkMetaAtomTask(metaAtomTask);
         if (!checkMetaAtomTaskResult.isSuccess()) {
             return MetaRestResult.returnError(checkMetaAtomTaskResult.getMessage());
         }
         metaTaskToUserNew.setMetaAtomTask(metaAtomTask);
         MetaTaskNew metaTaskNew = metaTaskNewRepo.findByIdAndDel(metaTaskToUserNew.getTaskId(), false);
-        MetaServiceResult checkMetaTaskNewResult = checkMetaTaskNew(metaTaskNew);
+        MetaServiceResult checkMetaTaskNewResult = MetaTaskNew.checkMetaTaskNew(metaTaskNew);
         if (!checkMetaTaskNewResult.isSuccess()) {
             return MetaRestResult.returnError(checkMetaTaskNewResult.getMessage());
         }
@@ -168,8 +190,11 @@ public class MetaTaskToUserNewService {
     private void setProgress(MetaTaskToUserNew metaTaskToUserNew) {
         MetaAtomTask metaAtomTask = metaTaskToUserNew.getMetaAtomTask();
         List<Long> atomTaskIds = metaTaskBindRepo.findAtomTaskIds(metaTaskToUserNew.getTaskId());
-        List<MetaTaskToUserNew> completed = metaTaskToUserNewRepo.findAllByUserIdAndStatusAndDelAndAtomTaskIdIn(metaTaskToUserNew.getUserId(), MetaTaskStatus.COMPLETION, false, atomTaskIds);
-        metaTaskToUserNew.setProcess(String.valueOf(completed.size()).concat("/").concat(String.valueOf(atomTaskIds.size())));
+        List<MetaTaskToUserNew> completed = metaTaskToUserNewRepo
+                .findAllByUserIdAndStatusAndDelAndAtomTaskIdIn(metaTaskToUserNew
+                        .getUserId(), MetaTaskStatus.COMPLETION, false, atomTaskIds);
+        metaTaskToUserNew
+                .setProcess(String.valueOf(completed.size()).concat("/").concat(String.valueOf(atomTaskIds.size())));
         String value = metaAtomTask.getTargetConfig();
         String PREFIX = "0/";
         switch (metaAtomTask.getTargetType()) {
@@ -181,12 +206,14 @@ public class MetaTaskToUserNewService {
                     break;
                 }
                 String[] split = value.split(" ");
-                List<MetaUserTaskProgressNew> collectCollection = metaUserTaskProgressNewRepo.findAllByMetaTaskToUserNewIdAndDel(metaTaskToUserNew.getId(), false);
+                List<MetaUserTaskProgressNew> collectCollection = metaUserTaskProgressNewRepo
+                        .findAllByMetaTaskToUserNewIdAndDel(metaTaskToUserNew.getId(), false);
                 if (CollectionUtils.isEmpty(collectCollection)) {
                     metaTaskToUserNew.setAtomTaskProcess(PREFIX.concat(String.valueOf(split.length)));
                     break;
                 }
-                metaTaskToUserNew.setAtomTaskProcess(String.valueOf(collectCollection.size()).concat("/").concat(String.valueOf(split.length)));
+                metaTaskToUserNew.setAtomTaskProcess(String.valueOf(collectCollection.size()).concat("/")
+                                                           .concat(String.valueOf(split.length)));
                 break;
             case ON_LINE_TIME_DAILY:
                 if (StringUtils.isBlank(value)) {
@@ -195,11 +222,17 @@ public class MetaTaskToUserNewService {
                     metaTaskToUserNew.setAtomTaskProcess(errMsg);
                     break;
                 }
-                MetaUserTaskProgressNew onLineTimeDaily = metaUserTaskProgressNewRepo.findByMetaTaskToUserNewIdAndDelAndCreatedAtAfter(metaTaskToUserNew.getId(), false, LocalDateTime.now().withHour(0).withMinute(0).withSecond(0));
+                MetaUserTaskProgressNew onLineTimeDaily = metaUserTaskProgressNewRepo
+                        .findByMetaTaskToUserNewIdAndDelAndCreatedAtAfter(metaTaskToUserNew
+                                .getId(), false, LocalDateTime.now().withHour(0).withMinute(0).withSecond(0));
                 if (Objects.isNull(onLineTimeDaily)) {
                     metaTaskToUserNew.setAtomTaskProcess(PREFIX.concat(value));
                     break;
                 }
+                if (Integer.parseInt(onLineTimeDaily.getRemark()) >= Integer.parseInt(value)) {
+                    metaTaskToUserNew.setAtomTaskProcess(value.concat("/").concat(value));
+                    break;
+                }
                 metaTaskToUserNew.setAtomTaskProcess(onLineTimeDaily.getRemark().concat("/").concat(value));
                 break;
             case ACCUMULATE:
@@ -209,7 +242,8 @@ public class MetaTaskToUserNewService {
                     metaTaskToUserNew.setAtomTaskProcess(errMsg);
                     break;
                 }
-                List<MetaUserTaskProgressNew> accumulate = metaUserTaskProgressNewRepo.findAllByMetaTaskToUserNewIdAndDel(metaTaskToUserNew.getId(), false);
+                List<MetaUserTaskProgressNew> accumulate = metaUserTaskProgressNewRepo
+                        .findAllByMetaTaskToUserNewIdAndDel(metaTaskToUserNew.getId(), false);
                 if (CollectionUtils.isEmpty(accumulate)) {
                     metaTaskToUserNew.setAtomTaskProcess(PREFIX.concat(value));
                     break;
@@ -224,62 +258,6 @@ public class MetaTaskToUserNewService {
         }
     }
 
-    /**
-     * 校验基础任务
-     *
-     * @param metaAtomTask 基础任务
-     * @return result
-     */
-    private MetaServiceResult checkMetaAtomTask(MetaAtomTask metaAtomTask) {
-        if (Objects.isNull(metaAtomTask)) {
-            return MetaServiceResult.returnError("基础任务不存在");
-        }
-        if (StringUtils.isBlank(metaAtomTask.getName())) {
-            return MetaServiceResult.returnError(String.format("基础任务[%S]缺少任务名称", metaAtomTask.getId()));
-        }
-        if (Objects.isNull(metaAtomTask.getDetail())) {
-            return MetaServiceResult.returnError(String.format("基础任务[%S]缺少任务详情", metaAtomTask.getId()));
-        }
-        if (Objects.isNull(metaAtomTask.getTargetType())) {
-            return MetaServiceResult.returnError(String.format("基础任务[%S]缺少目标", metaAtomTask.getId()));
-        }
-        if (StringUtils.isBlank(metaAtomTask.getTargetConfig())) {
-            return MetaServiceResult.returnError(String.format("基础任务[%S]缺少目标配置", metaAtomTask.getId()));
-        }
-        if (Objects.isNull(metaAtomTask.getAwardType())) {
-            return MetaServiceResult.returnError(String.format("基础任务[%S]缺少奖励类型", metaAtomTask.getId()));
-        }
-        if (StringUtils.isBlank(metaAtomTask.getAwardConfig())) {
-            return MetaServiceResult.returnError(String.format("基础任务[%S]缺少奖励配置", metaAtomTask.getId()));
-        }
-        return MetaServiceResult.returnSuccess();
-    }
-
-    /**
-     * 校验任务
-     *
-     * @param metaTaskNew 任务信息
-     * @return result
-     */
-    private MetaServiceResult checkMetaTaskNew(MetaTaskNew metaTaskNew) {
-        if (Objects.isNull(metaTaskNew)) {
-            return MetaServiceResult.returnError("任务不存在");
-        }
-        if (!metaTaskNew.isPublish()) {
-            return MetaServiceResult.returnError("status error : task has not been published");
-        }
-        if (StringUtils.isBlank(metaTaskNew.getName())) {
-            return MetaServiceResult.returnError(String.format("任务[%S]缺少任务名称", metaTaskNew.getId()));
-        }
-        if (Objects.isNull(metaTaskNew.getDetail())) {
-            return MetaServiceResult.returnError(String.format("任务[%S]缺少任务详情", metaTaskNew.getId()));
-        }
-        if (Objects.isNull(metaTaskNew.getType())) {
-            return MetaServiceResult.returnError(String.format("任务[%S]缺少任务类型", metaTaskNew.getId()));
-        }
-        return MetaServiceResult.returnSuccess();
-    }
-
     /**
      * 道具奖励 构建道具信息
      *
@@ -290,11 +268,30 @@ public class MetaTaskToUserNewService {
         if (!MetaAwardTypeEnum.META_PROP.equals(metaTaskToUserNew.getMetaAtomTask().getAwardType())) {
             return MetaServiceResult.returnSuccess();
         }
-        MetaProp metaProp = metaPropRepo.findByIdAndDel(Long.parseLong(metaTaskToUserNew.getMetaAtomTask().getAwardConfig()), false);
+        MetaProp metaProp = metaPropRepo
+                .findByIdAndDel(Long.parseLong(metaTaskToUserNew.getMetaAtomTask().getAwardConfig()), false);
         if (Objects.isNull(metaProp)) {
-            return MetaServiceResult.returnError(String.format("基础任务[%S]道具奖励 道具信息为空", metaTaskToUserNew.getMetaAtomTask().getId()));
+            return MetaServiceResult
+                    .returnError(String.format("基础任务[%S]道具奖励 道具信息为空", metaTaskToUserNew.getMetaAtomTask().getId()));
         }
         metaTaskToUserNew.setMetaProp(metaProp);
         return MetaServiceResult.returnSuccess();
     }
+
+    /**
+     * 每天凌晨刷新日常任务状态为执行中
+     */
+    @Scheduled(cron = "0 0 0 * * *")
+    @Transactional
+    public void handleDailyTask() {
+        // 查询所有已经发布的日常任务
+        List<Long> ids = metaTaskNewRepo.findDailyTaskIds(MetaTaskType.DAILY);
+        if (CollectionUtil.isEmpty(ids)) {
+            log.info(String.format("当前[%S]没有日常任务需要调整状态", LocalDateTime.now()));
+            return;
+        }
+        log.info(String.format("[%S]更新日常任务[%S]状态", LocalDateTime.now(), JSONUtils.toJSONString(ids)));
+        // 每日流程将所有日常任务状态全部调整为进行中
+        metaTaskToUserNewRepo.updateStatus(MetaTaskStatus.PROGRESS, ids);
+    }
 }

+ 2 - 2
src/main/java/com/izouma/nineth/service/MetaUserPropRecordService.java

@@ -20,8 +20,8 @@ public class MetaUserPropRecordService {
         return metaUserPropRecordRepo.findAll(JpaUtils.toSpecification(pageQuery, MetaUserPropRecord.class), JpaUtils.toPageRequest(pageQuery));
     }
 
-    public MetaUserPropRecord save(Long userId, MetaProp metaProp, MetaPropOperationType operationType, int num) {
-        MetaUserPropRecord metaUserPropRecord = MetaUserPropRecord.create(userId, metaProp, operationType, num);
+    public MetaUserPropRecord save(Long userId, MetaProp metaProp, MetaPropOperationType operationType, int num, String remark) {
+        MetaUserPropRecord metaUserPropRecord = MetaUserPropRecord.create(userId, metaProp, operationType, num, remark);
         return metaUserPropRecordRepo.save(metaUserPropRecord);
     }
 }

+ 17 - 13
src/main/java/com/izouma/nineth/service/MetaUserPropService.java

@@ -14,6 +14,7 @@ import org.springframework.data.domain.Page;
 import org.springframework.stereotype.Service;
 
 import javax.transaction.Transactional;
+import java.time.LocalDateTime;
 import java.util.Objects;
 
 @Service
@@ -30,7 +31,7 @@ public class MetaUserPropService {
     }
 
     @Transactional
-    public MetaRestResult<MetaUserProp> operate(Long userId, Long metaPropId, MetaPropOperationType operationType, int num) {
+    public MetaRestResult<MetaUserProp> operate(Long userId, Long metaPropId, MetaPropOperationType operationType, int num, String remark) {
         if (Objects.isNull(metaPropId)) {
             return MetaRestResult.returnError("Illegal parameter : metaPropId can not be null");
         }
@@ -43,12 +44,12 @@ public class MetaUserPropService {
             if (num < 1) {
                 return MetaRestResult.returnError("道具数量最少为1");
             }
-            return receive(userId, dbMetaUserProp, metaProp, num);
+            return receive(userId, dbMetaUserProp, metaProp, num, remark);
         }
         if (MetaPropOperationType.CANCEL_USE.equals(operationType)) {
-            return cancelUse(dbMetaUserProp, metaProp);
+            return cancelUse(dbMetaUserProp, metaProp, remark);
         }
-        return use(dbMetaUserProp, metaProp);
+        return use(dbMetaUserProp, metaProp, remark);
     }
 
     /**
@@ -59,7 +60,7 @@ public class MetaUserPropService {
      * @return
      */
     @Transactional
-    public MetaRestResult<MetaUserProp> cancelUse(MetaUserProp metaUserProp, MetaProp metaProp) {
+    public MetaRestResult<MetaUserProp> cancelUse(MetaUserProp metaUserProp, MetaProp metaProp, String remark) {
         if (Objects.isNull(metaUserProp)) {
             return MetaRestResult.returnError("玩家未拥有该道具!");
         }
@@ -67,7 +68,8 @@ public class MetaUserPropService {
             return MetaRestResult.returnError("仅限永久道具才能取消使用!");
         }
         metaUserProp.setUsed(false);
-        metaUserPropRecordService.save(metaUserProp.getUserId(), metaProp, MetaPropOperationType.CANCEL_USE, 1);
+        int num = 1;
+        metaUserPropRecordService.save(metaUserProp.getUserId(), metaProp, MetaPropOperationType.CANCEL_USE, num, remark);
         return MetaRestResult.returnSuccess("取消使用成功", metaUserPropRepo.save(metaUserProp));
     }
 
@@ -81,7 +83,7 @@ public class MetaUserPropService {
      * @return
      */
     @Transactional
-    public MetaRestResult<MetaUserProp> receive(Long userId, MetaUserProp metaUserProp, MetaProp metaProp, int num) {
+    public MetaRestResult<MetaUserProp> receive(Long userId, MetaUserProp metaUserProp, MetaProp metaProp, int num, String remark) {
         boolean init = false;
         if (Objects.isNull(metaUserProp)) {
             metaUserProp = MetaUserProp.create(userId, metaProp, num);
@@ -101,14 +103,14 @@ public class MetaUserPropService {
             // 未拥有该道具,领取一个,多余转化为金币
             if (init) {
                 MetaUserProp save = metaUserPropRepo.save(metaUserProp);
-                metaUserPropRecordService.save(metaUserProp.getUserId(), metaProp, MetaPropOperationType.RECEIVE, 1);
+                metaUserPropRecordService.save(metaUserProp.getUserId(), metaProp, MetaPropOperationType.RECEIVE, 1, remark);
                 return MetaRestResult.returnSuccess(String.format("永久道具仅限持有一个,多余道具将转化为[%S]个金币!", goldNum), save);
             }
             // 已拥有该道具,全部转为道具后返回
             return MetaRestResult.returnSuccess(String.format("玩家已拥有该道具,所领取的道具将转化为[%S]个金币!", goldNum));
         }
         MetaUserProp save = metaUserPropRepo.save(metaUserProp);
-        metaUserPropRecordService.save(metaUserProp.getUserId(), metaProp, MetaPropOperationType.RECEIVE, num);
+        metaUserPropRecordService.save(metaUserProp.getUserId(), metaProp, MetaPropOperationType.RECEIVE, num, remark);
         return MetaRestResult.returnSuccess("道具领取成功!", save);
 
     }
@@ -121,26 +123,28 @@ public class MetaUserPropService {
      * @return
      */
     @Transactional
-    public MetaRestResult<MetaUserProp> use(MetaUserProp metaUserProp, MetaProp metaProp) {
+    public MetaRestResult<MetaUserProp> use(MetaUserProp metaUserProp, MetaProp metaProp, String remark) {
         if (Objects.isNull(metaUserProp)) {
             return MetaRestResult.returnError("玩家未拥有该道具!");
         }
+        int num = 1;
+        String msg = String.format("玩家[%S]于[%S]使用道具[%S],数量[%S]", metaUserProp.getUserId(), LocalDateTime.now(), metaProp.getId(), num);
         // 永久道具 不对背包做操作,增加一条操作记录
         if (MetaPropUsedType.PERMANENT.equals(metaProp.getUsedType())) {
             metaUserProp.setUsed(true);
-            metaUserPropRecordService.save(metaUserProp.getUserId(), metaProp, MetaPropOperationType.USE, 1);
+            metaUserPropRecordService.save(metaUserProp.getUserId(), metaProp, MetaPropOperationType.USE, num, msg);
             return MetaRestResult.returnSuccess(metaUserPropRepo.save(metaUserProp));
         }
         // 数量为1的非永久道具,成功使用后直接删除背包中该道具数据,增加一条操作记录
         if (1 == metaUserProp.getNum()) {
             metaUserProp.setNum(0);
-            metaUserPropRecordService.save(metaUserProp.getUserId(), metaProp, MetaPropOperationType.USE, 1);
+            metaUserPropRecordService.save(metaUserProp.getUserId(), metaProp, MetaPropOperationType.USE, num, msg);
             metaUserPropRepo.deleteByUserIdAndMetaPropId(metaUserProp.getUserId(), metaProp.getId());
             return MetaRestResult.returnSuccess(metaUserProp);
         }
         // 数量大于1的非永久道具,背包中该道具数量减1,增加一条操作记录
         metaUserProp.setNum(metaUserProp.getNum() - 1);
-        metaUserPropRecordService.save(metaUserProp.getUserId(), metaProp, MetaPropOperationType.USE, 1);
+        metaUserPropRecordService.save(metaUserProp.getUserId(), metaProp, MetaPropOperationType.USE, num, msg);
         return MetaRestResult.returnSuccess(metaUserPropRepo.save(metaUserProp));
     }
 

+ 19 - 9
src/main/java/com/izouma/nineth/service/MetaUserTaskAwardReceivedRecordNewService.java

@@ -1,6 +1,7 @@
 package com.izouma.nineth.service;
 
 import com.izouma.nineth.domain.MetaAtomTask;
+import com.izouma.nineth.domain.MetaTaskNew;
 import com.izouma.nineth.domain.MetaTaskToUserNew;
 import com.izouma.nineth.domain.MetaUserTaskAwardReceivedRecordNew;
 import com.izouma.nineth.dto.MetaAwardReceiveDTO;
@@ -10,6 +11,7 @@ import com.izouma.nineth.dto.PageQuery;
 import com.izouma.nineth.enums.MetaTaskStatus;
 import com.izouma.nineth.enums.MetaTaskTarget;
 import com.izouma.nineth.repo.MetaAtomTaskRepo;
+import com.izouma.nineth.repo.MetaTaskNewRepo;
 import com.izouma.nineth.repo.MetaTaskToUserNewRepo;
 import com.izouma.nineth.repo.MetaUserTaskAwardReceivedRecordNewRepo;
 import com.izouma.nineth.utils.JpaUtils;
@@ -29,6 +31,7 @@ public class MetaUserTaskAwardReceivedRecordNewService {
     private MetaUserTaskAwardReceivedRecordNewRepo metaUserTaskAwardReceivedRecordNewRepo;
     private MetaTaskToUserNewRepo                  metaTaskToUserNewRepo;
     private MetaAtomTaskRepo                       metaAtomTaskRepo;
+    private MetaTaskNewRepo                        metaTaskNewRepo;
     private MetaAwardReceiveService                metaAwardReceiveService;
 
     public Page<MetaUserTaskAwardReceivedRecordNew> all(PageQuery pageQuery) {
@@ -38,24 +41,29 @@ public class MetaUserTaskAwardReceivedRecordNewService {
     @Transactional
     public MetaRestResult<Void> receiveAward(Long taskId, Long atomTaskId) {
         Long userId = SecurityUtils.getAuthenticatedUser().getId();
+        MetaTaskNew metaTaskNew = metaTaskNewRepo.findByIdAndDel(taskId, false);
+        MetaServiceResult checkMetaTaskNewResult = MetaTaskNew.checkMetaTaskNew(metaTaskNew);
+        if (!checkMetaTaskNewResult.isSuccess()) {
+            return MetaRestResult.returnError(checkMetaTaskNewResult.getMessage());
+        }
         MetaAtomTask metaAtomTask = metaAtomTaskRepo.findByIdAndDel(atomTaskId, false);
-        if (Objects.isNull(metaAtomTask)) {
-            return MetaRestResult.returnError("奖励领取失败:基础任务不存在!");
+        MetaServiceResult checkMetaAtomTaskResult = MetaAtomTask.checkMetaAtomTask(metaAtomTask);
+        if (!checkMetaAtomTaskResult.isSuccess()) {
+            return MetaRestResult.returnError(checkMetaAtomTaskResult.getMessage());
         }
-        MetaTaskToUserNew metaTaskToUserNew = metaTaskToUserNewRepo.findByUserIdAndTaskIdAndAtomTaskIdAndDel(userId, taskId, atomTaskId, false);
+        MetaTaskToUserNew metaTaskToUserNew = metaTaskToUserNewRepo.findByUserIdAndTaskIdAndAtomTaskIdAndChannelIdAndDel(userId, taskId, atomTaskId, metaTaskNew.getChannelId(), false);
         if (Objects.isNull(metaTaskToUserNew)) {
-            return MetaRestResult.returnError("奖励领取失败:用户未领取过该任务!");
+            return MetaRestResult.returnError(String.format("奖励领取失败:用户[%S]在频道[%S]下未领取过该任务!", userId, metaTaskNew.getChannelId()));
+        }
+        if (MetaTaskStatus.PROGRESS.equals(metaTaskToUserNew.getStatus()) || MetaTaskStatus.FINISH.equals(metaTaskToUserNew.getStatus())) {
+            return MetaRestResult.returnError(String.format("奖励领取失败:当前任务状态为[%S]", metaTaskToUserNew.getStatus().getDescription()));
         }
         if (MetaTaskTarget.ON_LINE_TIME_DAILY.equals(metaAtomTask.getTargetType())) {
             MetaUserTaskAwardReceivedRecordNew metaUserTaskAwardReceivedRecordNew = metaUserTaskAwardReceivedRecordNewRepo.findByUserIdAndTaskIdAndAtomTaskIdAndDelAndReceivedTimeAfter(userId, taskId, atomTaskId, false, LocalDateTime.now().withHour(0).withMinute(0).withSecond(0));
             if (Objects.nonNull(metaUserTaskAwardReceivedRecordNew)) {
                 return MetaRestResult.returnError("奖励领取失败:用户今天已经领取过该任务奖励,不可重复领取!");
             }
-        }
-        if (!MetaTaskTarget.ON_LINE_TIME_DAILY.equals(metaAtomTask.getTargetType())) {
-            if (MetaTaskStatus.PROGRESS.equals(metaTaskToUserNew.getStatus()) || MetaTaskStatus.FINISH.equals(metaTaskToUserNew.getStatus())) {
-                return MetaRestResult.returnError(String.format("奖励领取失败:当前任务状态为[%S]", metaTaskToUserNew.getStatus().getDescription()));
-            }
+        } else {
             MetaUserTaskAwardReceivedRecordNew metaUserTaskAwardReceivedRecordNew = metaUserTaskAwardReceivedRecordNewRepo.findByUserIdAndTaskIdAndAtomTaskIdAndDel(userId, taskId, atomTaskId, false);
             if (Objects.nonNull(metaUserTaskAwardReceivedRecordNew)) {
                 return MetaRestResult.returnError("奖励领取失败:用户已经领取过该任务奖励,不可重复领取!");
@@ -66,6 +74,8 @@ public class MetaUserTaskAwardReceivedRecordNewService {
             return MetaRestResult.returnError(receive.getMessage());
         }
         metaUserTaskAwardReceivedRecordNewRepo.save(new MetaUserTaskAwardReceivedRecordNew(userId, taskId, atomTaskId, LocalDateTime.now()));
+        metaTaskToUserNew.setStatus(MetaTaskStatus.FINISH);
+        metaTaskToUserNewRepo.save(metaTaskToUserNew);
         return MetaRestResult.returnSuccess(receive.getMessage());
     }
 }

+ 26 - 13
src/main/java/com/izouma/nineth/service/MetaUserTaskProgressNewService.java

@@ -33,6 +33,7 @@ public class MetaUserTaskProgressNewService {
     private MetaAtomTaskRepo            metaAtomTaskRepo;
     private MetaTaskToUserNewService    metaTaskToUserNewService;
     private MetaTaskBindRepo            metaTaskBindRepo;
+    private MetaTaskNewRepo             metaTaskNewRepo;
 
     public Page<MetaUserTaskProgressNew> all(PageQuery pageQuery) {
         return metaUserTaskProgressNewRepo.findAll(JpaUtils.toSpecification(pageQuery, MetaUserTaskProgressNew.class), JpaUtils.toPageRequest(pageQuery));
@@ -40,12 +41,12 @@ public class MetaUserTaskProgressNewService {
 
     @Transactional
     public MetaRestResult<Boolean> metaSave(MetaUserTaskProgressNew metaUserTaskProgressNew) {
-        // 校验参数
+        // 校验进度模型参数
         MetaServiceResult result = checkParams(metaUserTaskProgressNew);
         if (!result.isSuccess()) {
             return MetaRestResult.returnError(result.getMessage());
         }
-        // 任务领取记录
+        // 校验任务领取记录
         MetaTaskToUserNew metaTaskToUserNew = metaTaskToUserNewRepo.findByIdAndDel(metaUserTaskProgressNew.getMetaTaskToUserNewId(), false);
         if (Objects.isNull(metaTaskToUserNew)) {
             return MetaRestResult.returnError("无用户领取任务记录");
@@ -53,7 +54,13 @@ public class MetaUserTaskProgressNewService {
         if (!metaTaskToUserNew.getStatus().equals(MetaTaskStatus.PROGRESS)) {
             return MetaRestResult.returnError(String.format("状态错误:当前任务状态为[%S]", metaTaskToUserNew.getStatus().getDescription()));
         }
-        // 基础任务
+        // 校验任务
+        MetaTaskNew metaTaskNew = metaTaskNewRepo.findByIdAndDel(metaTaskToUserNew.getTaskId(), false);
+        MetaServiceResult checkMetaTaskNewResult = MetaTaskNew.checkMetaTaskNew(metaTaskNew);
+        if (!checkMetaTaskNewResult.isSuccess()) {
+            return MetaRestResult.returnError(checkMetaTaskNewResult.getMessage());
+        }
+        // 校验基础任务
         MetaAtomTask metaAtomTask = metaAtomTaskRepo.findByIdAndDel(metaTaskToUserNew.getAtomTaskId(), false);
         if (Objects.isNull(metaAtomTask)) {
             return MetaRestResult.returnError("基础任务信息为空");
@@ -91,17 +98,16 @@ public class MetaUserTaskProgressNewService {
             MetaUserTaskProgressNew dbMetaUserTaskProgressNew = metaUserTaskProgressNewRepo.findByMetaTaskToUserNewIdAndDelAndCreatedAtAfter(metaUserTaskProgressNew.getMetaTaskToUserNewId(), false, LocalDateTime.now().withHour(0).withMinute(0).withSecond(0));
             if (Objects.isNull(dbMetaUserTaskProgressNew)) {
                 metaUserTaskProgressNewRepo.save(metaUserTaskProgressNew);
-                // 该类型任务不存在完成
-                return MetaRestResult.returnSuccess(Integer.parseInt(metaUserTaskProgressNew.getRemark()) >= Integer.parseInt(value));
+            } else {
+                int remark = Integer.parseInt(metaUserTaskProgressNew.getRemark()) + Integer.parseInt(dbMetaUserTaskProgressNew.getRemark());
+                dbMetaUserTaskProgressNew.setRemark(String.valueOf(remark));
+                dbMetaUserTaskProgressNew.setProgressTime(LocalDateTime.now());
+                metaUserTaskProgressNewRepo.save(dbMetaUserTaskProgressNew);
             }
-            int remark = Integer.parseInt(metaUserTaskProgressNew.getRemark()) + Integer.parseInt(dbMetaUserTaskProgressNew.getRemark());
-            dbMetaUserTaskProgressNew.setRemark(String.valueOf(remark));
-            dbMetaUserTaskProgressNew.setProgressTime(LocalDateTime.now());
-            metaUserTaskProgressNewRepo.save(dbMetaUserTaskProgressNew);
-            return MetaRestResult.returnSuccess(Integer.parseInt(metaUserTaskProgressNew.getRemark()) >= Integer.parseInt(value));
-        }
-        // 保存进度
-        metaUserTaskProgressNewRepo.save(metaUserTaskProgressNew);
+        } else {
+            // 保存进度
+            metaUserTaskProgressNewRepo.save(metaUserTaskProgressNew);
+        }
         List<MetaUserTaskProgressNew> metaUserTaskProgressNews = metaUserTaskProgressNewRepo.findAllByMetaTaskToUserNewIdAndDel(metaUserTaskProgressNew.getMetaTaskToUserNewId(), false);
         // 是否完成任务
         switch (metaAtomTask.getTargetType()) {
@@ -120,6 +126,13 @@ public class MetaUserTaskProgressNewService {
                     return MetaRestResult.returnSuccess(true);
                 }
                 return MetaRestResult.returnSuccess(false);
+            case ON_LINE_TIME_DAILY:
+                MetaUserTaskProgressNew dbMetaUserTaskProgressNew = metaUserTaskProgressNewRepo.findByMetaTaskToUserNewIdAndDelAndCreatedAtAfter(metaUserTaskProgressNew.getMetaTaskToUserNewId(), false, LocalDateTime.now().withHour(0).withMinute(0).withSecond(0));
+                if (Integer.parseInt(dbMetaUserTaskProgressNew.getRemark()) >= Integer.parseInt(value)) {
+                    completeTask(metaTaskToUserNew);
+                    return MetaRestResult.returnSuccess(true);
+                }
+                return MetaRestResult.returnSuccess(false);
             default:
                 throw new BusinessException(String.format("不存在的任务类型[%S]", metaAtomTask.getTargetType()));
         }

+ 14 - 7
src/main/java/com/izouma/nineth/service/UserService.java

@@ -141,21 +141,28 @@ public class UserService {
         return userRepo.save(user);
     }
 
-    public User metaUpdate(Long userId, String nickname) {
-        if (StringUtils.isBlank(nickname)) {
-            throw new BusinessException("用户昵称为空");
+    public MetaRestResult<User> metaUpdate(User record) {
+        if (Objects.isNull(record)) {
+            return MetaRestResult.returnError("Illegal parameter : params can not be null");
         }
-        User user = userRepo.findById(userId).orElse(null);
+        if (Objects.isNull(record.getId())) {
+            return MetaRestResult.returnError("Illegal parameter : userId can not be null");
+        }
+        if (StringUtils.isBlank(record.getNickname())) {
+            return MetaRestResult.returnError("Illegal parameter : nickname can not be null");
+        }
+        String nickname = record.getNickname();
+        User user = userRepo.findById(record.getId()).orElse(null);
         if (Objects.isNull(user)) {
-            throw new BusinessException("用户信息为空");
+            return MetaRestResult.returnError("用户信息为空");
         }
         if (!nickname.equals(user.getNickname())) {
             if (!contentAuditService.auditText(nickname)) {
-                throw new BusinessException("昵称包含非法内容");
+                return MetaRestResult.returnError("昵称包含非法内容");
             }
         }
         user.setNickname(nickname);
-        return save(user);
+        return MetaRestResult.returnSuccess(save(user));
     }
 
     public User update(Long userId, String nickname, String avatar, String sex, String bg, String intro,

+ 48 - 0
src/main/java/com/izouma/nineth/utils/OSSClientUtil.java

@@ -0,0 +1,48 @@
+package com.izouma.nineth.utils;
+
+import com.aliyun.oss.OSSClient;
+import com.aliyun.oss.model.OSSObject;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.type.TypeFactory;
+import com.izouma.nineth.config.AliyunProperties;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.List;
+
+
+public class OSSClientUtil {
+
+    /**
+     * 通过阿里云OSSClient客户端读取指定objectKey的文件流,利用Jackson将文件流反序列化成List<T>类型的数据模型并返回。
+     *
+     * @param properties 用于配置阿里云OSS客户端的属性对象。
+     * @param objectKey  阿里云OSS存储桶中的文件对象的唯一标识符。
+     * @param clazz      要反序列化的目标类型。
+     * @return 返回反序列化后的List<T>类型数据模型。
+     * @throws IOException 当出现IO异常时,抛出IOException。
+     */
+    public static <T> List<T> getDataModel(AliyunProperties properties, String objectKey, Class<T> clazz) throws IOException {
+        // 从阿里云OSS客户端配置对象中获取必要的参数
+        String endpoint = properties.getOssEndPoint();
+        String accessKeyId = properties.getAccessKeyId();
+        String accessKeySecret = properties.getAccessKeySecret();
+        String bucketName = properties.getOssBucketName();
+        // 创建OSS客户端
+        OSSClient client = new OSSClient(endpoint, accessKeyId, accessKeySecret);
+        List<T> list;
+        // 获取指定文件对象的OSSObject对象
+        OSSObject ossObject = client.getObject(bucketName, objectKey);
+        // 创建Jackson的ObjectMapper对象用于反序列化操作
+        ObjectMapper objectMapper = new ObjectMapper();
+        // 将OSSObject对象中的文件流反序列化成List<T>类型的数据模型
+        try (InputStream inputStream = ossObject.getObjectContent()) {
+            list = objectMapper.readValue(inputStream, TypeFactory.defaultInstance().constructCollectionType(List.class, clazz));
+        } finally {
+            // 关闭OSS客户端
+            client.shutdown();
+        }
+        return list;
+    }
+
+}

+ 48 - 0
src/main/java/com/izouma/nineth/web/MetaAwardDropController.java

@@ -0,0 +1,48 @@
+package com.izouma.nineth.web;
+
+import com.izouma.nineth.domain.MetaAwardDrop;
+import com.izouma.nineth.dto.PageQuery;
+import com.izouma.nineth.exception.BusinessException;
+import com.izouma.nineth.repo.MetaAwardDropRepo;
+import com.izouma.nineth.service.MetaAwardDropService;
+import com.izouma.nineth.utils.excel.ExcelUtils;
+import lombok.AllArgsConstructor;
+import org.springframework.data.domain.Page;
+import org.springframework.web.bind.annotation.*;
+
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.util.List;
+
+@RestController
+@RequestMapping("/metaAwardDrop")
+@AllArgsConstructor
+public class MetaAwardDropController extends BaseController {
+    private MetaAwardDropService metaAwardDropService;
+    private MetaAwardDropRepo    metaAwardDropRepo;
+
+    //@PreAuthorize("hasRole('ADMIN')")
+    @PostMapping("/save")
+    public MetaAwardDrop save(@RequestBody MetaAwardDrop record) {
+        return metaAwardDropService.save(record);
+    }
+
+    //@PreAuthorize("hasRole('ADMIN')")
+    @PostMapping("/all")
+    public Page<MetaAwardDrop> all(@RequestBody PageQuery pageQuery) {
+        return metaAwardDropService.all(pageQuery);
+    }
+
+    @GetMapping("/get/{id}")
+    public MetaAwardDrop get(@PathVariable Long id) {
+        return metaAwardDropRepo.findById(id).orElseThrow(new BusinessException("无记录"));
+    }
+
+    @GetMapping("/excel")
+    @ResponseBody
+    public void excel(HttpServletResponse response, PageQuery pageQuery) throws IOException {
+        List<MetaAwardDrop> data = all(pageQuery).getContent();
+        ExcelUtils.export(response, data);
+    }
+}
+

+ 11 - 57
src/main/java/com/izouma/nineth/web/MetaObjectMoveController.java

@@ -1,47 +1,38 @@
 package com.izouma.nineth.web;
 
-import com.izouma.nineth.config.MetaConstants;
 import com.izouma.nineth.domain.MetaObjectMove;
 import com.izouma.nineth.domain.MetaObjectMoveCoordinate;
 import com.izouma.nineth.dto.PageQuery;
 import com.izouma.nineth.exception.BusinessException;
-import com.izouma.nineth.repo.MetaObjectMoveCoordinateRepo;
 import com.izouma.nineth.repo.MetaObjectMoveRepo;
 import com.izouma.nineth.service.MetaObjectMoveService;
-import com.izouma.nineth.utils.ObjUtils;
 import com.izouma.nineth.utils.excel.ExcelUtils;
 import lombok.AllArgsConstructor;
 import org.springframework.data.domain.Page;
-import org.springframework.data.redis.core.RedisTemplate;
 import org.springframework.web.bind.annotation.*;
 
 import javax.servlet.http.HttpServletResponse;
 import java.io.IOException;
-import java.time.ZoneOffset;
 import java.util.List;
-import java.util.Objects;
-import java.util.concurrent.atomic.AtomicLong;
 
 @RestController
 @RequestMapping("/metaObjectMove")
 @AllArgsConstructor
 public class MetaObjectMoveController extends BaseController {
-    private MetaObjectMoveService         metaObjectMoveService;
-    private MetaObjectMoveRepo            metaObjectMoveRepo;
-    private MetaObjectMoveCoordinateRepo  metaObjectMoveCoordinateRepo;
-    private RedisTemplate<String, Object> redisTemplate;
+    private MetaObjectMoveService metaObjectMoveService;
+    private MetaObjectMoveRepo    metaObjectMoveRepo;
 
     //@PreAuthorize("hasRole('ADMIN')")
     @PostMapping("/save")
     public MetaObjectMove save(@RequestBody MetaObjectMove record) {
-        if (record.getId() != null) {
-            MetaObjectMove orig = metaObjectMoveRepo.findById(record.getId()).orElseThrow(new BusinessException("无记录"));
-            ObjUtils.merge(orig, record);
-            return metaObjectMoveRepo.save(orig);
-        }
-        return metaObjectMoveRepo.save(record);
+        return metaObjectMoveService.save(record);
+
     }
 
+    @PostMapping("/{id}/handleCoordinate")
+    public void handleCoordinate(@PathVariable Long id) {
+        metaObjectMoveService.handleCoordinate(id);
+    }
 
     //@PreAuthorize("hasRole('ADMIN')")
     @PostMapping("/all")
@@ -66,46 +57,9 @@ public class MetaObjectMoveController extends BaseController {
         ExcelUtils.export(response, data);
     }
 
-    @GetMapping("/test")
-    public MetaObjectMoveCoordinate test(Long objectId) {
-        // 查询缓存-物体移动配置
-        String objectMoveKey = MetaConstants.META_OBJECT_MOVE_REDIS_KEY.concat(String.valueOf(objectId));
-        MetaObjectMove metaObjectMove = (MetaObjectMove) redisTemplate.opsForValue().get(objectMoveKey);
-        // 缓存不存在 查询数据库
-        if (Objects.isNull(metaObjectMove)) {
-            metaObjectMove = metaObjectMoveRepo.findByObjectIdAndDel(objectId, false);
-            if (Objects.isNull(metaObjectMove)) {
-                throw new BusinessException("物体配置不存在!");
-            }
-            AtomicLong totalTime = new AtomicLong();
-            metaObjectMove.getMetaObjectMoveCoordinateDTOS().forEach(metaObjectMoveCoordinateDTO -> {
-                totalTime.set(totalTime.get() + metaObjectMoveCoordinateDTO.getTime());
-            });
-            metaObjectMove.setTotalTime(totalTime.get());
-            // 重新缓存-物体移动配置
-            redisTemplate.delete(objectMoveKey);
-            redisTemplate.opsForValue().set(objectMoveKey, metaObjectMove);
-        }
-        long startTime = metaObjectMove.getStartTime().toInstant(ZoneOffset.of("+8")).toEpochMilli();
-        long now = System.currentTimeMillis();
-        long index = (now - startTime) % (metaObjectMove.getTotalTime() * 2L);
-        if (index > metaObjectMove.getTotalTime()) {
-            index = metaObjectMove.getTotalTime() * 2L - index;
-        }
-        // 查询缓存坐标信息
-        String coordinateKey = MetaConstants.META_OBJECT_INDEX_REDIS_KEY.concat(String.valueOf(objectId)).concat("_").concat(String.valueOf(index));
-        MetaObjectMoveCoordinate metaObjectMoveCoordinate = (MetaObjectMoveCoordinate) redisTemplate.opsForValue().get(coordinateKey);
-        if (Objects.isNull(metaObjectMoveCoordinate)) {
-            // 查询数据库坐标信息
-            metaObjectMoveCoordinate = metaObjectMoveCoordinateRepo.findByObjectIdAndCoordinateIndexAndDel(objectId, index, false);
-            if (Objects.isNull(metaObjectMoveCoordinate)) {
-                throw new BusinessException("坐标信息为空");
-            }
-            // 重新缓存坐标信息
-            redisTemplate.delete(coordinateKey);
-            redisTemplate.opsForValue().set(coordinateKey, metaObjectMoveCoordinate);
-        }
-        return metaObjectMoveCoordinate;
+    @GetMapping("/{objectId}/queryCoordinate")
+    public MetaObjectMoveCoordinate queryCoordinate(@PathVariable Long objectId) {
+        return metaObjectMoveService.queryCoordinate(objectId);
     }
 }
 

+ 6 - 4
src/main/java/com/izouma/nineth/web/MetaTaskToUserNewController.java

@@ -6,6 +6,7 @@ import com.izouma.nineth.dto.PageQuery;
 import com.izouma.nineth.enums.MetaTaskStatus;
 import com.izouma.nineth.repo.MetaTaskToUserNewRepo;
 import com.izouma.nineth.service.MetaTaskToUserNewService;
+import com.izouma.nineth.utils.SecurityUtils;
 import com.izouma.nineth.utils.excel.ExcelUtils;
 import lombok.AllArgsConstructor;
 import org.springframework.data.domain.Page;
@@ -39,11 +40,12 @@ public class MetaTaskToUserNewController {
         return metaTaskToUserNewService.receiveTask(metaTaskToUserNew, true);
     }
 
-    @GetMapping("/{id}/findProgress")
-    public MetaRestResult<MetaTaskToUserNew> findProgress(@PathVariable Long id) {
-        MetaTaskToUserNew metaTaskToUserNew = metaTaskToUserNewRepo.findByIdAndDel(id, false);
+    @GetMapping("/{taskId}/{atomTaskId}/{channelId}/findProgress")
+    public MetaRestResult<MetaTaskToUserNew> findProgress(@PathVariable Long taskId, @PathVariable Long atomTaskId, @PathVariable Long channelId) {
+        Long userId = SecurityUtils.getAuthenticatedUser().getId();
+        MetaTaskToUserNew metaTaskToUserNew = metaTaskToUserNewRepo.findByUserIdAndTaskIdAndAtomTaskIdAndChannelIdAndDel(userId, taskId, atomTaskId, channelId, false);
         if (Objects.isNull(metaTaskToUserNew)) {
-            return MetaRestResult.returnError(String.format("根据id[%S]查询不到用户领取记录", id));
+            return MetaRestResult.returnError(String.format("根据任务id[%S]+基础任务id[%S]查询不到用户[%S]在频道[%S]下的领取记录", taskId, atomTaskId, userId, channelId));
         }
         return metaTaskToUserNewService.setSingleProgress(metaTaskToUserNew);
     }

+ 12 - 3
src/main/java/com/izouma/nineth/web/MetaUserPropController.java

@@ -15,6 +15,7 @@ import org.springframework.web.bind.annotation.*;
 
 import javax.servlet.http.HttpServletResponse;
 import java.io.IOException;
+import java.time.LocalDateTime;
 import java.util.List;
 import java.util.Objects;
 
@@ -27,17 +28,25 @@ public class MetaUserPropController extends BaseController {
 
     @PostMapping("/receive")
     public MetaRestResult<MetaUserProp> receive(Long metaPropId, int num) {
-        return metaUserPropService.operate(SecurityUtils.getAuthenticatedUser().getId(), metaPropId, MetaPropOperationType.RECEIVE, num);
+        Long userId = SecurityUtils.getAuthenticatedUser().getId();
+        String remark = String.format("玩家[%S]于[%S]通过协议/metaUserProp/receive获得[%S]个道具", userId, LocalDateTime.now(), num);
+        return metaUserPropService.operate(userId, metaPropId, MetaPropOperationType.RECEIVE, num, remark);
     }
 
     @PostMapping("/cancelUser")
     public MetaRestResult<MetaUserProp> cancelUser(Long metaPropId) {
-        return metaUserPropService.operate(SecurityUtils.getAuthenticatedUser().getId(), metaPropId, MetaPropOperationType.CANCEL_USE, 1);
+        int num = 1;
+        Long userId = SecurityUtils.getAuthenticatedUser().getId();
+        String remark = String.format("玩家[%S]于[%S]通过协议/metaUserProp/cancelUser取消使用道具[%S],数量[%S]", userId, LocalDateTime.now(), metaPropId, num);
+        return metaUserPropService.operate(userId, metaPropId, MetaPropOperationType.CANCEL_USE, num, remark);
     }
 
     @PostMapping("/use")
     public MetaRestResult<MetaUserProp> use(Long metaPropId) {
-        return metaUserPropService.operate(SecurityUtils.getAuthenticatedUser().getId(), metaPropId, MetaPropOperationType.USE, 1);
+        int num = 1;
+        Long userId = SecurityUtils.getAuthenticatedUser().getId();
+        String remark = String.format("玩家[%S]于[%S]通过协议/metaUserProp/use使用道具[%S],数量[%S]", userId, LocalDateTime.now(), metaPropId, num);
+        return metaUserPropService.operate(userId, metaPropId, MetaPropOperationType.USE, num, remark);
     }
 
     //@PreAuthorize("hasRole('ADMIN')")

+ 4 - 3
src/main/java/com/izouma/nineth/web/UserAssetSummaryController.java

@@ -19,9 +19,10 @@ public class UserAssetSummaryController extends BaseController {
     @PostMapping("/all")
     public Page<UserAssetSummary> all(@RequestBody PageQuery pageQuery) {
         pageQuery.getQuery().putIfAbsent("companyId", 1L);
-        if (pageQuery.isRefresh()) {
-            userAssetSummaryService.calculateNum(null, SecurityUtils.getAuthenticatedUser().getId(), (Long) pageQuery.getQuery().get("companyId"));
-        }
+//        if (pageQuery.isRefresh()) {
+        userAssetSummaryService
+                .calculateNum(null, SecurityUtils.getAuthenticatedUser().getId(), 1L);
+//        }
         return userAssetSummaryService.all(pageQuery);
     }
 

+ 15 - 13
src/main/java/com/izouma/nineth/web/UserController.java

@@ -48,22 +48,19 @@ public class UserController extends BaseController {
     private UserBankCardRepo              userBankCardRepo;
     private RedisTemplate<String, Object> redisTemplate;
     private IdentityAuthRepo              identityAuthRepo;
-
-    private TokenHistoryRepo tokenHistoryRepo;
-
-    private FollowRepo followRepo;
-
-    private CompanyRepo companyRepo;
+    private TokenHistoryRepo              tokenHistoryRepo;
+    private FollowRepo                    followRepo;
+    private CompanyRepo                   companyRepo;
 
     @PostMapping("/register")
     public User register(@RequestParam String username,
                          @RequestParam String password) {
         UserRegister user = UserRegister.builder()
-                .username(username)
-                .nickname(username)
-                .password(password)
-                .authorities(Collections.singleton(Authority.get(AuthorityName.ROLE_USER)))
-                .build();
+                                        .username(username)
+                                        .nickname(username)
+                                        .password(password)
+                                        .authorities(Collections.singleton(Authority.get(AuthorityName.ROLE_USER)))
+                                        .build();
         return userService.create(user);
     }
 
@@ -89,6 +86,11 @@ public class UserController extends BaseController {
                 nickname, avatar, sex, bg, intro, useCollectionPic, riskWarning, level, isPublicShow);
     }
 
+    @PostMapping("/metaUpdate")
+    public MetaRestResult<User> metaUpdate(@RequestBody User user) {
+        return userService.metaUpdate(user);
+    }
+
     @GetMapping("/my")
     public User my(@RequestParam(defaultValue = "false") boolean refresh) {
         if (refresh) {
@@ -108,7 +110,7 @@ public class UserController extends BaseController {
     @PreAuthorize("hasRole('ADMIN')")
     public User myAdmin() {
         return userRepo.findById(SecurityUtils.getAuthenticatedUser().getId())
-                .orElseThrow(new BusinessException("用户不存在"));
+                       .orElseThrow(new BusinessException("用户不存在"));
     }
 
     @GetMapping("/myTrading")
@@ -204,7 +206,7 @@ public class UserController extends BaseController {
     @GetMapping("/getToken/{userId}")
     public String getToken(@PathVariable Long userId) {
         return jwtTokenUtil.generateToken(JwtUserFactory.create(userRepo.findById(userId)
-                .orElseThrow(new BusinessException("用户不存在"))));
+                                                                        .orElseThrow(new BusinessException("用户不存在"))));
     }
 
     @PostMapping("/bindPhone")

+ 1 - 0
src/main/resources/genjson/MetaAwardDrop.json

@@ -0,0 +1 @@
+{"tableName":"MetaAwardDrop","className":"MetaAwardDrop","remark":"元宇宙奖励空投","genTable":true,"genClass":true,"genList":true,"genForm":true,"genRouter":true,"javaPath":"/Users/xiaohuoban/IdeaProjects/raex_back/src/main/java/com/izouma/nineth","viewPath":"/Users/xiaohuoban/IdeaProjects/raex_back/src/main/vue/src/views","routerPath":"/Users/xiaohuoban/IdeaProjects/raex_back/src/main/vue/src","resourcesPath":"/Users/xiaohuoban/IdeaProjects/raex_back/src/main/resources","dataBaseType":"Mysql","fields":[{"name":"awardType","modelName":"awardType","remark":"奖励类型","showInList":true,"showInForm":true,"formType":"select","apiFlag":"1","optionsValue":"[{\"label\":\"空\",\"value\":\"NULL\"},{\"label\":\"NFT\",\"value\":\"NFT\"},{\"label\":\"金币\",\"value\":\"GOLD\"},{\"label\":\"元宇宙道具\",\"value\":\"META_PROP\"}]"},{"name":"remark","modelName":"remark","remark":"备注说明","showInList":true,"showInForm":true,"formType":"textarea"},{"name":"fileUrl","modelName":"fileUrl","remark":"文件上传","showInList":true,"showInForm":true,"formType":"singleLineText"}],"readTable":false,"dataSourceCode":"dataSource","genJson":"","subtables":[],"update":false,"basePackage":"com.izouma.nineth","tablePackage":"com.izouma.nineth.domain.MetaAwardDrop"}

+ 16 - 0
src/main/vue/src/router.js

@@ -2077,6 +2077,22 @@ const router = new Router({
                     meta: {
                        title: '物体移动配置',
                     },
+               },
+                {
+                    path: '/metaAwardDropEdit',
+                    name: 'MetaAwardDropEdit',
+                    component: () => import(/* webpackChunkName: "metaAwardDropEdit" */ '@/views/MetaAwardDropEdit.vue'),
+                    meta: {
+                       title: '元宇宙奖励空投编辑',
+                    },
+                },
+                {
+                    path: '/metaAwardDropList',
+                    name: 'MetaAwardDropList',
+                    component: () => import(/* webpackChunkName: "metaAwardDropList" */ '@/views/MetaAwardDropList.vue'),
+                    meta: {
+                       title: '元宇宙奖励空投',
+                    },
                }
                 /**INSERT_LOCATION**/
             ]

+ 148 - 0
src/main/vue/src/views/MetaAwardDropEdit.vue

@@ -0,0 +1,148 @@
+<template>
+    <div class="edit-view">
+        <page-title>
+            <el-button @click="$router.go(-1)" :disabled="saving">取消</el-button>
+            <template v-if="canEdit">
+                <el-button @click="onSave" :loading="saving" type="primary">
+                    保存
+                </el-button>
+            </template>
+        </page-title>
+        <div class="edit-view__content-wrapper">
+            <div class="edit-view__content-section">
+                <el-form :model="formData" :rules="rules" ref="form" label-width="80px" label-position="right" size="small"
+                    style="max-width: 500px;">
+                    <el-form-item prop="awardType" label="奖励类型">
+                        <el-select v-model="formData.awardType" clearable filterable placeholder="请选择" :disabled="!canEdit">
+                            <el-option v-for="item in awardTypeOptions" :key="item.value" :label="item.label"
+                                :value="item.value">
+                            </el-option>
+                        </el-select>
+                    </el-form-item>
+                    <el-form-item prop="remark" label="备注说明">
+                        <el-input type="textarea" v-model="formData.remark" :disabled="!canEdit"></el-input>
+                    </el-form-item>
+                    <el-form-item prop="fileUrl" label="文件上传" v-if="formData && formData.awardType === 'GOLD'">
+                        <file-upload v-model="formData.fileUrl" :limit="1"></file-upload>
+                        <div class="tip">金币奖励附件模板为:</div>
+                        <img width="50%" src="http://cdn.raex.vip/meta/gold.png" alt />
+                    </el-form-item>
+                    <el-form-item prop="fileUrl" label="文件上传" v-if="formData && formData.awardType === 'META_PROP'">
+                        <file-upload v-model="formData.fileUrl" :limit="1"></file-upload>
+                        <div class="tip">道具奖励附件模板为:</div>
+                        <img width="50%" src="http://cdn.raex.vip/meta/prop.png" alt />
+                    </el-form-item>
+                    <el-form-item class="form-submit">
+                        <template v-if="canEdit">
+                            <el-button @click="onSave" :loading="saving" type="primary">
+                                保存
+                            </el-button>
+                        </template>
+                        <el-button @click="$router.go(-1)" :disabled="saving">取消</el-button>
+                    </el-form-item>
+                </el-form>
+            </div>
+        </div>
+    </div>
+</template>
+<script>
+export default {
+	name: 'MetaAwardDropEdit',
+	created() {
+		if (this.$route.query.id) {
+			this.$http
+				.get('metaAwardDrop/get/' + this.$route.query.id)
+				.then(res => {
+					this.formData = res;
+				})
+				.catch(e => {
+					console.log(e);
+					this.$message.error(e.error);
+				});
+		}
+	},
+	computed: {
+		canEdit() {
+			return !!!this.$route.query.id;
+		}
+	},
+	data() {
+		return {
+			saving: false,
+			formData: {},
+			rules: {
+				awardType: [
+					{
+						required: true,
+						message: '请选择奖励类型',
+						trigger: 'blur'
+					}
+				],
+				remark: [
+					{
+						required: true,
+						message: '请输入备注',
+						trigger: 'blur'
+					}
+				],
+				fileUrl: [
+					{
+						required: true,
+						message: '请上传附件',
+						trigger: 'blur'
+					}
+				]
+			},
+			awardTypeOptions: [
+				{ label: '金币', value: 'GOLD' },
+				{ label: '道具', value: 'META_PROP' }
+			]
+		};
+	},
+	methods: {
+		onSave() {
+			this.$refs.form.validate(valid => {
+				if (valid) {
+					this.submit();
+				} else {
+					return false;
+				}
+			});
+		},
+		submit() {
+			let data = { ...this.formData };
+
+			this.saving = true;
+			this.$http
+				.post('/metaAwardDrop/save', data, { body: 'json' })
+				.then(res => {
+					this.saving = false;
+					this.$message.success('成功');
+					this.$router.go(-1);
+				})
+				.catch(e => {
+					console.log(e);
+					this.saving = false;
+					this.$message.error(e.error);
+				});
+		},
+		onDelete() {
+			this.$confirm('删除将无法恢复,确认要删除么?', '警告', { type: 'error' })
+				.then(() => {
+					return this.$http.post(`/metaAwardDrop/del/${this.formData.id}`);
+				})
+				.then(() => {
+					this.$message.success('删除成功');
+					this.$router.go(-1);
+				})
+				.catch(e => {
+					if (e !== 'cancel') {
+						console.log(e);
+						this.$message.error((e || {}).error || '删除失败');
+					}
+				});
+		}
+	}
+};
+</script>
+<style lang="less" scoped></style>

+ 133 - 0
src/main/vue/src/views/MetaAwardDropList.vue

@@ -0,0 +1,133 @@
+<template>
+    <div class="list-view">
+        <page-title>
+            <el-button @click="addRow" type="primary" icon="el-icon-plus" :disabled="fetchingData || downloading"
+                class="filter-item">
+                新增
+            </el-button>
+            <el-button @click="download" icon="el-icon-upload2" :loading="downloading" :disabled="fetchingData"
+                class="filter-item">
+                导出
+            </el-button>
+        </page-title>
+        <div class="filters-container">
+            <el-input placeholder="搜索..." v-model="search" clearable class="filter-item search"
+                @keyup.enter.native="getData">
+                <el-button @click="getData" slot="append" icon="el-icon-search"> </el-button>
+            </el-input>
+        </div>
+        <el-table :data="tableData" row-key="id" ref="table" header-row-class-name="table-header-row"
+            header-cell-class-name="table-header-cell" row-class-name="table-row" cell-class-name="table-cell"
+            :height="tableHeight" v-loading="fetchingData">
+            <el-table-column v-if="multipleMode" align="center" type="selection" width="50">
+            </el-table-column>
+            <el-table-column prop="operator" align="center" label="操作人">
+            </el-table-column>
+            <el-table-column prop="operatingTime" align="center" label="空投时间">
+            </el-table-column>
+            <el-table-column prop="awardType" align="center" label="奖励类型" :formatter="awardTypeFormatter">
+            </el-table-column>
+            <el-table-column prop="remark" align="center" label="备注说明" show-overflow-tooltip>
+            </el-table-column>
+            <el-table-column prop="fileUrl" align="center" label="附件地址" show-overflow-tooltip>
+            </el-table-column>
+            <el-table-column label="操作" align="center" fixed="right" width="150">
+                <template slot-scope="{row}">
+                    <el-button @click="editRow(row)" type="primary" size="mini" plain>查看</el-button>
+                </template>
+            </el-table-column>
+        </el-table>
+        <div class="pagination-wrapper">
+            <el-pagination background @size-change="onSizeChange" @current-change="onCurrentChange" :current-page="page"
+                :page-sizes="[10, 20, 30, 40, 50]" :page-size="pageSize" layout="total, sizes, prev, pager, next, jumper"
+                :total="totalElements">
+            </el-pagination>
+        </div>
+
+    </div>
+</template>
+<script>
+import { mapState } from 'vuex';
+import pageableTable from '@/mixins/pageableTable';
+
+export default {
+	name: 'MetaAwardDropList',
+	mixins: [pageableTable],
+	data() {
+		return {
+			multipleMode: false,
+			search: '',
+			url: '/metaAwardDrop/all',
+			downloading: false,
+			awardTypeOptions: [
+				{ label: '金币', value: 'GOLD' },
+				{ label: '道具', value: 'META_PROP' }
+			]
+		};
+	},
+	computed: {
+		selection() {
+			return this.$refs.table.selection.map(i => i.id);
+		}
+	},
+	methods: {
+		awardTypeFormatter(row, column, cellValue, index) {
+			let selectedOption = this.awardTypeOptions.find(i => i.value === cellValue);
+			if (selectedOption) {
+				return selectedOption.label;
+			}
+			return '';
+		},
+		beforeGetData() {
+			return { search: this.search, query: { del: false } };
+		},
+		toggleMultipleMode(multipleMode) {
+			this.multipleMode = multipleMode;
+			if (!multipleMode) {
+				this.$refs.table.clearSelection();
+			}
+		},
+		addRow() {
+			this.$router.push({
+				path: '/metaAwardDropEdit',
+				query: {
+					...this.$route.query
+				}
+			});
+		},
+        editRow(row) {
+			this.$router.push({
+				path: '/metaAwardDropEdit',
+				query: {
+					id: row.id
+				}
+			});
+		},
+		download() {
+			this.downloading = true;
+			this.$axios
+				.get('/metaAwardDrop/excel', {
+					responseType: 'blob',
+					params: { size: 10000 }
+				})
+				.then(res => {
+					console.log(res);
+					this.downloading = false;
+					const downloadUrl = window.URL.createObjectURL(new Blob([res.data]));
+					const link = document.createElement('a');
+					link.href = downloadUrl;
+					link.setAttribute('download', res.headers['content-disposition'].split('filename=')[1]);
+					document.body.appendChild(link);
+					link.click();
+					link.remove();
+				})
+				.catch(e => {
+					console.log(e);
+					this.downloading = false;
+					this.$message.error(e.error);
+				});
+		}
+	}
+};
+</script>
+<style lang="less" scoped></style>

+ 258 - 84
src/main/vue/src/views/MetaObjectMoveEdit.vue

@@ -2,29 +2,94 @@
     <div class="edit-view">
         <page-title>
             <el-button @click="$router.go(-1)" :disabled="saving">取消</el-button>
-            <el-button @click="onDelete" :disabled="saving" type="danger" v-if="formData.id">
-                删除
-            </el-button>
-            <el-button @click="onSave" :loading="saving" type="primary">保存</el-button>
+            <template v-if="canEdit">
+                <el-button @click="onSave" :loading="saving" type="primary">保存</el-button>
+            </template>
         </page-title>
         <div class="edit-view__content-wrapper">
             <div class="edit-view__content-section">
-                <el-form :model="formData" :rules="rules" ref="form" label-width="80px" label-position="right"
-                         size="small"
-                         style="max-width: 500px;">
-                        <el-form-item prop="ObjectId" label="物体id">
-                                    <el-input-number type="number" v-model="formData.ObjectId"></el-input-number>
-                        </el-form-item>
-                        <el-form-item prop="metaObjectMoveCoordinateDTOS" label="坐标配置">
-                                    <el-input v-model="formData.metaObjectMoveCoordinateDTOS"></el-input>
-                        </el-form-item>
+                <el-form :model="formData" :rules="rules" ref="form" label-width="80px" label-position="right" size="small"
+                    style="max-width: 500px;">
+                    <el-form-item prop="objectId" label="物体id">
+                        <el-input v-model="formData.objectId" :disabled="!canEdit"></el-input>
+                    </el-form-item>
+                    <el-form-item prop="startTime" label="开始时间">
+                        <el-date-picker v-model="formData.startTime" type="datetime" value-format="yyyy-MM-dd HH:mm:ss"
+                            placeholder="请选择日期时间" :disabled="!canEdit"></el-date-picker>
+                    </el-form-item>
+
+                    <el-form-item prop="metaObjectMoveCoordinateDTOS" label="坐标配置" style="width: calc(100vw - 450px)"
+                        size="mini">
+                        <el-table :data="formData.metaObjectMoveCoordinateDTOS">
+                            <el-table-column prop="axisX" label="axisX" align="center">
+                                <template v-slot="{ row }">
+                                    <el-input v-model="row.axisX" style="width: 120px" placeholder="请输入axisX"
+                                        :disabled="!canEdit">
+                                    </el-input>
+                                </template>
+                            </el-table-column>
+                            <el-table-column prop="axisY" label="axisY" align="center">
+                                <template v-slot="{ row }">
+                                    <el-input v-model="row.axisY" style="width: 120px" placeholder="请输入axisY"
+                                        :disabled="!canEdit">
+                                    </el-input>
+                                </template>
+                            </el-table-column>
+                            <el-table-column prop="axisZ" label="axisZ" align="center">
+                                <template v-slot="{ row }">
+                                    <el-input v-model="row.axisZ" style="width: 120px" placeholder="请输入axisZ"
+                                        :disabled="!canEdit">
+                                    </el-input>
+                                </template>
+                            </el-table-column>
+                            <el-table-column prop="eulerX" label="eulerX" align="center">
+                                <template v-slot="{ row }">
+                                    <el-input v-model="row.eulerX" style="width: 120px" placeholder="请输入eulerX"
+                                        :disabled="!canEdit">
+                                    </el-input>
+                                </template>
+                            </el-table-column>
+                            <el-table-column prop="eulerY" label="eulerY" align="center">
+                                <template v-slot="{ row }">
+                                    <el-input v-model="row.eulerY" style="width: 120px" placeholder="请输入eulerY"
+                                        :disabled="!canEdit">
+                                    </el-input>
+                                </template>
+                            </el-table-column>
+                            <el-table-column prop="eulerZ" label="eulerZ" align="center">
+                                <template v-slot="{ row }">
+                                    <el-input v-model="row.eulerZ" style="width: 120px" placeholder="请输入eulerZ"
+                                        :disabled="!canEdit">
+                                    </el-input>
+                                </template>
+                            </el-table-column>
+                            <el-table-column prop="time" label="time" align="center">
+                                <template v-slot="{ row }">
+                                    <el-input v-model="row.time" type="number" style="width: 120px" placeholder="请输入time"
+                                        :disabled="!canEdit">
+                                    </el-input>
+                                </template>
+                            </el-table-column>
+                            <el-table-column width="80" align="center" v-if="canEdit">
+                                <template v-slot="{ row, $index }">
+                                    <el-button type="danger" plain size="mini" @click="delAward($index)">
+                                        删除
+                                    </el-button>
+                                </template>
+                            </el-table-column>
+                        </el-table>
+                    </el-form-item>
+                    <el-form-item v-if="canEdit">
+                        <div class="tip">注意坐标配置规则:时间含义为到达该坐标的时间(整数,单位为秒)</div>
+                        <div class="tip">起点时间必须为0,后续坐标时间递增</div>
+                        <el-button size="mini" @click="add"> 添加坐标配置 </el-button>
+                    </el-form-item>
                     <el-form-item class="form-submit">
-                        <el-button @click="onSave" :loading="saving" type="primary">
-                            保存
-                        </el-button>
-                        <el-button @click="onDelete" :disabled="saving" type="danger" v-if="formData.id">
-                            删除
-                        </el-button>
+                        <template v-if="canEdit">
+                            <el-button @click="onSave" :loading="saving" type="primary">
+                                保存
+                            </el-button>
+                        </template>
                         <el-button @click="$router.go(-1)" :disabled="saving">取消</el-button>
                     </el-form-item>
                 </el-form>
@@ -33,71 +98,180 @@
     </div>
 </template>
 <script>
-    export default {
-        name: 'MetaObjectMoveEdit',
-        created() {
-            if (this.$route.query.id) {
-                this.$http
-                    .get('metaObjectMove/get/' + this.$route.query.id)
-                    .then(res => {
-                        this.formData = res;
-                    })
-                    .catch(e => {
-                        console.log(e);
-                        this.$message.error(e.error);
-                    });
-            }
-        },
-        data() {
-            return {
-                saving: false,
-                formData: {
-                },
-                rules: {
-                },
-            }
-        },
-        methods: {
-            onSave() {
-                this.$refs.form.validate((valid) => {
-                    if (valid) {
-                        this.submit();
-                    } else {
-                        return false;
-                    }
-                });
-            },
-            submit() {
-                let data = {...this.formData};
+import { reg } from '../util/regRules';
+export default {
+	name: 'MetaObjectMoveEdit',
+	created() {
+		if (this.$route.query.id) {
+			this.$http
+				.get('metaObjectMove/get/' + this.$route.query.id)
+				.then(res => {
+					this.formData = res;
+				})
+				.catch(e => {
+					console.log(e);
+					this.$message.error(e.error);
+				});
+		}
+	},
+	computed: {
+		canEdit() {
+			return !!!this.$route.query.id;
+		}
+	},
+	data() {
+		return {
+			reg,
+			saving: false,
+			formData: {
+				metaObjectMoveCoordinateDTOS: []
+			},
+			rules: {
+				objectId: [
+					{
+						required: true,
+						message: '请输入物体id',
+						trigger: 'blur'
+					}
+				],
+				startTime: [
+					{
+						required: true,
+						message: '请选择开始移动时间',
+						trigger: 'blur'
+					}
+				],
+				metaObjectMoveCoordinateDTOS: [
+					{
+						required: true,
+						validator: (rule, value, callback) => {
+							if (value) {
+								if (!(value instanceof Array)) {
+									callback(new Error('metaObjectMoveCoordinateDTOS must be array!'));
+									return;
+								} else {
+									if (value.length < 2) {
+										callback(new Error('坐标配置必须大于2条'));
+										return;
+									}
+									for (let i = 0; i < value.length; i++) {
+										if (
+											value[i].axisX === '' ||
+											value[i].axisX === undefined ||
+											value[i].axisX === null
+										) {
+											callback(new Error('请填写axisX'));
+											return;
+										}
+										if (
+											value[i].axisY === '' ||
+											value[i].axisY === undefined ||
+											value[i].axisY === null
+										) {
+											callback(new Error('请填写axisY'));
+											return;
+										}
+										if (
+											value[i].axisZ === '' ||
+											value[i].axisZ === undefined ||
+											value[i].axisZ === null
+										) {
+											callback(new Error('请填写axisZ'));
+											return;
+										}
+										if (
+											value[i].eulerX === '' ||
+											value[i].eulerX === undefined ||
+											value[i].eulerX === null
+										) {
+											callback(new Error('请填写eulerX'));
+											return;
+										}
+										if (
+											value[i].eulerY === '' ||
+											value[i].eulerY === undefined ||
+											value[i].eulerY === null
+										) {
+											callback(new Error('请填写eulerY'));
+											return;
+										}
+										if (
+											value[i].eulerZ === '' ||
+											value[i].eulerZ === undefined ||
+											value[i].eulerZ === null
+										) {
+											callback(new Error('请填写eulerZ'));
+											return;
+										}
+										if (
+											value[i].time === '' ||
+											value[i].time === undefined ||
+											value[i].time === null
+										) {
+											callback(new Error('请填写time'));
+											return;
+										}
+									}
+								}
+							}
+							callback();
+						},
+						trigger: 'blur'
+					}
+				]
+			}
+		};
+	},
+	methods: {
+		add() {
+			this.formData.metaObjectMoveCoordinateDTOS.push({});
+		},
+		delAward(i) {
+			this.formData.metaObjectMoveCoordinateDTOS.splice(i, 1);
+		},
+		onSave() {
+			this.$refs.form.validate(valid => {
+				if (valid) {
+					this.submit();
+				} else {
+					return false;
+				}
+			});
+		},
+		submit() {
+			let data = { ...this.formData };
 
-                this.saving = true;
-                this.$http
-                    .post('/metaObjectMove/save', data, {body: 'json'})
-                    .then(res => {
-                        this.saving = false;
-                        this.$message.success('成功');
-                        this.$router.go(-1);
-                    })
-                    .catch(e => {
-                        console.log(e);
-                        this.saving = false;
-                        this.$message.error(e.error);
-                    });
-            },
-            onDelete() {
-                this.$confirm('删除将无法恢复,确认要删除么?', '警告', {type: 'error'}).then(() => {
-                    return this.$http.post(`/metaObjectMove/del/${this.formData.id}`)
-                }).then(() => {
-                    this.$message.success('删除成功');
-                    this.$router.go(-1);
-                }).catch(e => {
-                    if (e !== 'cancel') {
-                        console.log(e);
-                        this.$message.error((e || {}).error || '删除失败');
-                    }
-                })
-            },
-        }
-    }
+			this.saving = true;
+			this.$http
+				.post('/metaObjectMove/save', data, { body: 'json' })
+				.then(res => {
+					this.saving = false;
+					this.$message.success('成功');
+					this.$router.go(-1);
+				})
+				.catch(e => {
+					console.log(e);
+					this.saving = false;
+					this.$message.error(e.error);
+				});
+		},
+		onDelete() {
+			this.$confirm('删除将无法恢复,确认要删除么?', '警告', { type: 'error' })
+				.then(() => {
+					return this.$http.post(`/metaObjectMove/del/${this.formData.id}`);
+				})
+				.then(() => {
+					this.$message.success('删除成功');
+					this.$router.go(-1);
+				})
+				.catch(e => {
+					if (e !== 'cancel') {
+						console.log(e);
+						this.$message.error((e || {}).error || '删除失败');
+					}
+				});
+		}
+	}
+};
 </script>
 <style lang="less" scoped></style>

+ 114 - 143
src/main/vue/src/views/MetaObjectMoveList.vue

@@ -1,166 +1,137 @@
 <template>
-    <div  class="list-view">
+    <div class="list-view">
         <page-title>
-            <el-button @click="addRow" type="primary" icon="el-icon-plus" :disabled="fetchingData || downloading" class="filter-item">
+            <el-button @click="addRow" type="primary" icon="el-icon-plus" :disabled="fetchingData || downloading"
+                class="filter-item">
                 新增
             </el-button>
-            <el-button @click="download" icon="el-icon-upload2" :loading="downloading" :disabled="fetchingData" class="filter-item">
+            <el-button @click="download" icon="el-icon-upload2" :loading="downloading" :disabled="fetchingData"
+                class="filter-item">
                 导出
             </el-button>
         </page-title>
         <div class="filters-container">
-            <el-input
-                    placeholder="搜索..."
-                    v-model="search"
-                    clearable
-                    class="filter-item search"
-                    @keyup.enter.native="getData"
-            >
+            <el-input placeholder="搜索..." v-model="search" clearable class="filter-item search"
+                @keyup.enter.native="getData">
                 <el-button @click="getData" slot="append" icon="el-icon-search"> </el-button>
             </el-input>
         </div>
-        <el-table :data="tableData" row-key="id" ref="table"
-                  header-row-class-name="table-header-row"
-                  header-cell-class-name="table-header-cell"
-                  row-class-name="table-row" cell-class-name="table-cell"
-                  :height="tableHeight" v-loading="fetchingData">
-            <el-table-column v-if="multipleMode" align="center" type="selection"
-                             width="50">
-            </el-table-column>
-            <el-table-column prop="id" label="ID" width="100">
-            </el-table-column>
-                                <el-table-column prop="ObjectId" label="物体id"
->
-                    </el-table-column>
-                    <el-table-column prop="metaObjectMoveCoordinateDTOS" label="坐标配置"
->
-                    </el-table-column>
-            <el-table-column
-                    label="操作"
-                    align="center"
-                    fixed="right"
-                    width="150">
-                <template slot-scope="{row}">
-                    <el-button @click="editRow(row)" type="primary" size="mini" plain>编辑</el-button>
+        <el-table :data="tableData" row-key="id" ref="table" header-row-class-name="table-header-row"
+            header-cell-class-name="table-header-cell" row-class-name="table-row" cell-class-name="table-cell"
+            :height="tableHeight" v-loading="fetchingData">
+            <el-table-column v-if="multipleMode" align="center" type="selection" width="50"> </el-table-column>
+            <el-table-column prop="objectId" label="物体id" align="center" > </el-table-column>
+            <el-table-column prop="startTime" label="物体开始移动时间" align="center" > </el-table-column>
+            <el-table-column label="操作" align="center" fixed="right" width="150">
+                <template slot-scope="{ row }">
+                    <el-button @click="editRow(row)" type="primary" size="mini" plain>查看</el-button>
                     <el-button @click="deleteRow(row)" type="danger" size="mini" plain>删除</el-button>
                 </template>
             </el-table-column>
         </el-table>
         <div class="pagination-wrapper">
-            <!-- <div class="multiple-mode-wrapper">
-                <el-button v-if="!multipleMode" @click="toggleMultipleMode(true)">批量编辑</el-button>
-                <el-button-group v-else>
-                    <el-button @click="operation1">批量操作1</el-button>
-                    <el-button @click="operation2">批量操作2</el-button>
-                    <el-button @click="toggleMultipleMode(false)">取消</el-button>
-                </el-button-group>
-            </div> -->
-            <el-pagination background @size-change="onSizeChange"
-                           @current-change="onCurrentChange" :current-page="page"
-                           :page-sizes="[10, 20, 30, 40, 50]" :page-size="pageSize"
-                           layout="total, sizes, prev, pager, next, jumper"
-                           :total="totalElements">
+            <el-pagination background @size-change="onSizeChange" @current-change="onCurrentChange" :current-page="page"
+                :page-sizes="[10, 20, 30, 40, 50]" :page-size="pageSize" layout="total, sizes, prev, pager, next, jumper"
+                :total="totalElements">
             </el-pagination>
         </div>
-
     </div>
 </template>
 <script>
-    import { mapState } from "vuex";
-    import pageableTable from "@/mixins/pageableTable";
+import { mapState } from 'vuex';
+import pageableTable from '@/mixins/pageableTable';
 
-    export default {
-        name: 'MetaObjectMoveList',
-        mixins: [pageableTable],
-        data() {
-            return {
-                multipleMode: false,
-                search: "",
-                url: "/metaObjectMove/all",
-                downloading: false,
-            }
-        },
-        computed: {
-            selection() {
-                return this.$refs.table.selection.map(i => i.id);
-            }
-        },
-        methods: {
-            beforeGetData() {
-                return { search: this.search, query: { del: false } };
-            },
-            toggleMultipleMode(multipleMode) {
-                this.multipleMode = multipleMode;
-                if (!multipleMode) {
-                    this.$refs.table.clearSelection();
-                }
-            },
-            addRow() {
-                this.$router.push({
-                    path: "/metaObjectMoveEdit",
-                    query: {
-                        ...this.$route.query
-                    }
-                });
-            },
-            editRow(row) {
-                this.$router.push({
-                    path: "/metaObjectMoveEdit",
-                    query: {
-                    id: row.id
-                    }
-                });
-            },
-            download() {
-                this.downloading = true;
-                this.$axios
-                    .get("/metaObjectMove/excel", { 
-                        responseType: "blob",
-                        params: { size: 10000 }
-                    })
-                    .then(res => {
-                        console.log(res);
-                        this.downloading = false;
-                        const downloadUrl = window.URL.createObjectURL(new Blob([res.data]));
-                        const link = document.createElement("a");
-                        link.href = downloadUrl;
-                        link.setAttribute(
-                            "download",
-                            res.headers["content-disposition"].split("filename=")[1]
-                        );
-                        document.body.appendChild(link);
-                        link.click();
-                        link.remove();
-                    })
-                    .catch(e => {
-                        console.log(e);
-                        this.downloading = false;
-                        this.$message.error(e.error);
-                    });
-            },
-            operation1() {
-                this.$notify({
-                    title: '提示',
-                    message: this.selection
-                });
-            },
-            operation2() {
-                this.$message('操作2');
-            },
-            deleteRow(row) {
-                this.$alert('删除将无法恢复,确认要删除么?', '警告', {type: 'error'}).then(() => {
-                    return this.$http.post(`/metaObjectMove/del/${row.id}`)
-                }).then(() => {
-                    this.$message.success('删除成功');
-                    this.getData();
-                }).catch(e => {
-                    if (e !== 'cancel') {
-                        this.$message.error(e.error);
-                    }
-                })
-            },
-        }
-    }
+export default {
+	name: 'MetaObjectMoveList',
+	mixins: [pageableTable],
+	data() {
+		return {
+			multipleMode: false,
+			search: '',
+			url: '/metaObjectMove/all',
+			downloading: false
+		};
+	},
+	computed: {
+		selection() {
+			return this.$refs.table.selection.map(i => i.id);
+		}
+	},
+	methods: {
+		beforeGetData() {
+			return { search: this.search, query: { del: false } };
+		},
+		toggleMultipleMode(multipleMode) {
+			this.multipleMode = multipleMode;
+			if (!multipleMode) {
+				this.$refs.table.clearSelection();
+			}
+		},
+		addRow() {
+			this.$router.push({
+				path: '/metaObjectMoveEdit',
+				query: {
+					...this.$route.query
+				}
+			});
+		},
+		editRow(row) {
+			this.$router.push({
+				path: '/metaObjectMoveEdit',
+				query: {
+					id: row.id
+				}
+			});
+		},
+		download() {
+			this.downloading = true;
+			this.$axios
+				.get('/metaObjectMove/excel', {
+					responseType: 'blob',
+					params: { size: 10000 }
+				})
+				.then(res => {
+					console.log(res);
+					this.downloading = false;
+					const downloadUrl = window.URL.createObjectURL(new Blob([res.data]));
+					const link = document.createElement('a');
+					link.href = downloadUrl;
+					link.setAttribute('download', res.headers['content-disposition'].split('filename=')[1]);
+					document.body.appendChild(link);
+					link.click();
+					link.remove();
+				})
+				.catch(e => {
+					console.log(e);
+					this.downloading = false;
+					this.$message.error(e.error);
+				});
+		},
+		operation1() {
+			this.$notify({
+				title: '提示',
+				message: this.selection
+			});
+		},
+		operation2() {
+			this.$message('操作2');
+		},
+		deleteRow(row) {
+			this.$alert('删除将无法恢复,确认要删除么?', '警告', { type: 'error' })
+				.then(() => {
+					return this.$http.post(`/metaObjectMove/del/${row.id}`);
+				})
+				.then(() => {
+					this.$message.success('删除成功');
+					this.getData();
+				})
+				.catch(e => {
+					if (e !== 'cancel') {
+						this.$message.error(e.error);
+					}
+				});
+		}
+	}
+};
 </script>
-<style lang="less" scoped>
-</style>
+<style lang="less" scoped></style>

+ 48 - 0
src/test/java/com/izouma/nineth/service/MetaTest.java

@@ -0,0 +1,48 @@
+package com.izouma.nineth.service;
+
+import com.aliyun.oss.OSSClient;
+import com.aliyun.oss.model.OSSObject;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.izouma.nineth.ApplicationTests;
+import com.izouma.nineth.config.AliyunProperties;
+import com.izouma.nineth.dto.MetaAwardDropJsonDTO;
+import lombok.extern.slf4j.Slf4j;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+@Slf4j
+@ConditionalOnProperty(name = "storage.provider", havingValue = "aliyun")
+class MetaTest extends ApplicationTests {
+
+    @Autowired
+    private AliyunProperties aliyunProperties;
+
+    @Test
+    void test() {
+        String endpoint = aliyunProperties.getOssEndPoint();
+        String accessKeyId = aliyunProperties.getAccessKeyId();
+        String accessKeySecret = aliyunProperties.getAccessKeySecret();
+        String bucketName = aliyunProperties.getOssBucketName();
+        String objectKey = "application/2023-04-19-11-23-30MnpIUYmK.json";
+        OSSClient client = new OSSClient(endpoint, accessKeyId,
+                accessKeySecret);
+        List<MetaAwardDropJsonDTO> objects = new ArrayList<>();
+        OSSObject ossObject = client.getObject(bucketName, objectKey);
+        InputStream inputStream = ossObject.getObjectContent();
+        ObjectMapper objectMapper = new ObjectMapper();
+        try {
+            objects = objectMapper.readValue(inputStream, objects.getClass());
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+        client.shutdown();
+    }
+
+
+}