xiongzhu 4 лет назад
Родитель
Сommit
f9ca7e9c19
30 измененных файлов с 384 добавлено и 39 удалено
  1. 15 0
      src/main/java/com/izouma/nineth/annotations/RedisLock.java
  2. 1 1
      src/main/java/com/izouma/nineth/aspect/DebounceAspect.java
  3. 67 0
      src/main/java/com/izouma/nineth/aspect/RedisLockAspect.java
  4. 52 4
      src/main/java/com/izouma/nineth/config/CacheConfig.java
  5. 6 1
      src/main/java/com/izouma/nineth/domain/Asset.java
  6. 3 0
      src/main/java/com/izouma/nineth/domain/BlindBoxItem.java
  7. 6 0
      src/main/java/com/izouma/nineth/domain/Collection.java
  8. 5 1
      src/main/java/com/izouma/nineth/domain/IdentityAuth.java
  9. 3 0
      src/main/java/com/izouma/nineth/domain/User.java
  10. 2 0
      src/main/java/com/izouma/nineth/dto/PageQuery.java
  11. 27 0
      src/main/java/com/izouma/nineth/dto/PageWrapper.java
  12. 3 3
      src/main/java/com/izouma/nineth/repo/CollectionRepo.java
  13. 4 0
      src/main/java/com/izouma/nineth/repo/IdentityAuthRepo.java
  14. 2 1
      src/main/java/com/izouma/nineth/service/AirDropService.java
  15. 11 3
      src/main/java/com/izouma/nineth/service/AssetService.java
  16. 4 0
      src/main/java/com/izouma/nineth/service/CacheService.java
  17. 9 7
      src/main/java/com/izouma/nineth/service/CollectionService.java
  18. 9 1
      src/main/java/com/izouma/nineth/service/GiftOrderService.java
  19. 76 4
      src/main/java/com/izouma/nineth/service/IdentityAuthService.java
  20. 2 1
      src/main/java/com/izouma/nineth/service/OrderService.java
  21. 6 3
      src/main/java/com/izouma/nineth/service/UserService.java
  22. 1 1
      src/main/java/com/izouma/nineth/web/CollectionController.java
  23. 3 3
      src/main/java/com/izouma/nineth/web/IdentityAuthController.java
  24. 1 1
      src/main/java/com/izouma/nineth/web/MintActivityController.java
  25. 10 1
      src/main/vue/src/views/BlindBoxEdit.vue
  26. 23 0
      src/main/vue/src/views/CollectionEdit.vue
  27. 1 0
      src/main/vue/src/views/IdentityAuthList.vue
  28. 12 0
      src/test/java/com/izouma/nineth/CommonTest.java
  29. 3 3
      src/test/java/com/izouma/nineth/service/AssetServiceTest.java
  30. 17 0
      src/test/java/com/izouma/nineth/service/IdentityAuthServiceTest.java

+ 15 - 0
src/main/java/com/izouma/nineth/annotations/RedisLock.java

@@ -0,0 +1,15 @@
+package com.izouma.nineth.annotations;
+
+import java.lang.annotation.*;
+import java.util.concurrent.TimeUnit;
+
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface RedisLock {
+    String value();
+
+    long expire() default 10;
+
+    TimeUnit unit() default TimeUnit.SECONDS;
+}

+ 1 - 1
src/main/java/com/izouma/nineth/aspect/DebounceAspect.java

@@ -39,7 +39,7 @@ public class DebounceAspect {
     }
     }
 
 
     @Around(value = "debouncePointCut() && @annotation(debounce)")
     @Around(value = "debouncePointCut() && @annotation(debounce)")
