ソースを参照

Merge branch 'message' into dev

# Conflicts:
#	src/main/java/com/izouma/nineth/service/OrderService.java
#	src/main/java/com/izouma/nineth/service/UserService.java
#	src/main/java/com/izouma/nineth/web/OrderController.java
#	src/main/vue/src/router.js
licailing 3 年 前
コミット
e84d545267
29 ファイル変更490 行追加165 行削除
  1. 12 6
      src/main/java/com/izouma/nineth/domain/HeatInfo.java
  2. 0 2
      src/main/java/com/izouma/nineth/domain/ShowCollection.java
  3. 8 5
      src/main/java/com/izouma/nineth/domain/Showroom.java
  4. 19 0
      src/main/java/com/izouma/nineth/dto/CompanyDTO.java
  5. 8 0
      src/main/java/com/izouma/nineth/enums/HeatType.java
  6. 7 0
      src/main/java/com/izouma/nineth/enums/ShowroomType.java
  7. 2 0
      src/main/java/com/izouma/nineth/event/CreateOrderEvent.java
  8. 1 0
      src/main/java/com/izouma/nineth/event/RegisterEvent.java
  9. 1 1
      src/main/java/com/izouma/nineth/listener/CreateOrderListener.java
  10. 3 2
      src/main/java/com/izouma/nineth/listener/RegisterListener.java
  11. 16 0
      src/main/java/com/izouma/nineth/repo/HeatInfoRepo.java
  12. 20 2
      src/main/java/com/izouma/nineth/repo/ShowroomRepo.java
  13. 0 13
      src/main/java/com/izouma/nineth/repo/ViewInfoRepo.java
  14. 2 2
      src/main/java/com/izouma/nineth/service/CacheService.java
  15. 17 4
      src/main/java/com/izouma/nineth/service/NewsLikeService.java
  16. 33 5
      src/main/java/com/izouma/nineth/service/OrderService.java
  17. 25 17
      src/main/java/com/izouma/nineth/service/ShowroomService.java
  18. 41 14
      src/main/java/com/izouma/nineth/service/UserService.java
  19. 4 8
      src/main/java/com/izouma/nineth/web/AuthenticationController.java
  20. 3 2
      src/main/java/com/izouma/nineth/web/OrderController.java
  21. 13 7
      src/main/java/com/izouma/nineth/web/ShowroomController.java
  22. 7 0
      src/main/java/com/izouma/nineth/web/UserController.java
  23. 80 25
      src/main/vue/src/views/CompanyList.vue
  24. 12 7
      src/main/vue/src/views/ShowroomEdit.vue
  25. 36 27
      src/main/vue/src/views/ShowroomList.vue
  26. 6 2
      src/main/vue/src/views/company/CompanyCollectionShelf.vue
  27. 81 11
      src/main/vue/src/views/company/CompanyRoomEdit.vue
  28. 31 2
      src/main/vue/src/views/company/CompanyRoomList.vue
  29. 2 1
      src/test/java/com/izouma/nineth/service/UserServiceTest.java

+ 12 - 6
src/main/java/com/izouma/nineth/domain/ViewInfo.java → src/main/java/com/izouma/nineth/domain/HeatInfo.java

@@ -1,26 +1,32 @@
 package com.izouma.nineth.domain;
 
+import com.izouma.nineth.enums.HeatType;
 import io.swagger.annotations.ApiModel;
 import lombok.AllArgsConstructor;
 import lombok.Builder;
 import lombok.Data;
 import lombok.NoArgsConstructor;
 
-import javax.persistence.Entity;
-import javax.persistence.Index;
-import javax.persistence.Table;
+import javax.persistence.*;
 
 @Data
 @Entity
-@Table(name = "view_info", indexes =
+@Table(name = "heat_info", indexes =
         {@Index(columnList = "userId"), @Index(columnList = "showroomId")})
 @AllArgsConstructor
 @NoArgsConstructor
 @Builder
-@ApiModel("浏览")
-public class ViewInfo extends BaseEntity {
+@ApiModel("热力值详情")
+public class HeatInfo extends BaseEntity {
 
     private Long userId;
 
     private Long showroomId;
+
+    @Enumerated(EnumType.STRING)
+    private HeatType type;
+
+    private Long orderId;
+
+    private int value;
 }

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

@@ -1,7 +1,5 @@
 package com.izouma.nineth.domain;
 
-import com.izouma.nineth.enums.AssetStatus;
-import com.izouma.nineth.enums.CollectionStatus;
 import io.swagger.annotations.ApiModel;
 import lombok.AllArgsConstructor;
 import lombok.Builder;

+ 8 - 5
src/main/java/com/izouma/nineth/domain/Showroom.java

@@ -2,6 +2,7 @@ package com.izouma.nineth.domain;
 
 import com.izouma.nineth.annotations.Searchable;
 import com.izouma.nineth.enums.AuthStatus;
+import com.izouma.nineth.enums.ShowroomType;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 import lombok.AllArgsConstructor;
@@ -22,7 +23,7 @@ import java.util.List;
         @Index(columnList = "userId"),
         @Index(columnList = "assetId"),
         @Index(columnList = "likes"),
-        @Index(columnList = "share")
+        @Index(columnList = "heats")
 })
 @Where(clause = "del = 0")
 @ApiModel("展厅")