-    public synchronized void debounce(ProceedingJoinPoint joinPoint, Debounce debounce) {
+    public void debounce(ProceedingJoinPoint joinPoint, Debounce debounce) {
         ExpressionParser parser = new SpelExpressionParser();
         ExpressionParser parser = new SpelExpressionParser();
         EvaluationContext context = new StandardEvaluationContext(joinPoint.getSignature());
         EvaluationContext context = new StandardEvaluationContext(joinPoint.getSignature());
         MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
         MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();

+ 67 - 0
src/main/java/com/izouma/nineth/aspect/RedisLockAspect.java

@@ -0,0 +1,67 @@
+package com.izouma.nineth.aspect;
+
+import com.izouma.nineth.annotations.RedisLock;
+import lombok.extern.slf4j.Slf4j;
+import org.aspectj.lang.ProceedingJoinPoint;
+import org.aspectj.lang.annotation.Around;
+import org.aspectj.lang.annotation.Aspect;
+import org.aspectj.lang.annotation.Pointcut;
+import org.aspectj.lang.reflect.MethodSignature;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.core.DefaultParameterNameDiscoverer;
+import org.springframework.data.redis.core.BoundValueOperations;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.expression.EvaluationContext;
+import org.springframework.expression.ExpressionParser;
+import org.springframework.expression.spel.standard.SpelExpressionParser;
+import org.springframework.expression.spel.support.StandardEvaluationContext;
+import org.springframework.stereotype.Component;
+
+import java.lang.reflect.Method;
+import java.util.Optional;
+
+@Aspect
+@Component
+@Slf4j
+public class RedisLockAspect {
+
+    private DefaultParameterNameDiscoverer nameDiscoverer = new DefaultParameterNameDiscoverer();
+
+    @Autowired
+    private RedisTemplate<String, Object> redisTemplate;
+
+    @Pointcut("@annotation(com.izouma.nineth.annotations.RedisLock)")
+    public void redisLockPointCut() {
+    }
+
+    @Around(value = "redisLockPointCut() && @annotation(redisLock)")
+    public void redisLock(ProceedingJoinPoint joinPoint, RedisLock redisLock) {
+        ExpressionParser parser = new SpelExpressionParser();
+        EvaluationContext context = new StandardEvaluationContext(joinPoint.getSignature());
+        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
+        Method method = methodSignature.getMethod();
+        String[] paramNames = nameDiscoverer.getParameterNames(method);
+        Object[] args = joinPoint.getArgs();
+        for (int i = 0; i < args.length; i++) {
+            context.setVariable(paramNames[i], args[i]);
+        }
+        String key = redisLock.value();
+        try {
+            key = Optional.ofNullable(parser.parseExpression(redisLock.value()).getValue(context))
+                    .map(Object::toString)
+                    .orElse("default");
+        } catch (Exception e) {
+        }
+        BoundValueOperations<String, Object> ops = redisTemplate.boundValueOps(key);
+        Boolean success = ops.setIfAbsent(1, redisLock.expire(), redisLock.unit());
+        if (Boolean.TRUE.equals(success)) {
+            try {
+                joinPoint.proceed();
+            } catch (Throwable e) {
+                e.printStackTrace();
+            }
+            redisTemplate.delete(key);
+        }
+    }
+
+}

+ 52 - 4
src/main/java/com/izouma/nineth/config/CacheConfig.java

@@ -6,6 +6,8 @@ import com.fasterxml.jackson.annotation.PropertyAccessor;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.fasterxml.jackson.databind.SerializationFeature;
 import com.fasterxml.jackson.databind.SerializationFeature;
 import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
 import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
+import com.fasterxml.jackson.databind.module.SimpleModule;
+import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
 import com.fasterxml.jackson.datatype.hibernate5.Hibernate5Module;
 import com.fasterxml.jackson.datatype.hibernate5.Hibernate5Module;
 import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
 import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
 import com.izouma.nineth.JsonView.UserView;
 import com.izouma.nineth.JsonView.UserView;
@@ -24,6 +26,10 @@ import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
 import org.springframework.data.redis.serializer.RedisSerializationContext;
 import org.springframework.data.redis.serializer.RedisSerializationContext;
 import org.springframework.data.redis.serializer.StringRedisSerializer;
 import org.springframework.data.redis.serializer.StringRedisSerializer;
 
 
+import java.time.Duration;
+import java.util.HashMap;
+import java.util.Map;
+
 
 
 @Configuration
 @Configuration
 @AutoConfigureAfter({RedisAutoConfiguration.class, CacheAutoConfiguration.class})
 @AutoConfigureAfter({RedisAutoConfiguration.class, CacheAutoConfiguration.class})
@@ -49,6 +55,10 @@ public class CacheConfig {
         mapper.registerModule(new JavaTimeModule());
         mapper.registerModule(new JavaTimeModule());
         mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
         mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
         mapper.setConfig(mapper.getSerializationConfig().withView(UserView.Redis.class));
         mapper.setConfig(mapper.getSerializationConfig().withView(UserView.Redis.class));
+        SimpleModule simpleModule = new SimpleModule();
+        simpleModule.addSerializer(Long.class, ToStringSerializer.instance);
+        simpleModule.addSerializer(Long.TYPE, ToStringSerializer.instance);
+        mapper.registerModule(simpleModule);
 
 
         serializer.setObjectMapper(mapper);
         serializer.setObjectMapper(mapper);
 
 
@@ -61,11 +71,49 @@ public class CacheConfig {
         return template;
         return template;
     }
     }
 
 
+    //    @Bean
+//    public RedisCacheManager redisCacheManager(RedisTemplate redisTemplate) {
+//        RedisCacheWriter redisCacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(redisTemplate.getConnectionFactory());
+//        RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig()
+//                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(redisTemplate.getValueSerializer()));
+//        return new RedisCacheManager(redisCacheWriter, redisCacheConfiguration);
+//    }
     @Bean
     @Bean
-    public RedisCacheManager redisCacheManager(RedisTemplate redisTemplate) {
-        RedisCacheWriter redisCacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(redisTemplate.getConnectionFactory());
-        RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig()
+    public RedisCacheManager userRedisCacheManager(RedisTemplate redisTemplate) {
+        Jackson2JsonRedisSerializer serializer = new Jackson2JsonRedisSerializer<>(Object.class);
+
+        ObjectMapper mapper = new ObjectMapper();
+        mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
+        mapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance,
+                ObjectMapper.DefaultTyping.NON_FINAL,
+                JsonTypeInfo.As.WRAPPER_ARRAY);
+        mapper.registerModule(new Hibernate5Module()
+                .enable(Hibernate5Module.Feature.FORCE_LAZY_LOADING));
+        mapper.registerModule(new JavaTimeModule());
+        mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
+        mapper.setConfig(mapper.getSerializationConfig().withView(UserView.Redis.class));
+        SimpleModule simpleModule = new SimpleModule();
+        simpleModule.addSerializer(Long.class, ToStringSerializer.instance);
+        simpleModule.addSerializer(Long.TYPE, ToStringSerializer.instance);
+        mapper.registerModule(simpleModule);
+
+        serializer.setObjectMapper(mapper);
+
+        Map<String, RedisCacheConfiguration> cacheNamesConfigurationMap = new HashMap<>();
+        cacheNamesConfigurationMap.put("collectionList", RedisCacheConfiguration.defaultCacheConfig()
+                .entryTtl(Duration.ofSeconds(30))
+                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(redisTemplate.getValueSerializer())));
+
+        RedisCacheConfiguration cacheConfiguration = RedisCacheConfiguration.defaultCacheConfig()
+                .entryTtl(Duration.ofDays(7))
                 .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(redisTemplate.getValueSerializer()));
                 .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(redisTemplate.getValueSerializer()));
-        return new RedisCacheManager(redisCacheWriter, redisCacheConfiguration);
+
+        RedisCacheManager redisCacheManager = RedisCacheManager.builder()
+                .cacheWriter(RedisCacheWriter.nonLockingRedisCacheWriter(redisTemplate.getConnectionFactory()))
+                .withInitialCacheConfigurations(cacheNamesConfigurationMap)
+                .cacheDefaults(cacheConfiguration)
+                .build();
+
+        return redisCacheManager;
     }
     }
 }
 }

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

@@ -161,6 +161,9 @@ public class Asset extends BaseEntity {
     @Enumerated(EnumType.STRING)
     @Enumerated(EnumType.STRING)
     private CollectionType type;
     private CollectionType type;
 
 
+    @ApiModelProperty("持有几天")
+    private Integer holdDays;
+
     @Transient
     @Transient
     private boolean opened = true;
     private boolean opened = true;
 
 
@@ -187,10 +190,11 @@ public class Asset extends BaseEntity {
                 .ownerId(user.getId())
                 .ownerId(user.getId())
                 .ownerAvatar(user.getAvatar())
                 .ownerAvatar(user.getAvatar())
                 .type(CollectionType.DEFAULT)
                 .type(CollectionType.DEFAULT)
+                .holdDays(collection.getHoldDays())
                 .build();
                 .build();
     }
     }
 
 
-    public static Asset create(BlindBoxItem item, User user) {
+    public static Asset create(BlindBoxItem item, User user,Integer holdDays) {
         return Asset.builder()
         return Asset.builder()
                 .userId(user.getId())
                 .userId(user.getId())
                 .collectionId(item.getCollectionId())
                 .collectionId(item.getCollectionId())
@@ -213,6 +217,7 @@ public class Asset extends BaseEntity {
                 .ownerId(user.getId())
                 .ownerId(user.getId())
                 .ownerAvatar(user.getAvatar())
                 .ownerAvatar(user.getAvatar())
                 .type(CollectionType.BLIND_BOX)
                 .type(CollectionType.BLIND_BOX)
+                .holdDays(holdDays)
                 .build();
                 .build();
     }
     }
 }
 }

+ 3 - 0
src/main/java/com/izouma/nineth/domain/BlindBoxItem.java

@@ -95,4 +95,7 @@ public class BlindBoxItem extends BaseEntity {
 
 
     @ApiModelProperty("稀有")
     @ApiModelProperty("稀有")
     private boolean rare;
     private boolean rare;
+
+//    @ApiModelProperty("持有几天")
+//    private Integer holdDays;
 }
 }

+ 6 - 0
src/main/java/com/izouma/nineth/domain/Collection.java

@@ -182,4 +182,10 @@ public class Collection extends BaseEntity {
 
 
     @ApiModelProperty("销售时间")
     @ApiModelProperty("销售时间")
     private LocalDateTime saleTime;
     private LocalDateTime saleTime;
+
+    @ApiModelProperty("持有几天")
+    private Integer holdDays;
+
+    @ApiModelProperty("开启抢白名单")
+    private Boolean openQuota;
 }
 }

+ 5 - 1
src/main/java/com/izouma/nineth/domain/IdentityAuth.java

@@ -12,7 +12,7 @@ import javax.persistence.*;
 
 
 @Data
 @Data
 @Entity
 @Entity
-@Table(indexes = {@Index(columnList = "userId")})
+@Table(indexes = {@Index(columnList = "userId"), @Index(columnList = "idNo")})
 @AllArgsConstructor
 @AllArgsConstructor
 @NoArgsConstructor
 @NoArgsConstructor
 @Builder
 @Builder
@@ -50,4 +50,8 @@ public class IdentityAuth extends BaseEntity {
     @Enumerated(EnumType.STRING)
     @Enumerated(EnumType.STRING)
     private AuthStatus status;
     private AuthStatus status;
 
 
+    private boolean autoValidated;
+
+    private String reason;
+
 }
 }

+ 3 - 0
src/main/java/com/izouma/nineth/domain/User.java

@@ -151,4 +151,7 @@ public class User extends BaseEntity implements Serializable {
     @Column(columnDefinition = "int(11) default 0")
     @Column(columnDefinition = "int(11) default 0")
     @ApiModelProperty("白名单积分")
     @ApiModelProperty("白名单积分")
     private int vipPoint = 0;
     private int vipPoint = 0;
+
+    @ApiModelProperty(value = "风险提示")
+    private Boolean riskWarning;
 }
 }

+ 2 - 0
src/main/java/com/izouma/nineth/dto/PageQuery.java

@@ -1,11 +1,13 @@
 package com.izouma.nineth.dto;
 package com.izouma.nineth.dto;
 
 
 import lombok.Data;
 import lombok.Data;
+import lombok.ToString;
 
 
 import java.util.HashMap;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Map;
 
 
 @Data
 @Data
+@ToString
 public class PageQuery {
 public class PageQuery {
     private int                 page  = 0;
     private int                 page  = 0;
     private int                 size  = 20;
     private int                 size  = 20;

+ 27 - 0
src/main/java/com/izouma/nineth/dto/PageWrapper.java

@@ -0,0 +1,27 @@
+package com.izouma.nineth.dto;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.PageImpl;
+import org.springframework.data.domain.PageRequest;
+
+import java.util.List;
+
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class PageWrapper<T> {
+    private List<T> content;
+
+    private int page;
+
+    private int size;
+
+    private long total;
+
+    public Page<T> toPage() {
+        return new PageImpl<>(content, PageRequest.of(page, size), total);
+    }
+}

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

@@ -30,14 +30,14 @@ public interface CollectionRepo extends JpaRepository<Collection, Long>, JpaSpec
             "c.schedule_sale = ?5, c.sort = ?6, c.detail = ?7, c.privileges = ?8, " +
             "c.schedule_sale = ?5, c.sort = ?6, c.detail = ?7, c.privileges = ?8, " +
             "c.properties = ?9, c.model3d = ?10, c.max_count = ?11, c.count_id = ?12, c.scan_code = ?13, " +
             "c.properties = ?9, c.model3d = ?10, c.max_count = ?11, c.count_id = ?12, c.scan_code = ?13, " +
             "c.no_sold_out = ?14, c.assignment = ?15, c.coupon_payment = ?16, c.share_bg = ?17," +
             "c.no_sold_out = ?14, c.assignment = ?15, c.coupon_payment = ?16, c.share_bg = ?17," +
-            "c.register_bg = ?18, c.vip_quota = ?19, c.time_delay = ?20, c.sale_time = ?21 " +
-            "where c.id = ?1", nativeQuery = true)
+            "c.register_bg = ?18, c.vip_quota = ?19, c.time_delay = ?20, c.sale_time = ?21, c.hold_days = ?22, " +
+            "c.open_quota = ?23 where c.id = ?1", nativeQuery = true)
     @CacheEvict(value = {"collection", "recommend"}, allEntries = true)
     @CacheEvict(value = {"collection", "recommend"}, allEntries = true)
     void update(@Nonnull Long id, boolean onShelf, boolean salable, LocalDateTime startTime,
     void update(@Nonnull Long id, boolean onShelf, boolean salable, LocalDateTime startTime,
                 boolean schedule, int sort, String detail, String privileges,
                 boolean schedule, int sort, String detail, String privileges,
                 String properties, String model3d, int maxCount, String countId, boolean scanCode,
                 String properties, String model3d, int maxCount, String countId, boolean scanCode,
                 boolean noSoldOut, int assignment, boolean couponPayment, String shareBg, String registerBg,
                 boolean noSoldOut, int assignment, boolean couponPayment, String shareBg, String registerBg,
-                Integer vipQuota, Boolean timeDelay, LocalDateTime saleTime);
+                Integer vipQuota, Boolean timeDelay, LocalDateTime saleTime, Integer holdDays, Boolean openQuota);
 
 
     @Cacheable("collection")
     @Cacheable("collection")
     Optional<Collection> findById(@Nonnull Long id);
     Optional<Collection> findById(@Nonnull Long id);

+ 4 - 0
src/main/java/com/izouma/nineth/repo/IdentityAuthRepo.java