@@ -56,7 +57,8 @@ public class Showroom extends BaseEntity {
     @ApiModelProperty("展厅背景")
     private String showroomBg;
 
-    private String type;
+    @Enumerated(EnumType.STRING)
+    private ShowroomType type;
 
     @Enumerated(EnumType.STRING)
     private AuthStatus status;
@@ -75,10 +77,11 @@ public class Showroom extends BaseEntity {
     @Transient
     private boolean liked;
 
-    private int views;
-
-    private int buys;
+    @Column(columnDefinition = "int(11) default 0")
+    @ApiModelProperty("热力值")
+    private int heats;
 
+    @Column(columnDefinition = "int(11) default 0")
     private int registers;
 
 }

+ 19 - 0
src/main/java/com/izouma/nineth/dto/CompanyDTO.java

@@ -0,0 +1,19 @@
+package com.izouma.nineth.dto;
+
+import com.izouma.nineth.domain.User;
+import lombok.Data;
+import org.springframework.beans.BeanUtils;
+
+@Data
+public class CompanyDTO {
+    private Long   id;
+    private String username;
+    private String nickname;
+    private String avatar;
+    private int    showroomNum;
+    private int    boxShowroomNum;
+
+    public CompanyDTO(User user) {
+        BeanUtils.copyProperties(user, this);
+    }
+}

+ 8 - 0
src/main/java/com/izouma/nineth/enums/HeatType.java

@@ -0,0 +1,8 @@
+package com.izouma.nineth.enums;
+
+public enum HeatType {
+    VIEW,
+    REGISTER,
+    BUY,
+    LIKE
+}

+ 7 - 0
src/main/java/com/izouma/nineth/enums/ShowroomType.java

@@ -0,0 +1,7 @@
+package com.izouma.nineth.enums;
+
+public enum ShowroomType {
+    COMPANY_BOX,
+    COMPANY,
+    USER
+}

+ 2 - 0
src/main/java/com/izouma/nineth/event/CreateOrderEvent.java

@@ -26,4 +26,6 @@ public class CreateOrderEvent implements Serializable {
     @JsonSerialize(using = ToStringSerializer.class)
     private Long    invitor;
     private boolean vip;
+    @JsonSerialize(using = ToStringSerializer.class)
+    private Long    showroomId;
 }

+ 1 - 0
src/main/java/com/izouma/nineth/event/RegisterEvent.java

@@ -14,4 +14,5 @@ public class RegisterEvent {
     private String inviteCode;
     private Long   invitor;
     private Long   collectionId;
+    private Long   showroomId;
 }

+ 1 - 1
src/main/java/com/izouma/nineth/listener/CreateOrderListener.java

@@ -37,7 +37,7 @@ public class CreateOrderListener implements RocketMQListener<CreateOrderEvent> {
         try {
             Order order = orderService.create(event.getUserId(), event.getCollectionId(), event.getQty(),
                     event.getAddressId(), event.getUserCouponId(), event.getInvitor(), event.getId(),
-                    event.isVip());
+                    event.isVip(), event.getShowroomId());
             map.put("success", true);
             map.put("data", order);
         } catch (Exception e) {

+ 3 - 2
src/main/java/com/izouma/nineth/listener/RegisterListener.java

@@ -28,9 +28,9 @@ import java.util.regex.Pattern;
         consumeMode = ConsumeMode.ORDERLY)
 @ConditionalOnProperty(value = "general.notify-server", havingValue = "false", matchIfMissing = true)
 public class RegisterListener implements RocketMQListener<RegisterEvent> {
+    private final JwtTokenUtil                  jwtTokenUtil;
     private       UserService                   userService;
     private       RedisTemplate<String, Object> redisTemplate;
-    private final JwtTokenUtil                  jwtTokenUtil;
 
     @Override
     public void onMessage(RegisterEvent registerEvent) {
@@ -38,7 +38,8 @@ public class RegisterListener implements RocketMQListener<RegisterEvent> {
         try {
             User user = userService.phoneRegister(registerEvent.getPhone(), registerEvent.getCode(),
                     registerEvent.getPassword(), registerEvent.getInviteCode(),
-                    registerEvent.getInvitor(), registerEvent.getCollectionId());
+                    registerEvent.getInvitor(), registerEvent.getCollectionId(),
+                    registerEvent.getShowroomId());
             map.put("status", "success");
             map.put("data", user);
             map.put("token", jwtTokenUtil.generateToken(JwtUserFactory.create(user)));

+ 16 - 0
src/main/java/com/izouma/nineth/repo/HeatInfoRepo.java

@@ -0,0 +1,16 @@
+package com.izouma.nineth.repo;
+
+import com.izouma.nineth.domain.HeatInfo;
+import com.izouma.nineth.enums.HeatType;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
+
+import java.util.List;
+
+public interface HeatInfoRepo extends JpaRepository<HeatInfo, Long>, JpaSpecificationExecutor<HeatInfo> {
+
+    List<HeatInfo> findByUserIdAndShowroomIdAndType(Long userId, Long showroomId, HeatType type);
+
+    List<HeatInfo> findByUserIdAndOrderIdAndType(Long userId, Long orderId, HeatType type);
+
+}

+ 20 - 2
src/main/java/com/izouma/nineth/repo/ShowroomRepo.java

@@ -10,6 +10,8 @@ import org.springframework.data.jpa.repository.Query;
 
 import javax.annotation.Nonnull;
 import javax.transaction.Transactional;
+import java.util.List;
+import java.util.Map;
 import java.util.Optional;
 
 public interface ShowroomRepo extends JpaRepository<Showroom, Long>, JpaSpecificationExecutor<Showroom> {
@@ -36,10 +38,26 @@ public interface ShowroomRepo extends JpaRepository<Showroom, Long>, JpaSpecific
     @Cacheable(value = "showroom", key = "#id")
     Optional<Showroom> findById(@Nonnull Long id);
 
-    @Query("update Showroom t set t.views = t.views + ?2 where t.id = ?1")
+//    @Query("update Showroom t set t.views = t.views + ?2 where t.id = ?1")
+//    @Modifying
+//    @Transactional
+//    void addView(Long id, int num);
+
+    @Query("update Showroom t set t.heats = t.heats + ?2 where t.id = ?1")
+    @Modifying
+    @Transactional
+    void addHeat(Long id, int num);
+
+    @Query("update Showroom t set t.heats = t.heats + ?2, t.likes = t.likes + ?3 where t.id = ?1")
     @Modifying
     @Transactional
-    void addView(Long id, int num);
+    void addHeatAndLike(Long id, int heatNum, int likeNum);
 
+    @Query("update Showroom t set t.heats = t.heats + ?2, t.registers = t.registers + ?3 where t.id = ?1")
+    @Modifying
+    @Transactional
+    void addHeatAndRegister(Long id, int heatNum, int registerNum);
 
+    @Query(nativeQuery = true, value = "select user_id, count(id) num from showroom where type = ?1 group by user_id")
+    List<Map<String, Object>> countNum(String type);
 }

+ 0 - 13
src/main/java/com/izouma/nineth/repo/ViewInfoRepo.java

@@ -1,13 +0,0 @@
-package com.izouma.nineth.repo;
-
-import com.izouma.nineth.domain.ViewInfo;
-import org.springframework.data.jpa.repository.JpaRepository;
-import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
-
-import java.util.List;
-
-public interface ViewInfoRepo extends JpaRepository<ViewInfo, Long>, JpaSpecificationExecutor<ViewInfo> {
-
-    List<ViewInfo> findByUserIdAndShowroomId(Long userId, Long showroomId);
-
-}

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

@@ -87,8 +87,8 @@ public class CacheService {
     public void clearSettingList(int flag) {
     }
 
-    @CacheEvict(value = {"showroom"}, allEntries = true)
-    public void clearShowroom() {
+    @CacheEvict(value = {"showroom"}, key = "#id")
+    public void clearShowroom(Long id) {
     }
 
     @CacheEvict(value = "fmaa", allEntries = true)

+ 17 - 4
src/main/java/com/izouma/nineth/service/NewsLikeService.java

@@ -1,7 +1,10 @@
 package com.izouma.nineth.service;
 
+import com.izouma.nineth.domain.HeatInfo;
 import com.izouma.nineth.domain.NewsLike;
 import com.izouma.nineth.dto.PageQuery;
+import com.izouma.nineth.enums.HeatType;
+import com.izouma.nineth.repo.HeatInfoRepo;
 import com.izouma.nineth.repo.NewsLikeRepo;
 import com.izouma.nineth.repo.NewsRepo;
 import com.izouma.nineth.repo.ShowroomRepo;
@@ -16,9 +19,11 @@ import java.util.List;
 @AllArgsConstructor
 public class NewsLikeService {
 
-    private NewsLikeRepo newsLikeRepo;
-    private NewsRepo     newsRepo;
-    private ShowroomRepo showroomRepo;
+    private NewsLikeRepo     newsLikeRepo;
+    private NewsRepo         newsRepo;
+    private ShowroomRepo     showroomRepo;
+    private SysConfigService sysConfigService;
+    private HeatInfoRepo     heatInfoRepo;
 
     public Page<NewsLike> all(PageQuery pageQuery) {
         return newsLikeRepo.findAll(JpaUtils.toSpecification(pageQuery, NewsLike.class), JpaUtils.toPageRequest(pageQuery));
@@ -49,7 +54,15 @@ public class NewsLikeService {
                 .userId(userId)
                 .showroomId(roomId)
                 .build());
-        showroomRepo.addLike(roomId, 1);
+        int weight = sysConfigService.getInt("heat_like_weight");
+        heatInfoRepo.save(HeatInfo.builder()
+                .showroomId(roomId)
+                .userId(userId)
+                .type(HeatType.LIKE)
+                .value(weight)
+                .build());
+        showroomRepo.addHeatAndLike(roomId, 1, weight);
+
     }
 
     public void unlikeRoom(Long userId, Long roomId) {

+ 33 - 5
src/main/java/com/izouma/nineth/service/OrderService.java

@@ -1,5 +1,6 @@
 package com.izouma.nineth.service;
 
+import cn.hutool.core.collection.CollUtil;
 import com.alibaba.excel.EasyExcel;
 import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONObject;
@@ -48,7 +49,6 @@ import org.springframework.cache.annotation.Cacheable;
 import org.springframework.context.event.EventListener;
 import org.springframework.core.env.Environment;
 import org.springframework.data.domain.Page;
-import org.springframework.data.domain.Pageable;
 import org.springframework.data.redis.core.BoundSetOperations;
 import org.springframework.data.redis.core.BoundValueOperations;
 import org.springframework.data.redis.core.RedisTemplate;
@@ -105,6 +105,8 @@ public class OrderService {
     private final UserPropertyRepo              userPropertyRepo;
     private final UserBalanceService            userBalanceService;
     private final ProxyManager<String>          buckets;
+    private final HeatInfoRepo                  heatInfoRepo;
+    private final ShowroomRepo                  showroomRepo;
 
     public OrderService(OrderRepo orderRepo, CollectionRepo collectionRepo, UserAddressRepo userAddressRepo,
                         UserRepo userRepo, Environment env, AlipayClient alipayClient,
@@ -117,7 +119,8 @@ public class OrderService {
                         SmsService smsService, ErrorOrderRepo errorOrderRepo, ShowCollectionRepo showCollectionRepo,
                         ShowroomService showroomService, CollectionPrivilegeRepo collectionPrivilegeRepo,
                         UserBankCardRepo userBankCardRepo, CacheService cacheService, UserPropertyRepo userPropertyRepo,
-                        UserBalanceService userBalanceService, ProxyManager<String> proxyManager) {
+                        UserBalanceService userBalanceService, ProxyManager<String> proxyManager,
+                        HeatInfoRepo heatInfoRepo, ShowroomRepo showroomRepo) {
         this.orderRepo = orderRepo;
         this.collectionRepo = collectionRepo;
         this.userAddressRepo = userAddressRepo;
@@ -148,14 +151,17 @@ public class OrderService {
         this.userPropertyRepo = userPropertyRepo;
         this.userBalanceService = userBalanceService;
         this.buckets = proxyManager;
+        this.heatInfoRepo = heatInfoRepo;
+        this.showroomRepo = showroomRepo;
     }
 
+
     public Page<Order> all(PageQuery pageQuery) {
         return orderRepo.findAll(JpaUtils.toSpecification(pageQuery, Order.class), JpaUtils.toPageRequest(pageQuery));
     }
 
     public String mqCreate(Long userId, Long collectionId, int qty, Long addressId, Long userCouponId, Long invitor,
-                           String sign, boolean vip, int vipPurchase, int vipPoint, boolean safeFlag) {
+                           String sign, boolean vip,  boolean safeFlag, Long showroomId) {
         String qs = null;
         try {
             qs = AESEncryptUtil.decrypt(sign);
@@ -190,7 +196,7 @@ public class OrderService {
         Long id = snowflakeIdWorker.nextId();
         redisTemplate.opsForValue().set("safeFlag::" + id, safeFlag, 10, TimeUnit.MINUTES);
         SendResult result = rocketMQTemplate.syncSend(generalProperties.getCreateOrderTopic(),
-                new CreateOrderEvent(id, userId, collectionId, qty, addressId, userCouponId, invitor, vip),
+                new CreateOrderEvent(id, userId, collectionId, qty, addressId, userCouponId, invitor, vip, showroomId),
                 100000);
 
         log.info("发送订单到队列: {}, userId={}, result={}", id, userId, result);
@@ -207,7 +213,7 @@ public class OrderService {
     }
 
     public Order create(Long userId, Long collectionId, int qty, Long addressId, Long userCouponId, Long invitor,
-                        Long id, boolean vip) {
+                        Long id, boolean vip, Long showroomId) {
         long t = System.currentTimeMillis();
         qty = 1;
         int stock = Optional.ofNullable(collectionService.decreaseStock(collectionId, qty))
@@ -393,6 +399,17 @@ public class OrderService {
                 userRepo.addVipPoint(userId, -usePoint);
                 cacheService.clearUserMy(userId);
             }
+
+            if (ObjectUtils.isNotEmpty(showroomId)) {
+                //通过展厅的购买数量
+                heatInfoRepo.save(HeatInfo.builder()
+                        .showroomId(showroomId)
+                        .userId(userId)
+                        .type(HeatType.BUY)
+                        .value(0)
+                        .orderId(order.getId())
+                        .build());
+            }
             rocketMQTemplate.syncSend(generalProperties.getUpdateStockTopic(), collectionId, 10000);
             log.info("订单创建完成, id={}, {}ms", order.getId(), System.currentTimeMillis() - t);
             return order;
@@ -738,6 +755,17 @@ public class OrderService {
                 if (collection.getAssetId() == null) {
                     collectionService.increaseSale(order.getCollectionId(), order.getQty());
                 }
+
+                //通过展厅购买加热力值
+                List<HeatInfo> heatInfos = heatInfoRepo.findByUserIdAndOrderIdAndType(order.getUserId(), orderId, HeatType.BUY);
+                if (CollUtil.isNotEmpty(heatInfos)) {
+                    HeatInfo heatInfo = heatInfos.get(0);
+                    int weight = sysConfigService.getInt("heat_buy_weight");
+                    heatInfo.setValue(weight);
+                    heatInfoRepo.save(heatInfo);
+                    showroomRepo.addHeat(heatInfo.getShowroomId(), weight);
+                }
+
             } else {
                 throw new BusinessException("状态错误 " + order.getStatus());
             }

+ 25 - 17
src/main/java/com/izouma/nineth/service/ShowroomService.java

@@ -1,12 +1,13 @@
 package com.izouma.nineth.service;
 
 import cn.hutool.core.collection.CollUtil;
-import com.izouma.nineth.domain.*;
 import com.izouma.nineth.domain.Collection;
+import com.izouma.nineth.domain.*;
 import com.izouma.nineth.dto.PageQuery;
 import com.izouma.nineth.enums.AssetStatus;
 import com.izouma.nineth.enums.AuthStatus;
 import com.izouma.nineth.enums.CollectionType;
+import com.izouma.nineth.enums.ShowroomType;
 import com.izouma.nineth.exception.BusinessException;
 import com.izouma.nineth.repo.*;
 import com.izouma.nineth.utils.JpaUtils;
@@ -104,7 +105,6 @@ public class ShowroomService {
             }
         });
 
-        cacheService.clearShowroom();
         return show;
     }
 
@@ -128,25 +128,27 @@ public class ShowroomService {
                 .userId(asset.getUserId())
                 .assetId(asset.getId())
                 .nickname(asset.getOwner())
-                .type("USER")
+                .type(ShowroomType.USER)
                 .status(AuthStatus.SUCCESS)
                 .build();
         showroom = showroomRepo.save(showroom);
 
-        cacheService.clearShowroom();
         return showroom;
     }
 
-    public Showroom save(Long userId) {
+    public Showroom save(Long userId, String type) {
         User user = userRepo.findByIdAndDelFalse(userId).orElseThrow(new BusinessException("无用户"));
         if (!user.isCompany()) {
             throw new BusinessException("无用户权限");
         }
-
-        if (showroomRepo.findByUserIdAndType(user.getId(), "COMPANY").isPresent()) {
-            throw new BusinessException("已创建过展厅");
+        int maxCollection = 1;
+        if ("COMPANY".equals(type)) {
+//            if (showroomRepo.findByUserIdAndType(user.getId(), "COMPANY").isPresent()) {
+//                throw new BusinessException("已创建过展厅");
+//            }
+            maxCollection = sysConfigService.getInt("max_collection");
         }
-        int maxCollection = sysConfigService.getInt("max_collection");
+
 
         Showroom showroom = Showroom.builder()
                 .headBg("")
@@ -155,12 +157,11 @@ public class ShowroomService {
                 .publish(false)
                 .userId(user.getId())
                 .nickname(user.getNickname())
-                .type("COMPANY")
+                .type(ShowroomType.valueOf(type))
                 .status(AuthStatus.NOT_AUTH)
                 .build();
         showroom = showroomRepo.save(showroom);
 
-        cacheService.clearShowroom();
         return showroom;
     }
 
@@ -180,6 +181,7 @@ public class ShowroomService {
 
         Set<Long> removeRecord = new HashSet<>(showCollectionMap.keySet());
 
+
         if (CollUtil.isNotEmpty(showCollections)) {
             showCollections = showCollections.stream().distinct().collect(Collectors.toList());
 
@@ -195,12 +197,13 @@ public class ShowroomService {
             List<Collection> collections = collectionRepo.findAllByIdIn(collectionIds);
             Map<Long, Collection> collectionMap = new HashMap<>();
             collections.forEach(collection -> {
-                if (!userId.equals(collection.getOwnerId())) {
-                    throw new BusinessException("该藏品不属于你");
-                }
+//                if (!userId.equals(collection.getOwnerId())) {
+//                    throw new BusinessException("该藏品不属于你");
+//                }
                 collectionMap.put(collection.getId(), collection);
             });
 
+
             showCollections.forEach(coll -> {
                 if (coll.getId() != null) {
                     ShowCollection showCollection = showCollectionMap.get(coll.getId());
@@ -219,6 +222,11 @@ public class ShowroomService {
                     } else {
                         Collection collection = collectionMap.get(coll.getCollectionId());
                         if (ObjectUtils.isNotEmpty(collection)) {
+                            if (ShowroomType.COMPANY_BOX.equals(recordRoom.getType())) {
+                                if (!CollectionType.BLIND_BOX.equals(collection.getType())) {
+                                    throw new BusinessException("盲盒展厅,只能添加盲盒");
+                                }
+                            }
                             FileObject pic = collection.getPic().get(0);
                             coll.setPic(pic.getUrl());
                             if ("video/mp4".equals(pic.getType())) {
@@ -246,13 +254,13 @@ public class ShowroomService {
         recordRoom.setPublish(true);
 
         showroom = showroomRepo.save(recordRoom);
-        cacheService.clearShowroom();
+        cacheService.clearShowroom(showroom.getId());
         return showroom;
     }
 
     public void audit(Long id, AuthStatus status, String reason) {
         Showroom showroom = showroomRepo.findById(id).orElseThrow(new BusinessException("无展厅"));
-        if (!"COMPANY".equals(showroom.getType())) {
+        if (ShowroomType.USER.equals(showroom.getType())) {
             // 非企业类型不需要审核
             showroom.setStatus(null);
             showroomRepo.save(showroom);
@@ -261,7 +269,7 @@ public class ShowroomService {
         showroom.setStatus(status);
         showroom.setReason(reason);
         showroomRepo.save(showroom);
-        cacheService.clearShowroom();
+        cacheService.clearShowroom(id);
     }
 
     public String getStatus(Collection collection) {

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

@@ -3,8 +3,8 @@ package com.izouma.nineth.service;
 import cn.binarywang.wx.miniapp.api.WxMaService;
 import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
 import cn.binarywang.wx.miniapp.bean.WxMaUserInfo;
+import cn.hutool.core.convert.Convert;
 import com.alibaba.fastjson.JSONObject;
-import com.fasterxml.jackson.core.sym.NameN;
 import com.huifu.adapay.core.exception.BaseAdaPayException;
 import com.izouma.nineth.TokenHistory;
 import com.izouma.nineth.config.Constants;
@@ -15,7 +15,7 @@ import com.izouma.nineth.domain.*;
 import com.izouma.nineth.dto.*;
 import com.izouma.nineth.enums.AuthStatus;
 import com.izouma.nineth.enums.AuthorityName;
-import com.izouma.nineth.event.AccountCreatedEvent;
+import com.izouma.nineth.enums.HeatType;
 import com.izouma.nineth.event.RegisterEvent;
 import com.izouma.nineth.exception.BusinessException;
 import com.izouma.nineth.repo.*;
@@ -41,8 +41,6 @@ import org.apache.rocketmq.spring.core.RocketMQTemplate;
 import org.springframework.beans.BeanUtils;
 import org.springframework.cache.annotation.CacheEvict;
 import org.springframework.cache.annotation.Cacheable;
-import org.springframework.context.event.EventListener;
-import org.springframework.core.env.Environment;
 import org.springframework.data.domain.Page;
 import org.springframework.data.domain.PageImpl;
 import org.springframework.data.domain.PageRequest;
@@ -54,17 +52,11 @@ import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
 import org.springframework.security.crypto.password.PasswordEncoder;
 import org.springframework.stereotype.Service;
 
-import javax.persistence.criteria.CriteriaBuilder;
-import javax.persistence.criteria.CriteriaQuery;
 import javax.persistence.criteria.Predicate;
-import javax.persistence.criteria.Root;
 import java.math.BigDecimal;
 import java.math.BigInteger;
 import java.text.SimpleDateFormat;
 import java.time.Duration;
-import java.time.LocalDate;
-import java.time.format.DateTimeFormatter;
-import java.time.temporal.ChronoUnit;
 import java.util.*;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.regex.Pattern;
@@ -97,7 +89,8 @@ public class UserService {
     private WeakPassRepo                  weakPassRepo;
     private UserBalanceRepo               userBalanceRepo;
     private ContentAuditService           contentAuditService;
-    private OrderRepo                     orderRepo;
+    private HeatInfoRepo                  heatInfoRepo;
+    private ShowroomRepo                  showroomRepo;
 
     public User update(User user) {
         if (!SecurityUtils.hasRole(AuthorityName.ROLE_ADMIN)) {
@@ -224,7 +217,8 @@ public class UserService {
         return save(user);
     }
 
-    public User phoneRegister(String phone, String code, String password, String inviteCode, Long invitor, Long collectionId) {
+    public User phoneRegister(String phone, String code, String password, String inviteCode, Long invitor,
+                              Long collectionId, Long showroomId) {
         String name = "0x" + RandomStringUtils.randomAlphabetic(8);
         Invite invite = null;
         if (StringUtils.isNotBlank(inviteCode)) {
@@ -261,12 +255,25 @@ public class UserService {
         if (invite != null) {
             inviteRepo.increaseNum(invite.getId());
         }
+
+        if (ObjectUtils.isNotEmpty(showroomId)) {
+            //通过展厅的注册数量
+            int weight = sysConfigService.getInt("heat_register_weight");
+            heatInfoRepo.save(HeatInfo.builder()
+                    .showroomId(showroomId)
+                    .userId(user.getId())
+                    .type(HeatType.REGISTER)
+                    .value(weight)
+                    .build());
+            showroomRepo.addHeatAndRegister(showroomId, weight, 1);
+        }
         return user;
     }
 
-    public String mqRegister(String phone, String code, String password, String inviteCode, Long invitor, Long collectionId) {
+    public String mqRegister(String phone, String code, String password, String inviteCode, Long invitor,
+                             Long collectionId, Long showroomId) {
         rocketMQTemplate.convertAndSend(generalProperties.getRegisterTopic(),
-                new RegisterEvent(phone, code, password, inviteCode, invitor, collectionId));
+                new RegisterEvent(phone, code, password, inviteCode, invitor, collectionId, showroomId));
         return phone;
     }
 
@@ -901,4 +908,24 @@ public class UserService {
         user.setWalletEnabled(true);
         save(user);
     }
+
+    public Page<CompanyDTO> companyList(PageQuery pageQuery) {
+        Page<User> users = this.all(pageQuery).toPage();
+        List<Map<String, Object>> companyNums = showroomRepo.countNum("COMPANY");
+        Map<Long, Integer> showroomNum = new HashMap<>();
+        companyNums.forEach(value -> showroomNum.put(Convert.convert(Long.class, value.get("user_id")),
+                Convert.convert(Integer.class, value.get("num"))));
+
+        List<Map<String, Object>> companyBoxNums = showroomRepo.countNum("COMPANY_BOX");
+        Map<Long, Integer> boxNum = new HashMap<>();
+        companyBoxNums.forEach(value -> boxNum.put(Convert.convert(Long.class, value.get("user_id")),
+                Convert.convert(Integer.class, value.get("num"))));
+        return users.map(user -> {
+            CompanyDTO dto = new CompanyDTO(user);
+            dto.setShowroomNum(showroomNum.get(user.getId()) == null ? 0 : showroomNum.get(user.getId()));
+            dto.setBoxShowroomNum(boxNum.get(user.getId()) == null ? 0 : boxNum.get(user.getId()));
+            return dto;
+        });
+    }
+
 }

+ 4 - 8
src/main/java/com/izouma/nineth/web/AuthenticationController.java

@@ -60,24 +60,20 @@ public class AuthenticationController {
     @PostMapping("/phoneRegister")
     @ApiOperation(value = "手机号密码注册")
     public String phonePwdLogin(String phone, String code, String password, String inviteCode, Long invitor,
-                                Long collectionId, String captcha, String captchaKey) {
-//        boolean verify = captchaService.verify(captchaKey, captcha);
-//        if (!verify) {
-//            throw new BusinessException("验证码错误");
-//        }
-        User user = userService.phoneRegister(phone, code, password, inviteCode, invitor, collectionId);
+                                Long collectionId, Long showroomId) {
+        User user = userService.phoneRegister(phone, code, password, inviteCode, invitor, collectionId, showroomId);
         return jwtTokenUtil.generateToken(JwtUserFactory.create(user));
     }
 
     @PostMapping("/mqPhoneRegister")
     @ApiOperation(value = "手机号密码注册")
     public String mqPhoneRegister(String phone, String code, String password, String inviteCode, Long invitor,
-                                  Long collectionId, String captcha, String captchaKey) {
+                                  Long collectionId, Long showroomId) {
 //        boolean verify = captchaService.verify(captchaKey, captcha);
 //        if (!verify) {
 //            throw new BusinessException("验证码错误");
 //        }
-        return userService.mqRegister(phone, code, password, inviteCode, invitor, collectionId);
+        return userService.mqRegister(phone, code, password, inviteCode, invitor, collectionId, showroomId);
     }
 
     @GetMapping("/registerResult")

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

@@ -115,11 +115,12 @@ public class OrderController extends BaseController {
                                             @RequestParam(required = false) Long invitor,
                                             @RequestParam String sign,
                                             @RequestParam(defaultValue = "false") boolean vip,
-                                            @RequestParam(defaultValue = "false") boolean safeFlag) {
+                                            @RequestParam(defaultValue = "false") boolean safeFlag,
+                                            @RequestParam(required = false) Long showroomId) {
         final User user = SecurityUtils.getAuthenticatedUser();
         return new HashMap<>() {{
             put("id", orderService.mqCreate(user.getId(), collectionId, qty, addressId, couponId, invitor, sign,
-                    vip, user.getVipPurchase(), user.getVipPoint(), safeFlag));
+                    vip, safeFlag, showroomId));
         }};
     }
 

+ 13 - 7
src/main/java/com/izouma/nineth/web/ShowroomController.java

@@ -1,13 +1,15 @@
 package com.izouma.nineth.web;
 
 import cn.hutool.core.collection.CollUtil;
-import com.izouma.nineth.domain.*;
 import com.izouma.nineth.domain.Collection;
+import com.izouma.nineth.domain.*;
 import com.izouma.nineth.dto.PageQuery;
 import com.izouma.nineth.enums.AuthStatus;
+import com.izouma.nineth.enums.HeatType;
 import com.izouma.nineth.exception.BusinessException;
 import com.izouma.nineth.repo.*;
 import com.izouma.nineth.service.ShowroomService;
+import com.izouma.nineth.service.SysConfigService;
 import com.izouma.nineth.utils.SecurityUtils;
 import com.izouma.nineth.utils.excel.ExcelUtils;
 import lombok.AllArgsConstructor;
@@ -30,7 +32,8 @@ public class ShowroomController extends BaseController {
     private ShowCollectionRepo showCollectionRepo;
     private NewsLikeRepo       newsLikeRepo;
     private CollectionRepo     collectionRepo;
-    private ViewInfoRepo       viewInfoRepo;
+    private HeatInfoRepo       heatInfoRepo;
+    private SysConfigService   sysConfigService;
 
     @PostMapping("/save")
     public Showroom save(@RequestBody Showroom record) {
@@ -43,8 +46,8 @@ public class ShowroomController extends BaseController {
     }
 
     @PostMapping("/create")
-    public Showroom create(@RequestParam Long userId) {
-        return showroomService.save(userId);
+    public Showroom create(@RequestParam Long userId, @RequestParam String type) {
+        return showroomService.save(userId, type);
     }
 
     @PostMapping("/all")
@@ -141,13 +144,16 @@ public class ShowroomController extends BaseController {
         if (ObjectUtils.isEmpty(userId)) {
             return;
         }
-        List<ViewInfo> list = viewInfoRepo.findByUserIdAndShowroomId(userId, id);
+        List<HeatInfo> list = heatInfoRepo.findByUserIdAndShowroomIdAndType(userId, id, HeatType.VIEW);
         if (!list.isEmpty()) return;
-        viewInfoRepo.save(ViewInfo.builder()
+        int weight = sysConfigService.getInt("heat_view_weight");
+        heatInfoRepo.save(HeatInfo.builder()
                 .userId(userId)
                 .showroomId(id)
+                .type(HeatType.VIEW)
+                .value(weight)
                 .build());
-        showroomRepo.addLike(id, 1);
+        showroomRepo.addHeat(id, weight);
     }
 
 

+ 7 - 0
src/main/java/com/izouma/nineth/web/UserController.java

@@ -320,6 +320,13 @@ public class UserController extends BaseController {
     public void enableWallet() {
         userService.enableWallet(SecurityUtils.getAuthenticatedUser().getId());
     }
+
+    @PreAuthorize("hasAnyRole('ADMIN', 'SHOWROOM')")
+    @PostMapping("/companyAll")
+    public Page<CompanyDTO> companyAll(@RequestBody PageQuery pageQuery) {
+        return userService.companyList(pageQuery);
+    }
+
 }
 
 

+ 80 - 25
src/main/vue/src/views/CompanyList.vue

@@ -37,9 +37,11 @@
                     ></el-image>
                 </template>
             </el-table-column>
+            <el-table-column prop="showroomNum" label="展厅数量"> </el-table-column>
+            <el-table-column prop="boxShowroomNum" label="盲盒展厅数量"> </el-table-column>
             <el-table-column label="操作" align="center" fixed="right" width="180">
                 <template slot-scope="{ row }">
-                    <el-button @click="createShowroom(row)" type="success" size="mini" plain>发放展厅</el-button>
+                    <el-button @click="chooseShowroomType(row)" type="success" size="mini" plain>发放展厅</el-button>
                     <el-button @click="editRow(row)" type="primary" size="mini" plain>编辑</el-button>
                 </template>
             </el-table-column>
@@ -57,6 +59,20 @@
             >
             </el-pagination>
         </div>
+        <el-dialog :visible.sync="showDialog" title="选择类型" width="500px" center>
+            <el-form :model="addShowroom" label-width="100px" size="mini" :rules="rules" ref="form">
+                <el-form-item label="发放类型" prop="type">
+                    <el-radio-group v-model="addShowroom.type">
+                        <el-radio label="COMPANY">普通展厅</el-radio>
+                        <el-radio label="COMPANY_BOX">盲盒展厅</el-radio>
+                    </el-radio-group>
+                </el-form-item>
+                <el-form-item>
+                    <el-button type="primary" size="mini" @click="createShowroom">确定</el-button>
+                    <el-button @click="showDialog = false">取消</el-button>
+                </el-form-item>
+            </el-form>
+        </el-dialog>
     </div>
 </template>
 <script>
@@ -70,8 +86,19 @@ export default {
         return {
             multipleMode: false,
             search: '',
-            url: '/user/adminAll',
-            downloading: false
+            url: '/user/companyAll',
+            downloading: false,
+            showDialog: false,
+            addShowroom: {},
+            rules: {
+                type: [
+                    {
+                        required: true,
+                        message: '请选择类型',
+                        trigger: 'blur'
+                    }
+                ]
+            }
         };
     },
     computed: {
@@ -154,7 +181,7 @@ export default {
                     .then(res => {
                         let el = document.createElement('div');
                         new ClipboardJS(el, {
-                            text: function (trigger) {
+                            text: function(trigger) {
                                 return res;
                             }
                         });
@@ -167,27 +194,55 @@ export default {
                     });
             }
         },
-        createShowroom(row) {
-            this.$confirm('确认发布展厅吗?', '提示', {
-                confirmButtonText: '确定',
-                cancelButtonText: '取消',
-                type: 'warning'
-            })
-                .then(() => {
-                    return this.$http.post('/showroom/create', { userId: row.id });
-                })
-                .then(() => {
-                    this.saving = false;
-                    this.$message.success('成功');
-                    this.getData();
-                })
-                .catch(e => {
-                    console.log(e);
-                    this.saving = false;
-                    if (e !== 'cancel') {
-                        this.$message.error(e.error);
-                    }
-                });
+        chooseShowroomType(row) {
+            this.showDialog = true;
+            this.addShowroom.id = row.id;
+        },
+        createShowroom() {
+            // this.$confirm('确认发布展厅吗?', '提示', {
+            //     confirmButtonText: '确定',
+            //     cancelButtonText: '取消',
+            //     type: 'warning'
+            // })
+            //     .then(() => {
+            //         return this.$http.post('/showroom/create', {
+            //             userId: this.addShowroom.id,
+            //             type: this.addShowroom.type
+            //         });
+            //     })
+            //     .then(() => {
+            //         this.saving = false;
+            //         this.$message.success('成功');
+            //         this.getData();
+            //     })
+            //     .catch(e => {
+            //         console.log(e);
+            //         this.saving = false;
+            //         if (e !== 'cancel') {
+            //             this.$message.error(e.error);
+            //         }
+            //     });
+            this.$refs.form.validate(valid => {
+                if (valid) {
+                    this.$http
+                        .post('/showroom/create', {
+                            userId: this.addShowroom.id,
+                            type: this.addShowroom.type
+                        })
+                        .then(() => {
+                            this.$message.success('成功');
+                            this.showDialog = false;
+                            this.getData();
+                        })
+                        .catch(e => {
+                            this.$message.error(e.error);
+                            this.showDialog = false;
+                            console.log(e);
+                        });
+                } else {
+                    return false;
+                }
+            });
         }
     }
 };

+ 12 - 7
src/main/vue/src/views/ShowroomEdit.vue

@@ -25,15 +25,12 @@
                             disabled
                         ></el-input>
                     </el-form-item>
-                    <el-form-item prop="sort" label="排序">
+                    <!-- <el-form-item prop="sort" label="排序">
                         <el-input-number v-model="formData.sort" :min="0"></el-input-number>
                         <div class="tip">数字越大排序越靠前,相同数值按创建时间倒序排列</div>
-                    </el-form-item>
+                    </el-form-item> -->
                     <el-form-item prop="maxCollection" label="最多藏品数量">
-                        <el-input-number
-                            type="number"
-                            v-model="formData.maxCollection"
-                        ></el-input-number>
+                        <el-input-number type="number" v-model="formData.maxCollection"></el-input-number>
                     </el-form-item>
                     <el-form-item prop="userId" label="用户ID">
                         <el-input-number
@@ -94,6 +91,14 @@
                             <el-table-column prop="name" label="名称"></el-table-column>
                         </el-table>
                     </el-form-item>
+                    <div class="inline-wrapper">
+                        <el-form-item prop="heats" label="热力值">
+                            <el-input-number type="number" v-model="formData.heats" disabled></el-input-number>
+                        </el-form-item>
+                        <el-form-item prop="registers" label="邀请数量">
+                            <el-input-number type="number" v-model="formData.registers" disabled></el-input-number>
+                        </el-form-item>
+                    </div>
                     <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">
@@ -198,4 +203,4 @@ export default {
     color: @text3;
     margin-top: 5px;
 }
-</style>
+</style>

+ 36 - 27
src/main/vue/src/views/ShowroomList.vue

@@ -48,7 +48,7 @@
             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="id" label="ID" width="80"> </el-table-column>
             <el-table-column prop="userId" label="用户ID"> </el-table-column>
             <el-table-column prop="nickname" label="昵称"> </el-table-column>
             <el-table-column prop="pic" label="logo">
@@ -63,31 +63,15 @@
             </el-table-column>
             <el-table-column prop="introduction" label="简介"> </el-table-column>
             <el-table-column prop="likes" label="点赞"> </el-table-column>
-            <el-table-column prop="sort" label="排序"></el-table-column>
+            <el-table-column prop="registers" label="邀请数"> </el-table-column>
+            <el-table-column prop="heats" label="热力值"></el-table-column>
+            <!-- <el-table-column prop="sort" label="排序"></el-table-column> -->
             <!-- <el-table-column prop="maxCollection" label="最多可放藏品数量"> </el-table-column> -->
-            <!-- <el-table-column prop="headBg" label="头部背景">
-                <template slot-scope="{ row }">
-                    <el-image
-                        style="width: 30px; height: 30px"
-                        :src="row.headBg"
-                        fit="cover"
-                        :preview-src-list="[row.headBg]"
-                    ></el-image>
-                </template>
-            </el-table-column>
-            <el-table-column prop="showroomBg" label="展厅背景">
-                <template slot-scope="{ row }">
-                    <el-image
-                        style="width: 30px; height: 30px"
-                        :src="row.showroomBg"
-                        fit="cover"
-                        :preview-src-list="[row.showroomBg]"
-                    ></el-image>
-                </template>
-            </el-table-column> -->
+            <el-table-column prop="type" label="类型" :formatter="typeFormatter"></el-table-column>
             <el-table-column prop="status" label="状态" :formatter="statusFormatter"> </el-table-column>
-            <el-table-column label="操作" align="center" fixed="right" width="210">
+            <el-table-column label="操作" align="center" fixed="right" width="280">
                 <template slot-scope="{ row, $index }">
+                    <el-button size="mini" @click="showCode(row)" plain>预览</el-button>
                     <el-button @click="editRow(row)" type="primary" size="mini" plain>查看</el-button>
                     <!-- <el-button @click="deleteRow(row)" type="danger" size="mini" plain>删除</el-button> -->
                     <el-button
@@ -146,15 +130,21 @@
                 <el-button type="primary" @click="saveReason">保存</el-button>
             </div>
         </el-dialog>
+
+        <el-dialog :visible.sync="showCodeDialog" title="预览二维码" width="400px" center>
+            <vue-qrcode :value="codeValue" :options="{ width: 300, margin: 2 }" style="margin-left: 25px"></vue-qrcode>
+            <div style="margin-left: 40px; font-size: 16px">扫码预览展厅</div>
+        </el-dialog>
     </div>
 </template>
 <script>
 import { mapState } from 'vuex';
 import pageableTable from '@/mixins/pageableTable';
-
+import VueQrcode from '@chenfengyuan/vue-qrcode';
 export default {
     name: 'ShowroomList',
     mixins: [pageableTable],
+    components: { VueQrcode },
     data() {
         return {
             multipleMode: false,
@@ -173,7 +163,13 @@ export default {
                 reason: [{ required: true, message: '请填写理由' }]
             },
             status: 'PENDING',
-            saving: false
+            saving: false,
+            showCodeDialog: false,
+            codeValue: 'Hello, World!',
+            typeOptions: [
+                { label: '普通展厅', value: 'COMPANY' },
+                { label: '盲盒展厅', value: 'COMPANY_BOX' }
+            ]
         };
     },
     computed: {
@@ -197,11 +193,18 @@ export default {
             }
             return '';
         },
+        typeFormatter(row, column, cellValue, index) {
+            let selectedOption = this.typeOptions.find(i => i.value === cellValue);
+            if (selectedOption) {
+                return selectedOption.label;
+            }
+            return '';
+        },
         beforeGetData() {
             return {
-                sort: 'sort,desc;id,desc',
+                sort: 'heats,desc;id,desc',
                 search: this.search,
-                query: { del: false, type: 'COMPANY', status: this.status }
+                query: { del: false, type: ['COMPANY', 'COMPANY_BOX'], status: this.status }
             };
         },
         toggleMultipleMode(multipleMode) {
@@ -312,6 +315,12 @@ export default {
                 .catch(e => {
                     this.tableData[this.denyForm.index].saving = false;
                 });
+        },
+        showCode(row) {
+            this.codeValue = this.$baseUrl + '9th/hall?id=' + row.id;
+            // this.codeValue = 'https://nfttest.raex.vip/9th/hall?id=' + row.id;
+            this.showCodeDialog = true;
+            console.log(this.codeValue);
         }
     }
 };

+ 6 - 2
src/main/vue/src/views/company/CompanyCollectionShelf.vue

@@ -143,11 +143,15 @@
                             <div class="tip">相同识别码的藏品共享限购数量</div>
                         </el-form-item>
                     </div>
-                    <el-form-item prop="onShelf" label="上架">
+                    <el-form-item prop="scanCode" label="仅扫码可见">
+                        <el-radio v-model="formData.scanCode" :label="true">是</el-radio>
+                        <el-radio v-model="formData.scanCode" :label="false">否</el-radio>
+                    </el-form-item>
+                    <el-form-item prop="onShelf" label="上架" v-if="!formData.scanCode">
                         <el-radio v-model="formData.onShelf" :label="true">是</el-radio>
                         <el-radio v-model="formData.onShelf" :label="false">否</el-radio>
                     </el-form-item>
-                    <el-form-item prop="salable" label="可售" v-if="formData.onShelf === true">
+                    <el-form-item prop="salable" label="可售" v-if="formData.onShelf === true || formData.scanCode === true ">
                         <el-radio v-model="formData.salable" :label="true">是</el-radio>
                         <el-radio v-model="formData.salable" :label="false">仅展示</el-radio>
                     </el-form-item>

+ 81 - 11
src/main/vue/src/views/company/CompanyRoomEdit.vue

@@ -60,6 +60,7 @@
                                 :value="item.id"
                             ></el-option>
                         </el-select>
+                        <!-- <el-link style="margin-left: 20px" @click="preview">展厅预览</el-link> -->
                     </el-form-item>
                     <el-form-item prop="headBg" label="背景" v-if="formData.settingId">
                         <el-image :src="formData.headBg" style="height: 170px"></el-image>
@@ -83,8 +84,18 @@
                                 </template>
                             </el-table-column>
                         </el-table>
-                        <el-button @click="addCollection" size="mini">添加</el-button>
+                        <el-button @click="addCollection" size="mini" v-if="formData.maxCollection > collectionSize"
+                            >添加</el-button
+                        >
                     </el-form-item>
+                    <div class="inline-wrapper">
+                        <el-form-item prop="heats" label="热力值">
+                            <el-input-number type="number" v-model="formData.heats" disabled></el-input-number>
+                        </el-form-item>
+                        <el-form-item prop="registers" label="邀请数量">
+                            <el-input-number type="number" v-model="formData.registers" disabled></el-input-number>
+                        </el-form-item>
+                    </div>
                     <!-- <el-form-item prop="publish" label="发布" v-if="formData.status == 'SUCCESS'">
                         <el-radio v-model="formData.publish" :label="true">是</el-radio>
                         <el-radio v-model="formData.publish" :label="false">否</el-radio>
@@ -124,12 +135,20 @@
                     <el-button type="primary" size="mini" @click="saveCollection">确定</el-button>
                 </div>
             </el-dialog>
+
+            <el-dialog title="添加盲盒" :visible.sync="showBoxDialog" width="500px">
+                <div style="margin-bottom: 10px">输入盲盒ID</div>
+                <el-input placeholder="请输入盲盒ID" v-model="boxId" style="width: 220px"></el-input>
+                <div slot="footer">
+                    <el-button @click="showBoxDialog = false">取消</el-button>
+                    <el-button type="primary" size="mini" @click="saveBox">确定</el-button>
+                </div>
+            </el-dialog>
         </div>
     </div>
 </template>
 <script>
 import { mapState } from 'vuex';
-
 export default {
     name: 'ShowroomEdit',
     created() {
@@ -138,6 +157,7 @@ export default {
                 .get('showroom/get/' + this.$route.query.id)
                 .then(res => {
                     this.formData = res;
+                    this.collectionSize = res.collections.length;
                 })
                 .catch(e => {
                     console.log(e);
@@ -170,7 +190,7 @@ export default {
         return {
             saving: false,
             formData: {
-                showCollections: []
+                collections: []
             },
             rules: {},
             statusOptions: [
@@ -182,7 +202,10 @@ export default {
             settings: [],
             collections: [],
             showCollectionDialog: false,
-            collectionId: ''
+            collectionId: '',
+            showBoxDialog: false,
+            boxId: '',
+            collectionSize: 0
         };
     },
     computed: {
@@ -248,17 +271,27 @@ export default {
             this.formData.showroomBg = data.description;
         },
         addCollection() {
-            this.showCollectionDialog = true;
-            if (this.$refs.collectionForm) {
-                this.$nextTick(() => {
-                    this.$refs.collectionForm.clearValidate();
-                });
+            if (this.collectionSize >= this.formData.maxCollection) {
+                this.$message.error('最多只能添加' + this.formData.maxCollection + '个!');
+            } else {
+                if (this.formData.type === 'COMPANY_BOX') {
+                    this.showBoxDialog = true;
+                } else {
+                    this.showCollectionDialog = true;
+                }
+
+                if (this.$refs.collectionForm) {
+                    this.$nextTick(() => {
+                        this.$refs.collectionForm.clearValidate();
+                    });
+                }
             }
         },
         delCollection(index) {
             this.formData.collections.splice(index, 1);
+            this.collectionSize = this.formData.collections.length;
         },
-        saveCollection(res) {
+        saveCollection() {
             this.$refs.collectionForm
                 .validate()
                 .then(() => {
@@ -280,11 +313,43 @@ export default {
                             });
                         }
                         this.showCollectionDialog = false;
+                        this.collectionSize = this.formData.collections.length;
                     } else {
                         this.$message.error('请勿重复添加');
                     }
                 })
                 .catch(() => {});
+        },
+        saveBox() {
+            this.$http
+                .get('collection/get/' + this.boxId)
+                .then(res => {
+                    if (res.type !== 'BLIND_BOX') {
+                        this.$message.error('此为藏品ID,请添加盲盒ID');
+                        return;
+                    }
+                    this.formData.collections.push({
+                        showroomId: this.formData.id,
+                        collectionId: res.id,
+                        pic: res.pic[0].url,
+                        name: res.name
+                    });
+                    this.collectionSize = this.formData.collections.length;
+                    this.showBoxDialog = false;
+                })
+                .catch(e => {
+                    if (e.error === '无记录') {
+                        this.$message.error('没有此盲盒,请核对盲盒ID');
+                    } else {
+                        this.$message.error(e.error);
+                    }
+                    this.showBoxDialog = false;
+                    console.log(e);
+                });
+        },
+        preview() {
+            let url = '/9th/hall?id=' + this.formData.id;
+            window.open(url);
         }
     }
 };
@@ -296,4 +361,9 @@ export default {
 /deep/.el-textarea.is-disabled .el-textarea__inner {
     color: #7c7e7e;
 }
-</style>
+.inline-wrapper {
+    .el-form-item {
+        display: inline-block;
+    }
+}
+</style>

+ 31 - 2
src/main/vue/src/views/company/CompanyRoomList.vue

@@ -44,10 +44,14 @@
                 </template>
             </el-table-column> -->
             <el-table-column prop="likes" label="点赞"> </el-table-column>
+            <el-table-column prop="registers" label="邀请数"> </el-table-column>
+            <el-table-column prop="heats" label="热力值"></el-table-column>
+            <el-table-column prop="type" label="类型" :formatter="typeFormatter"></el-table-column>
             <el-table-column prop="status" label="状态" :formatter="statusFormatter"> </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 size="mini" @click="showCode(row)" type="success" plain>预览</el-button>
                 </template>
             </el-table-column>
         </el-table>
@@ -72,15 +76,21 @@
             >
             </el-pagination>
         </div>
+
+        <el-dialog :visible.sync="showCodeDialog" title="预览二维码" width="400px" center>
+            <vue-qrcode :value="codeValue" :options="{ width: 300, margin: 2 }" style="margin-left: 25px"></vue-qrcode>
+            <div style="margin-left: 40px; font-size: 16px">扫码预览展厅</div>
+        </el-dialog>
     </div>
 </template>
 <script>
 import { mapState } from 'vuex';
 import pageableTable from '@/mixins/pageableTable';
-
+import VueQrcode from '@chenfengyuan/vue-qrcode';
 export default {
     name: 'ShowroomList',
     mixins: [pageableTable],
+    components: { VueQrcode },
     data() {
         return {
             multipleMode: false,
@@ -92,7 +102,13 @@ export default {
                 { label: '审核中', value: 'PENDING' },
                 { label: '已审核', value: 'SUCCESS' },
                 { label: '失败', value: 'FAIL' }
-            ]
+            ],
+            showCodeDialog: false,
+            codeValue: 'Hello, World!',
+            typeOptions: [
+                { label: '普通展厅', value: 'COMPANY' },
+                { label: '盲盒展厅', value: 'COMPANY_BOX' }
+            ],
         };
     },
     computed: {
@@ -109,6 +125,13 @@ export default {
             }
             return '';
         },
+        typeFormatter(row, column, cellValue, index) {
+            let selectedOption = this.typeOptions.find(i => i.value === cellValue);
+            if (selectedOption) {
+                return selectedOption.label;
+            }
+            return '';
+        },
         beforeGetData() {
             return { search: this.search, query: { del: false, userId: this.userInfo.id } };
         },
@@ -181,6 +204,12 @@ export default {
                         this.$message.error(e.error);
                     }
                 });
+        },
+        showCode(row) {
+            this.codeValue = this.$baseUrl + '/9th/hall?id=' + row.id;
+            // this.codeValue = 'https://nfttest.raex.vip/9th/hall?id=' + row.id;
+            this.showCodeDialog = true;
+            console.log(this.codeValue);
         }
     }
 };

+ 2 - 1
src/test/java/com/izouma/nineth/service/UserServiceTest.java

@@ -119,7 +119,8 @@ public class UserServiceTest extends ApplicationTests {
 
     @Test
     public void phoneRegister() {
-        userService.phoneRegister("18100004444", "1234", "123456", null, 9972L, 206925L);
+        userService.phoneRegister("18100004444", "1234", "123456", null, 9972L,
+                206925L, null);
     }
 
     @Test