@@ -29,4 +29,8 @@ public interface IdentityAuthRepo extends JpaRepository<IdentityAuth, Long>, Jpa
     Optional<IdentityAuth> findByIdAndDelFalse(Long id);
     Optional<IdentityAuth> findByIdAndDelFalse(Long id);
 
 
     List<IdentityAuth> findAllByIdNoAndUserIdIsNotAndDelFalse(String idNo, Long userId);
     List<IdentityAuth> findAllByIdNoAndUserIdIsNotAndDelFalse(String idNo, Long userId);
+
+    List<IdentityAuth> findByStatusAndAutoValidated(AuthStatus status, boolean validated);
+
+    int countByIdNoAndStatus(String idNo, AuthStatus status);
 }
 }

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

@@ -56,7 +56,8 @@ public class AirDropService {
                 try {
                 try {
                     if (collection.getType() == CollectionType.BLIND_BOX) {
                     if (collection.getType() == CollectionType.BLIND_BOX) {
                         BlindBoxItem winItem = collectionService.draw(collection.getId());
                         BlindBoxItem winItem = collectionService.draw(collection.getId());
-                        assetService.createAsset(winItem, user, null, null, "空投", collectionService.getNextNumber(winItem.getCollectionId()));
+                        assetService.createAsset(winItem, user, null, null, "空投",
+                                collectionService.getNextNumber(winItem.getCollectionId()), collection.getHoldDays());
                     } else {
                     } else {
                         assetService.createAsset(collection, user, null, null, "空投", collectionService.getNextNumber(collection.getId()));
                         assetService.createAsset(collection, user, null, null, "空投", collectionService.getNextNumber(collection.getId()));
                     }
                     }

+ 11 - 3
src/main/java/com/izouma/nineth/service/AssetService.java

@@ -91,8 +91,9 @@ public class AssetService {
         return asset;
         return asset;
     }
     }
 
 
-    public Asset createAsset(BlindBoxItem winItem, User user, Long orderId, BigDecimal price, String type, Integer number) {
-        Asset asset = Asset.create(winItem, user);
+    public Asset createAsset(BlindBoxItem winItem, User user, Long orderId, BigDecimal price, String type,
+                             Integer number, Integer holdDays) {
+        Asset asset = Asset.create(winItem, user, holdDays);
         asset.setTokenId(TokenUtils.genTokenId());
         asset.setTokenId(TokenUtils.genTokenId());
         asset.setNumber(number);
         asset.setNumber(number);
         asset.setOrderId(orderId);
         asset.setOrderId(orderId);
@@ -163,7 +164,14 @@ public class AssetService {
         if (!asset.getUserId().equals(SecurityUtils.getAuthenticatedUser().getId())) {
         if (!asset.getUserId().equals(SecurityUtils.getAuthenticatedUser().getId())) {
             throw new BusinessException("此藏品不属于你");
             throw new BusinessException("此藏品不属于你");
         }
         }
-        int holdDays = sysConfigService.getInt("hold_days");
+
+        int holdDays;
+        if (ObjectUtils.isEmpty(asset.getHoldDays())) {
+            holdDays = sysConfigService.getInt("hold_days");
+        } else {
+            holdDays = asset.getHoldDays();
+        }
+
         if (ChronoUnit.DAYS.between(asset.getCreatedAt(), LocalDateTime.now()) < holdDays) {
         if (ChronoUnit.DAYS.between(asset.getCreatedAt(), LocalDateTime.now()) < holdDays) {
             throw new BusinessException("需持有满" + holdDays + "天才能寄售上架");
             throw new BusinessException("需持有满" + holdDays + "天才能寄售上架");
         }
         }

+ 4 - 0
src/main/java/com/izouma/nineth/service/CacheService.java

@@ -36,4 +36,8 @@ public class CacheService {
     @CacheEvict(value = "recommend", allEntries = true)
     @CacheEvict(value = "recommend", allEntries = true)
     public void clearRecommend() {
     public void clearRecommend() {
     }
     }
+
+    @CacheEvict(value = "collectionList", allEntries = true)
+    public void clearCollectionList() {
+    }
 }
 }

+ 9 - 7
src/main/java/com/izouma/nineth/service/CollectionService.java

@@ -6,10 +6,7 @@ import com.izouma.nineth.config.GeneralProperties;
 import com.izouma.nineth.config.RedisKeys;
 import com.izouma.nineth.config.RedisKeys;
 import com.izouma.nineth.domain.Collection;
 import com.izouma.nineth.domain.Collection;
 import com.izouma.nineth.domain.*;
 import com.izouma.nineth.domain.*;
-import com.izouma.nineth.dto.CollectionDTO;
-import com.izouma.nineth.dto.CollectionStockAndSale;
-import com.izouma.nineth.dto.CreateBlindBox;
-import com.izouma.nineth.dto.PageQuery;
+import com.izouma.nineth.dto.*;
 import com.izouma.nineth.enums.CollectionSource;
 import com.izouma.nineth.enums.CollectionSource;
 import com.izouma.nineth.enums.CollectionType;
 import com.izouma.nineth.enums.CollectionType;
 import com.izouma.nineth.enums.OrderStatus;
 import com.izouma.nineth.enums.OrderStatus;
@@ -25,6 +22,7 @@ import org.apache.commons.lang3.Range;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.rocketmq.spring.core.RocketMQTemplate;
 import org.apache.rocketmq.spring.core.RocketMQTemplate;
 import org.springframework.beans.BeanUtils;
 import org.springframework.beans.BeanUtils;
+import org.springframework.cache.annotation.Cacheable;
 import org.springframework.core.env.Environment;
 import org.springframework.core.env.Environment;
 import org.springframework.data.domain.Page;
 import org.springframework.data.domain.Page;
 import org.springframework.data.domain.PageImpl;
 import org.springframework.data.domain.PageImpl;
@@ -85,7 +83,8 @@ public class CollectionService {
         }
         }
     }
     }
 
 
-    public Page<Collection> all(PageQuery pageQuery) {
+    @Cacheable(value = "collectionList", key = "#pageQuery.hashCode()")
+    public PageWrapper<Collection> all(PageQuery pageQuery) {
         pageQuery.getQuery().put("del", false);
         pageQuery.getQuery().put("del", false);
         String type = MapUtils.getString(pageQuery.getQuery(), "type", "DEFAULT");
         String type = MapUtils.getString(pageQuery.getQuery(), "type", "DEFAULT");
         pageQuery.getQuery().remove("type");
         pageQuery.getQuery().remove("type");
@@ -115,7 +114,9 @@ public class CollectionService {
             }
             }
             return criteriaBuilder.and(and.toArray(new Predicate[0]));
             return criteriaBuilder.and(and.toArray(new Predicate[0]));
         });
         });
-        return collectionRepo.findAll(specification, pageRequest);
+        Page<Collection> page = collectionRepo.findAll(specification, pageRequest);
+        return new PageWrapper<>(page.getContent(), page.getPageable().getPageNumber(),
+                page.getPageable().getPageSize(), page.getTotalElements());
     }
     }
 
 
     public Collection create(Collection record) {
     public Collection create(Collection record) {
@@ -152,7 +153,8 @@ public class CollectionService {
                 JSON.toJSONString(record.getProperties()), JSON.toJSONString(record.getModel3d()),
                 JSON.toJSONString(record.getProperties()), JSON.toJSONString(record.getModel3d()),
                 record.getMaxCount(), record.getCountId(), record.isScanCode(), record.isNoSoldOut(),
                 record.getMaxCount(), record.getCountId(), record.isScanCode(), record.isNoSoldOut(),
                 record.getAssignment(), record.isCouponPayment(), record.getShareBg(), record.getRegisterBg(),
                 record.getAssignment(), record.isCouponPayment(), record.getShareBg(), record.getRegisterBg(),
-                record.getVipQuota(), record.getTimeDelay(), record.getSaleTime());
+                record.getVipQuota(), record.getTimeDelay(), record.getSaleTime(), record.getHoldDays(),
+                record.getOpenQuota());
 
 
         record = collectionRepo.findById(record.getId()).orElseThrow(new BusinessException("无记录"));
         record = collectionRepo.findById(record.getId()).orElseThrow(new BusinessException("无记录"));
         onShelfTask(record);
         onShelfTask(record);

+ 9 - 1
src/main/java/com/izouma/nineth/service/GiftOrderService.java

@@ -34,6 +34,7 @@ import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.codec.EncoderException;
 import org.apache.commons.codec.EncoderException;
 import org.apache.commons.codec.net.URLCodec;
 import org.apache.commons.codec.net.URLCodec;
 import org.apache.commons.collections.MapUtils;
 import org.apache.commons.collections.MapUtils;
+import org.apache.commons.lang3.ObjectUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.springframework.core.env.Environment;
 import org.springframework.core.env.Environment;
 import org.springframework.scheduling.annotation.Scheduled;
 import org.springframework.scheduling.annotation.Scheduled;
@@ -76,7 +77,14 @@ public class GiftOrderService {
         if (!asset.getUserId().equals(userId)) {
         if (!asset.getUserId().equals(userId)) {
             throw new BusinessException("无权限");
             throw new BusinessException("无权限");
         }
         }
-        int holdDays = sysConfigService.getInt("hold_days");
+
+        int holdDays;
+        if (ObjectUtils.isEmpty(asset.getHoldDays())) {
+            holdDays = sysConfigService.getInt("hold_days");
+        } else {
+            holdDays = asset.getHoldDays();
+        }
+
         if (ChronoUnit.DAYS.between(asset.getCreatedAt(), LocalDateTime.now()) < holdDays) {
         if (ChronoUnit.DAYS.between(asset.getCreatedAt(), LocalDateTime.now()) < holdDays) {
             throw new BusinessException("需持有满" + holdDays + "天才能转赠");
             throw new BusinessException("需持有满" + holdDays + "天才能转赠");
         }
         }

+ 76 - 4
src/main/java/com/izouma/nineth/service/IdentityAuthService.java

@@ -1,5 +1,8 @@
 package com.izouma.nineth.service;
 package com.izouma.nineth.service;
 
 
+import com.alibaba.fastjson.JSONObject;
+import com.github.kevinsawicki.http.HttpRequest;
+import com.izouma.nineth.annotations.RedisLock;
 import com.izouma.nineth.domain.IdentityAuth;
 import com.izouma.nineth.domain.IdentityAuth;
 import com.izouma.nineth.domain.User;
 import com.izouma.nineth.domain.User;
 import com.izouma.nineth.dto.PageQuery;
 import com.izouma.nineth.dto.PageQuery;
@@ -9,19 +12,29 @@ import com.izouma.nineth.repo.IdentityAuthRepo;
 import com.izouma.nineth.repo.UserRepo;
 import com.izouma.nineth.repo.UserRepo;
 import com.izouma.nineth.utils.JpaUtils;
 import com.izouma.nineth.utils.JpaUtils;
 import lombok.AllArgsConstructor;
 import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.core.env.Environment;
 import org.springframework.data.domain.Page;
 import org.springframework.data.domain.Page;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.scheduling.annotation.Scheduled;
 import org.springframework.stereotype.Service;
 import org.springframework.stereotype.Service;
 
 
+import java.util.Arrays;
 import java.util.List;
 import java.util.List;
+import java.util.concurrent.TimeUnit;
 import java.util.stream.Collectors;
 import java.util.stream.Collectors;
 
 
 @Service
 @Service
 @AllArgsConstructor
 @AllArgsConstructor
+@Slf4j
 public class IdentityAuthService {
 public class IdentityAuthService {
 
 
-    private IdentityAuthRepo identityAuthRepo;
-    private UserRepo         userRepo;
-    private AdapayService    adapayService;
+    private IdentityAuthRepo              identityAuthRepo;
+    private UserRepo                      userRepo;
+    private AdapayService                 adapayService;
+    private RedisTemplate<String, Object> redisTemplate;
+    private Environment                   env;
+    private SysConfigService              sysConfigService;
 
 
     public Page<IdentityAuth> all(PageQuery pageQuery) {
     public Page<IdentityAuth> all(PageQuery pageQuery) {
         return identityAuthRepo.findAll(JpaUtils.toSpecification(pageQuery, IdentityAuth.class), JpaUtils.toPageRequest(pageQuery));
         return identityAuthRepo.findAll(JpaUtils.toSpecification(pageQuery, IdentityAuth.class), JpaUtils.toPageRequest(pageQuery));
@@ -45,7 +58,7 @@ public class IdentityAuthService {
         userRepo.save(user);
         userRepo.save(user);
     }
     }
 
 
-    public void audit(Long id, AuthStatus status) {
+    public void audit(Long id, AuthStatus status, String reason) {
         IdentityAuth auth = identityAuthRepo.findByIdAndDelFalse(id).orElseThrow(new BusinessException("申请不存在"));
         IdentityAuth auth = identityAuthRepo.findByIdAndDelFalse(id).orElseThrow(new BusinessException("申请不存在"));
         if (auth.getStatus() != AuthStatus.PENDING) {
         if (auth.getStatus() != AuthStatus.PENDING) {
             throw new BusinessException("已经审核过");
             throw new BusinessException("已经审核过");
@@ -55,6 +68,8 @@ public class IdentityAuthService {
             user.setAuthId(auth.getId());
             user.setAuthId(auth.getId());
         }
         }
         auth.setStatus(status);
         auth.setStatus(status);
+        auth.setReason(reason);
+        auth.setAutoValidated(true);
         identityAuthRepo.save(auth);
         identityAuthRepo.save(auth);
         user.setAuthStatus(status);
         user.setAuthStatus(status);
         userRepo.save(user);
         userRepo.save(user);
@@ -68,4 +83,61 @@ public class IdentityAuthService {
         List<Long> userIds = auths.stream().map(IdentityAuth::getUserId).distinct().collect(Collectors.toList());
         List<Long> userIds = auths.stream().map(IdentityAuth::getUserId).distinct().collect(Collectors.toList());
         return userRepo.findByIdInAndDelFalse(userIds);
         return userRepo.findByIdInAndDelFalse(userIds);
     }
     }
+
+    public void validate(String name, String phone, String idno) {
+        String body = HttpRequest.post("https://jubrige.market.alicloudapi.com/mobile/3-validate-transfer")
+                .header("Authorization", "APPCODE b48bc8f6759345a79ae20a951f03dabe")
+                .contentType(HttpRequest.CONTENT_TYPE_FORM)
+                .form("idCardNo", idno)
+                .form("mobile", phone)
+                .form("name", name)
+                .body();
+        JSONObject jsonObject = JSONObject.parseObject(body);
+        if (jsonObject.getInteger("code") != 200) {
+            String msg = jsonObject.getString("msg");
+            throw new BusinessException(msg);
+        } else {
+            JSONObject data = jsonObject.getJSONObject("data");
+            int result = data.getIntValue("result");
+            String desc = data.getString("desc");
+            if (result != 0) {
+                throw new BusinessException(desc);
+            } else {
+                log.info("{} {} {} 实名认证通过", name, phone, idno);
+            }
+        }
+    }
+
+    @Scheduled(fixedRate = 60000)
+    @RedisLock(value = "autoValidate", expire = 30, unit = TimeUnit.MINUTES)
+    public void autoValidate() {
+        if (!sysConfigService.getBoolean("auto_validate")) return;
+        log.info("autoValidate");
+        if (Arrays.asList(env.getActiveProfiles()).contains("dev")) {
+            return;
+        }
+        try {
+            List<IdentityAuth> list = identityAuthRepo.findByStatusAndAutoValidated(AuthStatus.PENDING, false);
+            list.parallelStream().forEach(identityAuth -> {
+                int count = identityAuthRepo.countByIdNoAndStatus(identityAuth.getIdNo(), AuthStatus.SUCCESS);
+                boolean success = false;
+                String reason = null;
+                if (count >= 3) {
+                    success = false;
+                    reason = "同一身份证注册超过3个";
+                } else {
+                    try {
+                        User user = userRepo.findById(identityAuth.getUserId())
+                                .orElseThrow(new BusinessException("用户不存在"));
+                        validate(identityAuth.getRealName(), user.getPhone(), identityAuth.getIdNo());
+                        success = true;
+                    } catch (Exception e) {
+                        reason = e.getMessage();
+                    }
+                }
+                audit(identityAuth.getId(), success ? AuthStatus.SUCCESS : AuthStatus.PENDING, reason);
+            });
+        } catch (Exception ignored) {
+        }
+    }
 }
 }

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

@@ -565,7 +565,8 @@ public class OrderService {
                     order.setWinCollectionId(winItem.getCollectionId());
                     order.setWinCollectionId(winItem.getCollectionId());
                     orderRepo.save(order);
                     orderRepo.save(order);
                     assetService.createAsset(winItem, user, order.getId(), order.getPrice(), "出售",
                     assetService.createAsset(winItem, user, order.getId(), order.getPrice(), "出售",
-                            winItem.getTotal() > 1 ? collectionService.getNextNumber(winItem.getCollectionId()) : null);
+                            winItem.getTotal() > 1 ? collectionService.getNextNumber(winItem.getCollectionId()) : null,
+                            collection.getHoldDays());
                 } else {
                 } else {
                     if (collection.getSource() == CollectionSource.TRANSFER) {
                     if (collection.getSource() == CollectionSource.TRANSFER) {
                         orderRepo.save(order);
                         orderRepo.save(order);

+ 6 - 3
src/main/java/com/izouma/nineth/service/UserService.java

@@ -29,6 +29,7 @@ import me.chanjar.weixin.common.error.WxErrorException;
 import me.chanjar.weixin.mp.api.WxMpService;
 import me.chanjar.weixin.mp.api.WxMpService;
 import me.chanjar.weixin.mp.bean.result.WxMpOAuth2AccessToken;
 import me.chanjar.weixin.mp.bean.result.WxMpOAuth2AccessToken;
 import me.chanjar.weixin.mp.bean.result.WxMpUser;
 import me.chanjar.weixin.mp.bean.result.WxMpUser;
+import org.apache.commons.lang3.ObjectUtils;
 import org.apache.commons.lang3.RandomStringUtils;
 import org.apache.commons.lang3.RandomStringUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.springframework.beans.BeanUtils;
 import org.springframework.beans.BeanUtils;
@@ -191,8 +192,8 @@ public class UserService {
 
 
         // 加积分
         // 加积分
         if (collectionId != null && invitor != null) {
         if (collectionId != null && invitor != null) {
-            // 额度
-            if (collection.getVipQuota() > 0) {
+            // 额度或者额度为空
+            if (collection.getVipQuota() > 0 || ObjectUtils.isEmpty(collection.getVipQuota())) {
                 int countUser = userRepo.countAllByCollectionIdAndCollectionInvitor(collectionId, invitor);
                 int countUser = userRepo.countAllByCollectionIdAndCollectionInvitor(collectionId, invitor);
                 // 邀请人数
                 // 邀请人数
                 if (countUser >= collection.getAssignment()) {
                 if (countUser >= collection.getAssignment()) {
@@ -209,7 +210,9 @@ public class UserService {
                                     .point(1)
                                     .point(1)
                                     .build());
                                     .build());
                             // 扣除藏品额度
                             // 扣除藏品额度
-                            collectionService.decreaseQuota(collectionId, 1);
+                            if(ObjectUtils.isNotEmpty(collection.getVipQuota())){
+                                collectionService.decreaseQuota(collectionId, 1);
+                            }
                         }
                         }
                     }
                     }
                 }
                 }

+ 1 - 1
src/main/java/com/izouma/nineth/web/CollectionController.java

@@ -48,7 +48,7 @@ public class CollectionController extends BaseController {
     //@PreAuthorize("hasRole('ADMIN')")
     //@PreAuthorize("hasRole('ADMIN')")
     @PostMapping("/all")
     @PostMapping("/all")
     public Page<CollectionDTO> all(@RequestBody PageQuery pageQuery) {
     public Page<CollectionDTO> all(@RequestBody PageQuery pageQuery) {
-        return collectionService.toDTO(collectionService.all(pageQuery));
+        return collectionService.toDTO(collectionService.all(pageQuery).toPage());
     }
     }
 
 
     @GetMapping("/get/{id}")
     @GetMapping("/get/{id}")

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

@@ -61,13 +61,13 @@ public class IdentityAuthController extends BaseController {
     @PreAuthorize("hasAnyRole('ADMIN', 'OPERATOR')")
     @PreAuthorize("hasAnyRole('ADMIN', 'OPERATOR')")
     @PostMapping("/pass")
     @PostMapping("/pass")
     public void audit(@RequestParam Long id) {
     public void audit(@RequestParam Long id) {
-        identityAuthService.audit(id, AuthStatus.SUCCESS);
+        identityAuthService.audit(id, AuthStatus.SUCCESS, null);
     }
     }
 
 
     @PreAuthorize("hasAnyRole('ADMIN', 'OPERATOR')")
     @PreAuthorize("hasAnyRole('ADMIN', 'OPERATOR')")
     @PostMapping("/deny")
     @PostMapping("/deny")
-    public void deny(@RequestParam Long id) {
-        identityAuthService.audit(id, AuthStatus.FAIL);
+    public void deny(@RequestParam Long id, @RequestParam(required = false) String reason) {
+        identityAuthService.audit(id, AuthStatus.FAIL, reason);
     }
     }
 
 
     @ApiOperation("查找重复身份证")
     @ApiOperation("查找重复身份证")

+ 1 - 1
src/main/java/com/izouma/nineth/web/MintActivityController.java

@@ -23,7 +23,7 @@ public class MintActivityController extends BaseController {
     private MintActivityService mintActivityService;
     private MintActivityService mintActivityService;
     private MintActivityRepo    mintActivityRepo;
     private MintActivityRepo    mintActivityRepo;
 
 
-    //@PreAuthorize("hasRole('ADMIN')")
+    @PreAuthorize("hasRole('ADMIN')")
     @PostMapping("/save")
     @PostMapping("/save")
     public MintActivity save(@RequestBody MintActivity record) {
     public MintActivity save(@RequestBody MintActivity record) {
         if (record.getId() != null) {
         if (record.getId() != null) {

+ 10 - 1
src/main/vue/src/views/BlindBoxEdit.vue

@@ -189,6 +189,11 @@
                         <el-input v-model="formData.countId"></el-input>
                         <el-input v-model="formData.countId"></el-input>
                         <div class="tip">相同识别码的藏品共享限购数量</div>
                         <div class="tip">相同识别码的藏品共享限购数量</div>
                     </el-form-item>
                     </el-form-item>
+
+                    <el-form-item prop="holdDays" label="持有天数">
+                        <el-input-number type="number" :min="0" :step="1" :max="2147483647" v-model="formData.holdDays" style="width: 180px"></el-input-number>
+                        <div class="tip">持有多少天可转赠/转让。为空时,按系统设置天数</div>
+                    </el-form-item>
                     <el-form-item prop="noSoldOut" label="售罄">
                     <el-form-item prop="noSoldOut" label="售罄">
                         <el-radio v-model="formData.noSoldOut" :label="false">是</el-radio>
                         <el-radio v-model="formData.noSoldOut" :label="false">是</el-radio>
                         <el-radio v-model="formData.noSoldOut" :label="true">否</el-radio>
                         <el-radio v-model="formData.noSoldOut" :label="true">否</el-radio>
@@ -221,6 +226,10 @@
                             <div class="tip">多少人拉新可获得积分</div>
                             <div class="tip">多少人拉新可获得积分</div>
                         </el-form-item>
                         </el-form-item>
                     </div>
                     </div>
+                    <el-form-item prop="openQuota" label="白名单分享" v-if="formData.assignment > 0">
+                        <el-radio v-model="formData.openQuota" :label="true">开启</el-radio>
+                        <el-radio v-model="formData.openQuota" :label="false">关闭</el-radio>
+                    </el-form-item>
                     <div class="inline-wrapper">
                     <div class="inline-wrapper">
                         <el-form-item prop="timeDelay" label="延迟销售" v-if="formData.assignment > 0">
                         <el-form-item prop="timeDelay" label="延迟销售" v-if="formData.assignment > 0">
                             <el-radio v-model="formData.timeDelay" :label="true">是</el-radio>
                             <el-radio v-model="formData.timeDelay" :label="true">是</el-radio>
@@ -680,7 +689,7 @@ export default {
             });
             });
         },
         },
         submit() {
         submit() {
-              if (this.editQuota && this.formData.totalQuota) {
+            if (this.editQuota && this.formData.totalQuota) {
                 this.formData.vipQuota = this.formData.totalQuota;
                 this.formData.vipQuota = this.formData.totalQuota;
             }
             }
             if (this.formData.id) {
             if (this.formData.id) {

+ 23 - 0
src/main/vue/src/views/CollectionEdit.vue

@@ -226,6 +226,11 @@
                             <div class="tip">相同识别码的藏品共享限购数量</div>
                             <div class="tip">相同识别码的藏品共享限购数量</div>
                         </el-form-item>
                         </el-form-item>
                     </div>
                     </div>
+
+                    <el-form-item prop="holdDays" label="持有天数">
+                        <el-input-number type="number" :min="0" :step="1" :max="2147483647" v-model="formData.holdDays" style="width: 180px"></el-input-number>
+                        <div class="tip">持有多少天可转赠/转让。为空时,按系统设置天数。</div>
+                    </el-form-item>
                     <el-form-item prop="noSoldOut" label="售罄">
                     <el-form-item prop="noSoldOut" label="售罄">
                         <el-radio v-model="formData.noSoldOut" :label="false">是</el-radio>
                         <el-radio v-model="formData.noSoldOut" :label="false">是</el-radio>
                         <el-radio v-model="formData.noSoldOut" :label="true">否</el-radio>
                         <el-radio v-model="formData.noSoldOut" :label="true">否</el-radio>
@@ -258,6 +263,10 @@
                             <div class="tip">多少人拉新可获得积分</div>
                             <div class="tip">多少人拉新可获得积分</div>
                         </el-form-item>
                         </el-form-item>
                     </div>
                     </div>
+                    <el-form-item prop="openQuota" label="白名单分享" v-if="formData.assignment > 0">
+                        <el-radio v-model="formData.openQuota" :label="true">开启</el-radio>
+                        <el-radio v-model="formData.openQuota" :label="false">关闭</el-radio>
+                    </el-form-item>
                     <div class="inline-wrapper">
                     <div class="inline-wrapper">
                         <el-form-item prop="timeDelay" label="延迟销售" v-if="formData.assignment > 0">
                         <el-form-item prop="timeDelay" label="延迟销售" v-if="formData.assignment > 0">
                             <el-radio v-model="formData.timeDelay" :label="true">是</el-radio>
                             <el-radio v-model="formData.timeDelay" :label="true">是</el-radio>
@@ -600,6 +609,20 @@ export default {
                         },
                         },
                         trigger: 'blur'
                         trigger: 'blur'
                     }
                     }
+                ],
+                openQuota: [
+                    {
+                        validator: (rule, value, callback) => {
+                            if (this.formData.assignment > 0) {
+                                if (value === '' || value === undefined) {
+                                    callback(new Error('请选择开启/关闭白名单分享'));
+                                    return;
+                                }
+                            }
+                            callback();
+                        },
+                        trigger: 'blur'
+                    }
                 ]
                 ]
             },
             },
             typeOptions: [
             typeOptions: [

+ 1 - 0
src/main/vue/src/views/IdentityAuthList.vue

@@ -107,6 +107,7 @@
             </el-table-column>
             </el-table-column>
             <el-table-column prop="status" label="审核状态" :formatter="statusFormatter" width="120" align="center">
             <el-table-column prop="status" label="审核状态" :formatter="statusFormatter" width="120" align="center">
             </el-table-column>
             </el-table-column>
+            <el-table-column prop="createdAt" label="时间" width="150">
             <el-table-column label="操作" align="center" fixed="right" width="210">
             <el-table-column label="操作" align="center" fixed="right" width="210">
                 <template slot-scope="{ row }">
                 <template slot-scope="{ row }">
                     <el-button @click="repeat(row)" type="success" size="mini" plain> 查重 </el-button>
                     <el-button @click="repeat(row)" type="success" size="mini" plain> 查重 </el-button>

+ 12 - 0
src/test/java/com/izouma/nineth/CommonTest.java

@@ -8,6 +8,7 @@ import com.izouma.nineth.config.Constants;
 import com.izouma.nineth.domain.BaseEntity;
 import com.izouma.nineth.domain.BaseEntity;
 import com.izouma.nineth.domain.BlindBoxItem;
 import com.izouma.nineth.domain.BlindBoxItem;
 import com.izouma.nineth.domain.User;
 import com.izouma.nineth.domain.User;
+import com.izouma.nineth.dto.PageQuery;
 import com.izouma.nineth.utils.AESEncryptUtil;
 import com.izouma.nineth.utils.AESEncryptUtil;
 import com.izouma.nineth.utils.TokenUtils;
 import com.izouma.nineth.utils.TokenUtils;
 import com.izouma.nineth.web.BaseController;
 import com.izouma.nineth.web.BaseController;
@@ -452,4 +453,15 @@ public class CommonTest {
         final Map<String, String> map = Splitter.on('&').trimResults().withKeyValueSeparator('=').split(qs);
         final Map<String, String> map = Splitter.on('&').trimResults().withKeyValueSeparator('=').split(qs);
         System.out.println(map);
         System.out.println(map);
     }
     }
+
+    @Test
+    public void aasdf() {
+        System.out.println(new ArrayList<>(10).size());
+
+        PageQuery p1 = new PageQuery();
+        PageQuery p2 = new PageQuery();
+        p1.setPage(2);
+        System.out.println(p1.hashCode());
+        System.out.println(p2.hashCode());
+    }
 }
 }

+ 3 - 3
src/test/java/com/izouma/nineth/service/AssetServiceTest.java

@@ -78,7 +78,7 @@ class AssetServiceTest extends ApplicationTests {
         Collection collection = collectionRepo.findById(order.getCollectionId()).get();
         Collection collection = collectionRepo.findById(order.getCollectionId()).get();
         BlindBoxItem blindBoxItem = blindBoxItemRepo.findById(4250L).get();
         BlindBoxItem blindBoxItem = blindBoxItemRepo.findById(4250L).get();
         User user = userRepo.findById(order.getUserId()).get();
         User user = userRepo.findById(order.getUserId()).get();
-        assetService.createAsset(blindBoxItem, user, order.getId(), order.getPrice(), "出售", 1);
+        assetService.createAsset(blindBoxItem, user, order.getId(), order.getPrice(), "出售", 1, collection.getHoldDays());
     }
     }
 
 
     @Test
     @Test
@@ -188,8 +188,8 @@ class AssetServiceTest extends ApplicationTests {
     }
     }
 
 
     @Test
     @Test
-    public void asdfasdfasdfasdf() {
-        List<kebi> list = EasyExcel.read("/Users/drew/Downloads/科比移民明细表(1).xlsx")
+    public void 科比移民() {
+        List<kebi> list = EasyExcel.read("/Users/drew/Desktop/副本科比移民明细表(1).xlsx")
                 .head(kebi.class).sheet()
                 .head(kebi.class).sheet()
                 .headRowNumber(2)
                 .headRowNumber(2)
                 .doReadSync();
                 .doReadSync();

+ 17 - 0
src/test/java/com/izouma/nineth/service/IdentityAuthServiceTest.java

@@ -0,0 +1,17 @@
+package com.izouma.nineth.service;
+
+import com.izouma.nineth.ApplicationTests;
+import org.junit.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+
+public class IdentityAuthServiceTest extends ApplicationTests {
+    @Autowired
+    private IdentityAuthService identityAuthService;
+
+    @Test
+    public void validate() {
+        identityAuthService.validate("熊竹", "15077886171", "321002199408304611");
+        identityAuthService.validate("熊竹", "15077886171", "321002199408304614");
+    }
+
+}