ソースを参照

Merge branch 'dev' of xiongzhu/9th into master

panhui 4 年 前
コミット
e902dcf88d
35 ファイル変更1290 行追加370 行削除
  1. 10 26
      src/main/comos/src/views/Givesubmit.vue
  2. 1 1
      src/main/comos/src/views/order/CouponList.vue
  3. 8 1
      src/main/comos/src/views/user/Exchange.vue
  4. 9 5
      src/main/comos/src/views/user/Followers.vue
  5. 9 5
      src/main/comos/src/views/user/Follows.vue
  6. 9 5
      src/main/comos/src/views/user/Likes.vue
  7. 2 0
      src/main/java/com/izouma/nineth/TokenHistory.java
  8. 8 3
      src/main/java/com/izouma/nineth/domain/Asset.java
  9. 6 0
      src/main/java/com/izouma/nineth/domain/GiftOrder.java
  10. 5 0
      src/main/java/com/izouma/nineth/domain/Order.java
  11. 68 0
      src/main/java/com/izouma/nineth/dto/GiftOrderDTO.java
  12. 8 0
      src/main/java/com/izouma/nineth/repo/GiftOrderRepo.java
  13. 4 0
      src/main/java/com/izouma/nineth/repo/TokenHistoryRepo.java
  14. 7 2
      src/main/java/com/izouma/nineth/service/AssetService.java
  15. 11 0
      src/main/java/com/izouma/nineth/service/GiftOrderService.java
  16. 1 0
      src/main/java/com/izouma/nineth/service/OrderService.java
  17. 2 2
      src/main/java/com/izouma/nineth/web/AssetController.java
  18. 74 0
      src/main/java/com/izouma/nineth/web/GiftOrderController.java
  19. 8 1
      src/main/modern-point/src/views/user/Exchange.vue
  20. 9 5
      src/main/modern-point/src/views/user/Followers.vue
  21. 9 5
      src/main/modern-point/src/views/user/Follows.vue
  22. 9 5
      src/main/modern-point/src/views/user/Likes.vue
  23. 7 0
      src/main/nine-space/src/views/user/Exchange.vue
  24. 9 5
      src/main/nine-space/src/views/user/Followers.vue
  25. 10 6
      src/main/nine-space/src/views/user/Follows.vue
  26. 9 5
      src/main/nine-space/src/views/user/Likes.vue
  27. 0 0
      src/main/resources/genjson/GiftOrder.json
  28. 25 1
      src/main/vue/src/router.js
  29. 147 119
      src/main/vue/src/views/AssetEdit.vue
  30. 157 166
      src/main/vue/src/views/AssetList.vue
  31. 179 0
      src/main/vue/src/views/GiftOrderEdit.vue
  32. 226 0
      src/main/vue/src/views/GiftOrderList.vue
  33. 1 1
      src/main/vue/src/views/OrderList.vue
  34. 236 0
      src/main/vue/src/views/OrderUsedList.vue
  35. 7 1
      src/test/java/com/izouma/nineth/service/AssetServiceTest.java

+ 10 - 26
src/main/comos/src/views/Givesubmit.vue

@@ -206,38 +206,22 @@ export default {
                     this.$http
                         .post('/asset/gift', {
                             assetId: this.$route.query.id,
-                            toUserId: this.$route.query.toUserId
+                            toUserId: this.$route.query.toUserId,
+                            projectId: this.$store.state.projectId
                         })
                         .then(res => {
                             this.orderId = res.id;
                             this.$nextTick(() => {
                                 if (this.payType === 'ALIPAY') {
-                                    // document.location.replace(
-                                    //     resolveUrl(this.$baseUrl, 'payOrder/gift/alipay?id=' + res.id)
-                                    // );
-                                    this.$http
-                                        .get(`/payOrder/gift/${this.inApp ? 'alipay_app' : 'alipay_h5'}?id=${res.id}`)
-                                        .then(res => {
-                                            this.hrefUrl = 'alipays://platformapi/startapp?saId=10000007&qrcode=' + res;
-                                            // window.open(
-                                            //     'alipays://platformapi/startapp?saId=10000007&qrcode=' + res,
-                                            //     '_blank'
-                                            // );
-                                            this.$nextTick(() => {
-                                                document.getElementById('pay').click();
-                                            });
+                                    document.location.replace(
+                                        resolveUrl(this.$baseUrl, 'payOrder/gift/alipay?id=' + res.id)
+                                    );
+                                    this.$toast.loading({
+                                        message: '加载中...',
+                                        forbidClick: true
+                                    });
 
-                                            this.$toast.loading({
-                                                message: '加载中...',
-                                                forbidClick: true
-                                            });
-                                            this.getOrder(true);
-                                        })
-                                        .catch(e => {
-                                            if (e.error) {
-                                                this.$toast(e.error);
-                                            }
-                                        });
+                                    this.getOrder(true);
                                 } else if (this.payType === 'WEIXIN') {
                                     if (this.inWeixin) {
                                         this.$toast.loading('加载中');

+ 1 - 1
src/main/comos/src/views/order/CouponList.vue

@@ -70,7 +70,7 @@ export default {
         },
         beforeData() {
             return {
-                query: { userId: this.$store.state.userInfo.id, used: false }
+                query: { userId: this.$store.state.userInfo.id, used: false, projectId: this.$store.state.projectId }
             };
         }
     }

+ 8 - 1
src/main/comos/src/views/user/Exchange.vue

@@ -38,6 +38,13 @@ export default {
             url: '/asset/userHistory',
             httpType: 'get'
         };
+    },
+    methods: {
+        beforeData() {
+            return {
+                projectId: this.$store.state.projectId
+            };
+        }
     }
 };
 </script>
@@ -64,7 +71,7 @@ export default {
     .van-ellipsis {
         margin-bottom: 2px;
     }
-    border-top: 1px solid #202122;
+    border-top: 1px solid #f2f4f5;
 
     .top {
         .flex();

+ 9 - 5
src/main/comos/src/views/user/Followers.vue

@@ -31,11 +31,15 @@ export default {
             forbidClick: true
         });
         this.empty = false;
-        this.$http.get('/user/myFollowers').then(res => {
-            this.list = res;
-            this.empty = res.length === 0;
-            this.$toast.clear();
-        });
+        this.$http
+            .get('/user/myFollowers', {
+                projectId: this.$store.state.projectId
+            })
+            .then(res => {
+                this.list = res;
+                this.empty = res.length === 0;
+                this.$toast.clear();
+            });
     }
 };
 </script>

+ 9 - 5
src/main/comos/src/views/user/Follows.vue

@@ -46,11 +46,15 @@ export default {
                 forbidClick: true
             });
             this.empty = false;
-            this.$http.get('/user/myFollows').then(res => {
-                this.list = res;
-                this.empty = res.length === 0;
-                this.$toast.clear();
-            });
+            this.$http
+                .get('/user/myFollows', {
+                    projectId: this.$store.state.projectId
+                })
+                .then(res => {
+                    this.list = res;
+                    this.empty = res.length === 0;
+                    this.$toast.clear();
+                });
         }
     }
 };

+ 9 - 5
src/main/comos/src/views/user/Likes.vue

@@ -76,11 +76,15 @@ export default {
                 forbidClick: true
             });
             this.empty = false;
-            this.$http.get('/collection/myLikes').then(res => {
-                this.list = res;
-                this.empty = res.length === 0;
-                this.$toast.clear();
-            });
+            this.$http
+                .get('/collection/myLikes', {
+                    projectId: this.$store.state.projectId
+                })
+                .then(res => {
+                    this.list = res;
+                    this.empty = res.length === 0;
+                    this.$toast.clear();
+                });
         },
         change() {
             this.$root.$el.scrollTop = 0;

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

@@ -35,4 +35,6 @@ public class TokenHistory extends BaseEntity {
     private Long   toUserId;
 
     private String toAvatar;
+
+    private int projectId;
 }

+ 8 - 3
src/main/java/com/izouma/nineth/domain/Asset.java

@@ -16,6 +16,7 @@ import lombok.NoArgsConstructor;
 import javax.persistence.*;
 import java.math.BigDecimal;
 import java.math.BigInteger;
+import java.time.LocalDateTime;
 import java.util.List;
 
 
@@ -33,6 +34,7 @@ public class Asset extends BaseEntity {
     @ApiModelProperty("持有者")
     private String ownerName;
 
+    @Searchable
     @ApiModelProperty("藏品ID")
     private Long collectionId;
 
@@ -43,7 +45,7 @@ public class Asset extends BaseEntity {
     private Integer number;
 
     @ApiModelProperty("名称")
-    @Searchable
+//    @Searchable
     private String name;
 
     @ApiModelProperty("详情")
@@ -73,7 +75,7 @@ public class Asset extends BaseEntity {
     private int serviceCharge;
 
     @ApiModelProperty("铸造者")
-    @Searchable
+//    @Searchable
     private String minter;
 
     @ApiModelProperty("铸造者ID")
@@ -83,7 +85,7 @@ public class Asset extends BaseEntity {
     private String minterAvatar;
 
     @ApiModelProperty("持有者")
-    @Searchable
+//    @Searchable
     private String owner;
 
     @ApiModelProperty("持有者ID")
@@ -149,6 +151,9 @@ public class Asset extends BaseEntity {
 
     private Long fromAssetId;
 
+    @ApiModelProperty("交易时间")
+    private LocalDateTime outTime;
+
     private int projectId;
 
     public static Asset create(Collection collection, User user) {

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

@@ -27,6 +27,10 @@ public class GiftOrder extends BaseEntity {
 
     private Long assetId;
 
+    private Long collectionId;
+
+    private String name;
+
     private Long toUserId;
 
     @Enumerated(EnumType.STRING)
@@ -54,4 +58,6 @@ public class GiftOrder extends BaseEntity {
 
     @ApiModelProperty("区块高度")
     private BigInteger blockNumber;
+
+    private int projectId;
 }

+ 5 - 0
src/main/java/com/izouma/nineth/domain/Order.java

@@ -4,6 +4,7 @@ import com.izouma.nineth.annotations.Searchable;
 import com.izouma.nineth.converter.FileObjectListConverter;
 import com.izouma.nineth.converter.PrivilegeListConverter;
 import com.izouma.nineth.converter.PropertyListConverter;
+import com.izouma.nineth.enums.CollectionSource;
 import com.izouma.nineth.enums.CollectionType;
 import com.izouma.nineth.enums.OrderStatus;
 import com.izouma.nineth.enums.PayMethod;
@@ -79,6 +80,10 @@ public class Order extends BaseEntity {
     @Enumerated(EnumType.STRING)
     private CollectionType type;
 
+    @ApiModelProperty("来源")
+    @Enumerated(EnumType.STRING)
+    private CollectionSource source;
+
     @ApiModelProperty("铸造者")
     @Searchable
     private String minter;

+ 68 - 0
src/main/java/com/izouma/nineth/dto/GiftOrderDTO.java

@@ -0,0 +1,68 @@
+package com.izouma.nineth.dto;
+
+import com.alibaba.excel.annotation.ExcelProperty;
+import com.izouma.nineth.annotations.Searchable;
+import com.izouma.nineth.domain.GiftOrder;
+import lombok.Data;
+import org.springframework.beans.BeanUtils;
+
+import javax.persistence.Column;
+import javax.persistence.EnumType;
+import javax.persistence.Enumerated;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.time.LocalDateTime;
+
+@Data
+public class GiftOrderDTO {
+    @ExcelProperty("ID")
+    private Long id;
+
+    @ExcelProperty("赠送用户ID")
+    private Long userId;
+
+    @ExcelProperty("赠送用户昵称")
+    private String nickname;
+
+    @ExcelProperty("藏品ID")
+    private Long collectionId;
+
+    @ExcelProperty("名称")
+    private String name;
+
+    @ExcelProperty("收到用户ID")
+    private Long toUserId;
+
+    @ExcelProperty("收到用户昵称")
+    private String toNickname;
+
+    @ExcelProperty("支付方式")
+    private String payMethod;
+
+    @ExcelProperty("状态")
+    private String status;
+
+    @ExcelProperty("gas费")
+    @Column(precision = 10, scale = 2)
+    private BigDecimal gasPrice;
+
+    @ExcelProperty("交易ID")
+    @Searchable
+    private String transactionId;
+
+    @ExcelProperty("支付时间")
+    private LocalDateTime payTime;
+
+    @ExcelProperty("交易hash")
+    private String txHash;
+
+    @ExcelProperty("消耗gas")
+    private BigInteger gasUsed;
+
+    @ExcelProperty("区块高度")
+    private BigInteger blockNumber;
+
+    public GiftOrderDTO(GiftOrder go) {
+        BeanUtils.copyProperties(go, this);
+    }
+}

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

@@ -4,10 +4,18 @@ import com.izouma.nineth.domain.GiftOrder;
 import com.izouma.nineth.enums.OrderStatus;
 import org.springframework.data.jpa.repository.JpaRepository;
 import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
+import org.springframework.data.jpa.repository.Modifying;
+import org.springframework.data.jpa.repository.Query;
 
+import javax.transaction.Transactional;
 import java.time.LocalDateTime;
 import java.util.List;
 
 public interface GiftOrderRepo extends JpaRepository<GiftOrder, Long>, JpaSpecificationExecutor<GiftOrder> {
     List<GiftOrder> findByStatusAndCreatedAtBeforeAndDelFalse(OrderStatus status, LocalDateTime time);
+
+    @Query("update GiftOrder t set t.del = true where t.id = ?1")
+    @Modifying
+    @Transactional
+    void softDelete(Long id);
 }

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

@@ -17,6 +17,10 @@ public interface TokenHistoryRepo extends JpaRepository<TokenHistory, Long>, Jpa
     @Query("select t from TokenHistory t where t.toUserId = ?1 or t.fromUserId = ?1 order by t.createdAt desc")
     Page<TokenHistory> userHistory(Long userId, Pageable pageable);
 
+    @Query("select t from TokenHistory t where t.projectId = ?2 and (t.toUserId = ?1 or t.fromUserId = ?1) order by t.createdAt desc")
+    Page<TokenHistory> userHistoryAndProjectId(Long userId, int projectId, Pageable pageable);
+
+
     @Transactional
     @Modifying
     int deleteByTokenId(String tokenId);

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

@@ -68,6 +68,7 @@ public class AssetService {
                 .toAvatar(user.getAvatar())
                 .operation(type)
                 .price(price)
+                .projectId(asset.getProjectId())
                 .build());
         assetMintService.mint(asset);
         return asset;
@@ -91,6 +92,7 @@ public class AssetService {
                 .toAvatar(user.getAvatar())
                 .operation(type)
                 .price(price)
+                .projectId(asset.getProjectId())
                 .build());
         assetMintService.mint(asset.getId(), user.getId());
         return asset;
@@ -290,6 +292,7 @@ public class AssetService {
                 .toAvatar(toUser.getAvatar())
                 .operation(reason)
                 .price("转赠".equals(reason) ? null : price)
+                .projectId(asset.getProjectId())
                 .build());
 
         asset.setPublicShow(false);
@@ -299,6 +302,7 @@ public class AssetService {
         asset.setOwner(toUser.getNickname());
         asset.setOwnerId(toUser.getId());
         asset.setOwnerAvatar(toUser.getAvatar());
+        asset.setOutTime(LocalDateTime.now());
         assetRepo.save(asset);
 
         if (orderId != null) {
@@ -337,6 +341,7 @@ public class AssetService {
                         .toAvatar(owner.getAvatar())
                         .operation("出售")
                         .price(order.getPrice())
+                        .projectId(asset.getProjectId())
                         .build();
                 t.setCreatedAt(asset.getCreatedAt());
                 tokenHistoryRepo.save(t);
@@ -345,8 +350,8 @@ public class AssetService {
         });
     }
 
-    public Page<UserHistory> userHistory(Long userId, Pageable pageable) {
-        Page<TokenHistory> page = tokenHistoryRepo.userHistory(userId, pageable);
+    public Page<UserHistory> userHistory(Long userId, int projectId, Pageable pageable) {
+        Page<TokenHistory> page = tokenHistoryRepo.userHistoryAndProjectId(userId, projectId, pageable);
         Set<String> tokenIds = page.stream().map(TokenHistory::getTokenId).collect(Collectors.toSet());
         List<Asset> assets = tokenIds.isEmpty() ? new ArrayList<>() : assetRepo.findByTokenIdIn(tokenIds);
         return page.map(tokenHistory -> {

+ 11 - 0
src/main/java/com/izouma/nineth/service/GiftOrderService.java

@@ -18,7 +18,9 @@ import com.izouma.nineth.config.GeneralProperties;
 import com.izouma.nineth.config.WxPayProperties;
 import com.izouma.nineth.domain.Asset;
 import com.izouma.nineth.domain.GiftOrder;
+import com.izouma.nineth.domain.Order;
 import com.izouma.nineth.domain.User;
+import com.izouma.nineth.dto.PageQuery;
 import com.izouma.nineth.enums.AssetStatus;
 import com.izouma.nineth.enums.OrderStatus;
 import com.izouma.nineth.enums.PayMethod;
@@ -26,12 +28,14 @@ import com.izouma.nineth.exception.BusinessException;
 import com.izouma.nineth.repo.AssetRepo;
 import com.izouma.nineth.repo.GiftOrderRepo;
 import com.izouma.nineth.repo.UserRepo;
+import com.izouma.nineth.utils.JpaUtils;
 import com.izouma.nineth.utils.SnowflakeIdWorker;
 import lombok.AllArgsConstructor;
 import org.apache.commons.codec.EncoderException;
 import org.apache.commons.codec.net.URLCodec;
 import org.apache.commons.lang3.StringUtils;
 import org.springframework.core.env.Environment;
+import org.springframework.data.domain.Page;
 import org.springframework.scheduling.annotation.Scheduled;
 import org.springframework.stereotype.Service;
 import org.springframework.ui.Model;
@@ -88,9 +92,12 @@ public class GiftOrderService {
         GiftOrder giftOrder = GiftOrder.builder()
                 .userId(userId)
                 .assetId(assetId)
+                .collectionId(asset.getCollectionId())
+                .name(asset.getName())
                 .toUserId(toUserId)
                 .gasPrice(sysConfigService.getBigDecimal("gas_fee"))
                 .status(OrderStatus.NOT_PAID)
+                .projectId(asset.getProjectId())
                 .build();
         return giftOrderRepo.save(giftOrder);
     }
@@ -249,4 +256,8 @@ public class GiftOrderService {
         order.setCancelTime(LocalDateTime.now());
         giftOrderRepo.save(order);
     }
+
+    public Page<GiftOrder> all(PageQuery pageQuery) {
+        return giftOrderRepo.findAll(JpaUtils.toSpecification(pageQuery, GiftOrder.class), JpaUtils.toPageRequest(pageQuery));
+    }
 }

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

@@ -137,6 +137,7 @@ public class OrderService {
                 .royalties(collection.getRoyalties())
                 .serviceCharge(collection.getServiceCharge())
                 .type(collection.getType())
+                .source(collection.getSource())
                 .minterId(collection.getMinterId())
                 .minter(minter.getNickname())
                 .minterAvatar(minter.getAvatar())

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

@@ -117,8 +117,8 @@ public class AssetController extends BaseController {
 
     @GetMapping("/userHistory")
     @ApiOperation("交易历史")
-    public Page<UserHistory> userHistory(Pageable pageable) {
-        return assetService.userHistory(SecurityUtils.getAuthenticatedUser().getId(), pageable);
+    public Page<UserHistory> userHistory(int projectId, Pageable pageable) {
+        return assetService.userHistory(SecurityUtils.getAuthenticatedUser().getId(), projectId, pageable);
     }
 
     @PostMapping("/holdQuery")

+ 74 - 0
src/main/java/com/izouma/nineth/web/GiftOrderController.java

@@ -0,0 +1,74 @@
+package com.izouma.nineth.web;
+
+import com.izouma.nineth.domain.GiftOrder;
+import com.izouma.nineth.domain.User;
+import com.izouma.nineth.dto.GiftOrderDTO;
+import com.izouma.nineth.dto.PageQuery;
+import com.izouma.nineth.exception.BusinessException;
+import com.izouma.nineth.repo.GiftOrderRepo;
+import com.izouma.nineth.repo.UserRepo;
+import com.izouma.nineth.service.GiftOrderService;
+import com.izouma.nineth.utils.excel.ExcelUtils;
+import lombok.AllArgsConstructor;
+import org.springframework.data.domain.Page;
+import org.springframework.web.bind.annotation.*;
+
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+@RestController
+@RequestMapping("/giftOrder")
+@AllArgsConstructor
+public class GiftOrderController extends BaseController {
+    private GiftOrderService giftOrderService;
+    private GiftOrderRepo    giftOrderRepo;
+    private UserRepo         userRepo;
+
+
+    //@PreAuthorize("hasRole('ADMIN')")
+    @PostMapping("/all")
+    public Page<GiftOrderDTO> all(@RequestBody PageQuery pageQuery) {
+        Page<GiftOrder> all = giftOrderService.all(pageQuery);
+        Set<Long> userIds = new HashSet<>();
+        all.getContent().forEach(go -> {
+            userIds.add(go.getUserId());
+            userIds.add(go.getToUserId());
+        });
+        Map<Long, String> userMap = userRepo.findByIdInAndDelFalse(userIds)
+                .stream()
+                .collect(Collectors.toMap(User::getId, User::getNickname));
+        return all.map(go -> {
+            GiftOrderDTO dto = new GiftOrderDTO(go);
+            dto.setNickname(userMap.get(go.getUserId()));
+            dto.setToNickname(userMap.get(go.getToUserId()));
+            dto.setStatus(go.getStatus() == null ? "" :go.getStatus().getDescription());
+            dto.setPayMethod(go.getPayMethod() == null ? "" : go.getPayMethod().getDescription());
+            return dto;
+        });
+    }
+
+    @GetMapping("/get/{id}")
+    public GiftOrder get(@PathVariable Long id) {
+        return giftOrderRepo.findById(id).orElseThrow(new BusinessException("无记录"));
+    }
+
+    @PostMapping("/del/{id}")
+    public void del(@PathVariable Long id) {
+        giftOrderRepo.softDelete(id);
+    }
+
+    @PostMapping("/excel")
+    @ResponseBody
+    public void excel(HttpServletResponse response, @RequestBody PageQuery pageQuery) throws IOException {
+        List<GiftOrderDTO> data = all(pageQuery).getContent();
+        ExcelUtils.export(response, data);
+    }
+
+
+}
+

+ 8 - 1
src/main/modern-point/src/views/user/Exchange.vue

@@ -38,6 +38,13 @@ export default {
             url: '/asset/userHistory',
             httpType: 'get'
         };
+    },
+    methods: {
+        beforeData() {
+            return {
+                projectId: this.$store.state.projectId
+            };
+        }
     }
 };
 </script>
@@ -64,7 +71,7 @@ export default {
     .van-ellipsis {
         margin-bottom: 2px;
     }
-    border-top: 1px solid #202122;
+    border-top: 1px solid #f2f4f5;
 
     .top {
         .flex();

+ 9 - 5
src/main/modern-point/src/views/user/Followers.vue

@@ -31,11 +31,15 @@ export default {
             forbidClick: true
         });
         this.empty = false;
-        this.$http.get('/user/myFollowers').then(res => {
-            this.list = res;
-            this.empty = res.length === 0;
-            this.$toast.clear();
-        });
+        this.$http
+            .get('/user/myFollowers', {
+                projectId: this.$store.state.projectId
+            })
+            .then(res => {
+                this.list = res;
+                this.empty = res.length === 0;
+                this.$toast.clear();
+            });
     }
 };
 </script>

+ 9 - 5
src/main/modern-point/src/views/user/Follows.vue

@@ -46,11 +46,15 @@ export default {
                 forbidClick: true
             });
             this.empty = false;
-            this.$http.get('/user/myFollows').then(res => {
-                this.list = res;
-                this.empty = res.length === 0;
-                this.$toast.clear();
-            });
+            this.$http
+                .get('/user/myFollows', {
+                    projectId: this.$store.state.projectId
+                })
+                .then(res => {
+                    this.list = res;
+                    this.empty = res.length === 0;
+                    this.$toast.clear();
+                });
         }
     }
 };

+ 9 - 5
src/main/modern-point/src/views/user/Likes.vue

@@ -76,11 +76,15 @@ export default {
                 forbidClick: true
             });
             this.empty = false;
-            this.$http.get('/collection/myLikes').then(res => {
-                this.list = res;
-                this.empty = res.length === 0;
-                this.$toast.clear();
-            });
+            this.$http
+                .get('/collection/myLikes', {
+                    projectId: this.$store.state.projectId
+                })
+                .then(res => {
+                    this.list = res;
+                    this.empty = res.length === 0;
+                    this.$toast.clear();
+                });
         },
         change() {
             this.$root.$el.scrollTop = 0;

+ 7 - 0
src/main/nine-space/src/views/user/Exchange.vue

@@ -38,6 +38,13 @@ export default {
             url: '/asset/userHistory',
             httpType: 'get'
         };
+    },
+    methods: {
+        beforeData() {
+            return {
+                projectId: this.$store.state.projectId
+            };
+        }
     }
 };
 </script>

+ 9 - 5
src/main/nine-space/src/views/user/Followers.vue

@@ -31,11 +31,15 @@ export default {
             forbidClick: true
         });
         this.empty = false;
-        this.$http.get('/user/myFollowers').then(res => {
-            this.list = res;
-            this.empty = res.length === 0;
-            this.$toast.clear();
-        });
+        this.$http
+            .get('/user/myFollowers', {
+                projectId: this.$store.state.projectId
+            })
+            .then(res => {
+                this.list = res;
+                this.empty = res.length === 0;
+                this.$toast.clear();
+            });
     }
 };
 </script>

+ 10 - 6
src/main/nine-space/src/views/user/Follows.vue

@@ -46,11 +46,15 @@ export default {
                 forbidClick: true
             });
             this.empty = false;
-            this.$http.get('/user/myFollows').then(res => {
-                this.list = res;
-                this.empty = res.length === 0;
-                this.$toast.clear();
-            });
+            this.$http
+                .get('/user/myFollows', {
+                    projectId: this.$store.state.projectId
+                })
+                .then(res => {
+                    this.list = res;
+                    this.empty = res.length === 0;
+                    this.$toast.clear();
+                });
         }
     }
 };
@@ -58,7 +62,7 @@ export default {
 
 <style lang="less" scoped>
 .follow {
-    background-color: @bg3;;
+    background-color: @bg3;
 }
 .top {
     background-color: @bg;

+ 9 - 5
src/main/nine-space/src/views/user/Likes.vue

@@ -76,11 +76,15 @@ export default {
                 forbidClick: true
             });
             this.empty = false;
-            this.$http.get('/collection/myLikes').then(res => {
-                this.list = res;
-                this.empty = res.length === 0;
-                this.$toast.clear();
-            });
+            this.$http
+                .get('/collection/myLikes', {
+                    projectId: this.$store.state.projectId
+                })
+                .then(res => {
+                    this.list = res;
+                    this.empty = res.length === 0;
+                    this.$toast.clear();
+                });
         },
         change() {
             this.$root.$el.scrollTop = 0;

ファイルの差分が大きいため隠しています
+ 0 - 0
src/main/resources/genjson/GiftOrder.json


+ 25 - 1
src/main/vue/src/router.js

@@ -171,6 +171,14 @@ const router = new Router({
                         title: '订单'
                     }
                 },
+                {
+                    path: '/orderUsedList',
+                    name: 'OrderUsedList',
+                    component: () => import(/* webpackChunkName: "orderUsedList" */ '@/views/OrderUsedList.vue'),
+                    meta: {
+                        title: '订单'
+                    }
+                },
                 {
                     path: '/assetEdit',
                     name: 'AssetEdit',
@@ -414,6 +422,22 @@ const router = new Router({
                     meta: {
                         title: '邀请码管理'
                     }
+                },
+                {
+                    path: '/giftOrderEdit',
+                    name: 'GiftOrderEdit',
+                    component: () => import(/* webpackChunkName: "giftOrderEdit" */ '@/views/GiftOrderEdit.vue'),
+                    meta: {
+                        title: '转赠订单编辑'
+                    }
+                },
+                {
+                    path: '/giftOrderList',
+                    name: 'GiftOrderList',
+                    component: () => import(/* webpackChunkName: "giftOrderList" */ '@/views/GiftOrderList.vue'),
+                    meta: {
+                        title: '转赠订单'
+                    }
                 }
                 /**INSERT_LOCATION**/
             ]
@@ -474,4 +498,4 @@ router.beforeEach((to, from, next) => {
     }
 });
 
-export default router;
+export default router;

+ 147 - 119
src/main/vue/src/views/AssetEdit.vue

@@ -2,75 +2,98 @@
     <div class="edit-view">
         <page-title>
             <el-button @click="$router.go(-1)" :disabled="saving">取消</el-button>
-            <el-button @click="onDelete" :disabled="saving" type="danger" v-if="formData.id">
-                删除
-            </el-button>
+            <el-button @click="onDelete" :disabled="saving" type="danger" v-if="formData.id"> 删除 </el-button>
             <el-button @click="onSave" :loading="saving" type="primary">保存</el-button>
         </page-title>
         <div class="edit-view__content-wrapper">
             <div class="edit-view__content-section">
-                <el-form :model="formData" :rules="rules" ref="form" label-width="94px" label-position="right"
-                         size="small"
-                         style="max-width: 500px;">
-                        <el-form-item prop="userId" label="用户ID">
-                                    <el-input-number type="number" v-model="formData.userId"></el-input-number>
-                        </el-form-item>
-                        <el-form-item prop="orderId" label="订单ID">
-                                    <el-input-number type="number" v-model="formData.orderId"></el-input-number>
-                        </el-form-item>
-                        <el-form-item prop="name" label="名称">
-                                    <el-input v-model="formData.name"></el-input>
-                        </el-form-item>
-                        <el-form-item prop="minter" label="铸造者">
-                                    <el-input v-model="formData.minter"></el-input>
-                        </el-form-item>
-                        <el-form-item prop="minterId" label="铸造者ID">
-                                    <el-input-number type="number" v-model="formData.minterId"></el-input-number>
-                        </el-form-item>
-                        <el-form-item prop="minterAvatar" label="铸造者头像">
-                                    <el-input-number type="number" v-model="formData.minterAvatar"></el-input-number>
-                        </el-form-item>
-                        <el-form-item prop="pic" label="图片">
-                                    <el-input v-model="formData.pic"></el-input>
-                        </el-form-item>
-                        <el-form-item prop="tokenId" label="tokenId">
-                                    <el-input v-model="formData.tokenId"></el-input>
-                        </el-form-item>
-                        <el-form-item prop="txHash" label="购买hash">
-                                    <el-input v-model="formData.txHash"></el-input>
-                        </el-form-item>
-                        <el-form-item prop="ipfsUrl" label="购买hash">
-                                    <el-input v-model="formData.ipfsUrl"></el-input>
-                        </el-form-item>
-                        <el-form-item prop="price" label="购买价格">
-                                    <el-input-number type="number" v-model="formData.price"></el-input-number>
-                        </el-form-item>
-                        <el-form-item prop="sellPrice" label="转让价格">
-                                    <el-input-number type="number" v-model="formData.sellPrice"></el-input-number>
-                        </el-form-item>
-                        <el-form-item prop="outTxHash" label="转让hash">
-                                    <el-input v-model="formData.outTxHash"></el-input>
-                        </el-form-item>
-                        <el-form-item prop="outOrderId" label="转让订单ID">
-                                    <el-input-number type="number" v-model="formData.outOrderId"></el-input-number>
-                        </el-form-item>
-                        <el-form-item prop="status" label="状态">
-                                    <el-select v-model="formData.status" clearable filterable placeholder="请选择">
-                                        <el-option
-                                                v-for="item in statusOptions"
-                                                :key="item.value"
-                                                :label="item.label"
-                                                :value="item.value">
-                                        </el-option>
-                                    </el-select>
-                        </el-form-item>
+                <el-form
+                    :model="formData"
+                    :rules="rules"
+                    ref="form"
+                    label-width="94px"
+                    label-position="right"
+                    size="small"
+                    style="max-width: 500px"
+                >
+                    <el-form-item prop="userId" label="用户ID">
+                        <el-input-number type="number" v-model="formData.userId" disabled></el-input-number>
+                    </el-form-item>
+                    <el-form-item prop="collectionId" label="藏品ID">
+                        <el-input-number type="number" v-model="formData.collectionId" disabled></el-input-number>
+                    </el-form-item>
+                    <el-form-item prop="name" label="名称">
+                        <el-input v-model="formData.name" disabled></el-input>
+                    </el-form-item>
+                    <!-- <el-form-item prop="minter" label="铸造者">
+                        <el-input v-model="formData.minter"></el-input>
+                    </el-form-item>
+                    <el-form-item prop="minterId" label="铸造者ID">
+                        <el-input-number type="number" v-model="formData.minterId"></el-input-number>
+                    </el-form-item> -->
+                    <!-- <el-form-item prop="minterAvatar" label="铸造者头像">
+                        <el-input-number type="number" v-model="formData.minterAvatar"></el-input-number>
+                    </el-form-item>
+                    <el-form-item prop="pic" label="图片">
+                        <el-input v-model="formData.pic"></el-input>
+                    </el-form-item> -->
+                    <!-- <el-form-item prop="tokenId" label="tokenId">
+                        <el-input v-model="formData.tokenId"></el-input>
+                    </el-form-item> -->
+                    <!-- <el-form-item prop="ipfsUrl" label="购买hash">
+                        <el-input v-model="formData.ipfsUrl"></el-input>
+                    </el-form-item> -->
+                    <el-form-item prop="price" label="价格">
+                        <el-input-number type="number" v-model="formData.price" disabled></el-input-number>
+                    </el-form-item>
+                    <el-form-item prop="txHash" label="链上hash">
+                        <el-input v-model="formData.txHash" disabled></el-input>
+                    </el-form-item>
+                    <!-- <el-form-item prop="sellPrice" label="转让价格">
+                        <el-input-number type="number" v-model="formData.sellPrice"></el-input-number>
+                    </el-form-item> -->
+                    <!-- <el-form-item prop="outTxHash" label="转让hash">
+                        <el-input v-model="formData.outTxHash"></el-input>
+                    </el-form-item> -->
+                    <!-- <el-form-item prop="outOrderId" label="转让订单ID">
+                        <el-input-number type="number" v-model="formData.outOrderId"></el-input-number>
+                    </el-form-item> -->
+                    <!-- <el-form-item prop="status" label="状态">
+                        <el-select v-model="formData.status" clearable filterable placeholder="请选择">
+                            <el-option
+                                v-for="item in statusOptions"
+                                :key="item.value"
+                                :label="item.label"
+                                :value="item.value"
+                            >
+                            </el-option>
+                        </el-select>
+                    </el-form-item> -->
+                    <el-form-item prop="createdAt" label="购买时间">
+                        <el-date-picker
+                            v-model="formData.createdAt"
+                            type="datetime"
+                            value-format="yyyy-MM-dd HH:mm:ss"
+                            placeholder="选择日期时间"
+                            disabled
+                        >
+                        </el-date-picker>
+                    </el-form-item>
+                    <el-form-item prop="outTime" label="交易时间">
+                        <el-date-picker
+                            v-model="formData.outTime"
+                            type="datetime"
+                            value-format="yyyy-MM-dd HH:mm:ss"
+                            placeholder="选择日期时间"
+                            disabled
+                        >
+                        </el-date-picker>
+                    </el-form-item>
                     <el-form-item class="form-submit">
-                        <el-button @click="onSave" :loading="saving" type="primary">
-                            保存
-                        </el-button>
+                        <!-- <el-button @click="onSave" :loading="saving" type="primary"> 保存 </el-button>
                         <el-button @click="onDelete" :disabled="saving" type="danger" v-if="formData.id">
                             删除
-                        </el-button>
+                        </el-button> -->
                         <el-button @click="$router.go(-1)" :disabled="saving">取消</el-button>
                     </el-form-item>
                 </el-form>
@@ -79,72 +102,77 @@
     </div>
 </template>
 <script>
-    export default {
-        name: 'AssetEdit',
-        created() {
-            if (this.$route.query.id) {
-                this.$http
-                    .get('asset/get/' + this.$route.query.id)
-                    .then(res => {
-                        this.formData = res;
-                    })
-                    .catch(e => {
-                        console.log(e);
-                        this.$message.error(e.error);
-                    });
-            }
-        },
-        data() {
-            return {
-                saving: false,
-                formData: {
-                },
-                rules: {
-                },
-                statusOptions: [{"label":"正常","value":"NORMAL"},{"label":"出售中","value":"ON_SALE"},{"label":"已转让","value":"TRANSFERRED"}],
-            }
-        },
-        methods: {
-            onSave() {
-                this.$refs.form.validate((valid) => {
-                    if (valid) {
-                        this.submit();
-                    } else {
-                        return false;
-                    }
+export default {
+    name: 'AssetEdit',
+    created() {
+        if (this.$route.query.id) {
+            this.$http
+                .get('asset/get/' + this.$route.query.id)
+                .then(res => {
+                    this.formData = res;
+                })
+                .catch(e => {
+                    console.log(e);
+                    this.$message.error(e.error);
                 });
-            },
-            submit() {
-                let data = {...this.formData};
+        }
+    },
+    data() {
+        return {
+            saving: false,
+            formData: {},
+            rules: {},
+            statusOptions: [
+                { label: '正常', value: 'NORMAL' },
+                { label: '出售中', value: 'ON_SALE' },
+                { label: '已转让', value: 'TRANSFERRED' }
+            ]
+        };
+    },
+    methods: {
+        onSave() {
+            this.$refs.form.validate(valid => {
+                if (valid) {
+                    this.submit();
+                } else {
+                    return false;
+                }
+            });
+        },
+        submit() {
+            let data = { ...this.formData };
 
-                this.saving = true;
-                this.$http
-                    .post('/asset/save', data, {body: 'json'})
-                    .then(res => {
-                        this.saving = false;
-                        this.$message.success('成功');
-                        this.$router.go(-1);
-                    })
-                    .catch(e => {
-                        console.log(e);
-                        this.saving = false;
-                        this.$message.error(e.error);
-                    });
-            },
-            onDelete() {
-                this.$confirm('删除将无法恢复,确认要删除么?', '警告', {type: 'error'}).then(() => {
-                    return this.$http.post(`/asset/del/${this.formData.id}`)
-                }).then(() => {
+            this.saving = true;
+            this.$http
+                .post('/asset/save', data, { body: 'json' })
+                .then(res => {
+                    this.saving = false;
+                    this.$message.success('成功');
+                    this.$router.go(-1);
+                })
+                .catch(e => {
+                    console.log(e);
+                    this.saving = false;
+                    this.$message.error(e.error);
+                });
+        },
+        onDelete() {
+            this.$confirm('删除将无法恢复,确认要删除么?', '警告', { type: 'error' })
+                .then(() => {
+                    return this.$http.post(`/asset/del/${this.formData.id}`);
+                })
+                .then(() => {
                     this.$message.success('删除成功');
                     this.$router.go(-1);
-                }).catch(e => {
+                })
+                .catch(e => {
                     if (e !== 'cancel') {
                         console.log(e);
                         this.$message.error((e || {}).error || '删除失败');
                     }
-                })
-            },
+                });
         }
     }
+};
 </script>
 <style lang="less" scoped></style>

+ 157 - 166
src/main/vue/src/views/AssetList.vue

@@ -1,88 +1,71 @@
 <template>
-    <div  class="list-view">
+    <div class="list-view">
         <page-title>
-            <el-button @click="addRow" type="primary" icon="el-icon-plus" :disabled="fetchingData || downloading" class="filter-item">
+            <el-button
+                @click="addRow"
+                type="primary"
+                icon="el-icon-plus"
+                :disabled="fetchingData || downloading"
+                class="filter-item"
+            >
                 新增
             </el-button>
-            <el-button @click="download" icon="el-icon-upload2" :loading="downloading" :disabled="fetchingData" class="filter-item">
+            <el-button
+                @click="download"
+                icon="el-icon-upload2"
+                :loading="downloading"
+                :disabled="fetchingData"
+                class="filter-item"
+            >
                 导出
             </el-button>
         </page-title>
         <div class="filters-container">
             <el-input
-                    placeholder="搜索..."
-                    v-model="search"
-                    clearable
-                    class="filter-item search"
-                    @keyup.enter.native="getData"
+                placeholder="搜索..."
+                v-model="search"
+                clearable
+                class="filter-item search"
+                @keyup.enter.native="getData"
             >
                 <el-button @click="getData" slot="append" icon="el-icon-search"> </el-button>
             </el-input>
         </div>
-        <el-table :data="tableData" row-key="id" ref="table"
-                  header-row-class-name="table-header-row"
-                  header-cell-class-name="table-header-cell"
-                  row-class-name="table-row" cell-class-name="table-cell"
-                  :height="tableHeight" v-loading="fetchingData">
-            <el-table-column v-if="multipleMode" align="center" type="selection"
-                             width="50">
-            </el-table-column>
-            <el-table-column prop="id" label="ID" width="100">
-            </el-table-column>
-                                <el-table-column prop="userId" label="用户ID"
->
-                    </el-table-column>
-                    <el-table-column prop="orderId" label="订单ID"
->
-                    </el-table-column>
-                    <el-table-column prop="name" label="名称"
->
-                    </el-table-column>
-                    <el-table-column prop="minter" label="铸造者"
->
-                    </el-table-column>
-                    <el-table-column prop="minterId" label="铸造者ID"
->
-                    </el-table-column>
-                    <el-table-column prop="minterAvatar" label="铸造者头像"
->
-                    </el-table-column>
-                    <el-table-column prop="pic" label="图片"
->
-                    </el-table-column>
-                    <el-table-column prop="tokenId" label="tokenId"
->
-                    </el-table-column>
-                    <el-table-column prop="txHash" label="购买hash"
->
-                    </el-table-column>
-                    <el-table-column prop="ipfsUrl" label="购买hash"
->
-                    </el-table-column>
-                    <el-table-column prop="price" label="购买价格"
->
-                    </el-table-column>
-                    <el-table-column prop="sellPrice" label="转让价格"
->
-                    </el-table-column>
-                    <el-table-column prop="outTxHash" label="转让hash"
->
-                    </el-table-column>
-                    <el-table-column prop="outOrderId" label="转让订单ID"
->
-                    </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 @click="deleteRow(row)" type="danger" size="mini" plain>删除</el-button>
+        <el-table
+            :data="tableData"
+            row-key="id"
+            ref="table"
+            header-row-class-name="table-header-row"
+            header-cell-class-name="table-header-cell"
+            row-class-name="table-row"
+            cell-class-name="table-cell"
+            :height="tableHeight"
+            v-loading="fetchingData"
+        >
+            <el-table-column v-if="multipleMode" align="center" type="selection" width="50"> </el-table-column>
+            <el-table-column prop="id" label="ID" width="100"> </el-table-column>
+            <el-table-column prop="userId" label="用户ID"> </el-table-column>
+            <el-table-column prop="collectionId" label="藏品ID"> </el-table-column>
+            <el-table-column prop="name" label="名称" show-overflow-tooltip> </el-table-column>
+            <el-table-column prop="price" label="价格"> </el-table-column>
+            <!-- <el-table-column prop="sellPrice" label="转让价格"> </el-table-column> -->
+            <!-- <el-table-column prop="orderId" label="订单ID"> </el-table-column> -->
+            <!-- <el-table-column prop="minter" label="铸造者"> </el-table-column>
+            <el-table-column prop="minterId" label="铸造者ID"> </el-table-column>
+            <el-table-column prop="minterAvatar" label="铸造者头像"> </el-table-column>
+            <el-table-column prop="pic" label="图片"> </el-table-column> -->
+            <!-- <el-table-column prop="tokenId" label="tokenId"> </el-table-column> -->
+            <el-table-column prop="txHash" label="链上hash"> </el-table-column>
+            <!-- <el-table-column prop="ipfsUrl" label="购买hash"> </el-table-column> -->
+            <!-- <el-table-column prop="outTxHash" label="转让hash"> </el-table-column> -->
+            <!-- <el-table-column prop="outOrderId" label="转让订单ID"> </el-table-column> -->
+            <!-- <el-table-column prop="status" label="状态" :formatter="statusFormatter"> </el-table-column> -->
+            <el-table-column prop="createdAt" label="购买时间" width="140"> </el-table-column>
+            <el-table-column prop="outTime" label="交易时间" width="140"></el-table-column>
+            <el-table-column label="操作" align="center" fixed="right" width="150">
+                <template slot-scope="{ row }">
+                    <el-button @click="editRow(row)" type="primary" size="mini" plain>查看</el-button>
+                    <!-- <el-button @click="deleteRow(row)" type="danger" size="mini" plain>删除</el-button> -->
                 </template>
             </el-table-column>
         </el-table>
@@ -95,120 +78,128 @@
                     <el-button @click="toggleMultipleMode(false)">取消</el-button>
                 </el-button-group>
             </div> -->
-            <el-pagination background @size-change="onSizeChange"
-                           @current-change="onCurrentChange" :current-page="page"
-                           :page-sizes="[10, 20, 30, 40, 50]" :page-size="pageSize"
-                           layout="total, sizes, prev, pager, next, jumper"
-                           :total="totalElements">
+            <el-pagination
+                background
+                @size-change="onSizeChange"
+                @current-change="onCurrentChange"
+                :current-page="page"
+                :page-sizes="[10, 20, 30, 40, 50]"
+                :page-size="pageSize"
+                layout="total, sizes, prev, pager, next, jumper"
+                :total="totalElements"
+            >
             </el-pagination>
         </div>
-
     </div>
 </template>
 <script>
-    import { mapState } from "vuex";
-    import pageableTable from "@/mixins/pageableTable";
+import { mapState } from 'vuex';
+import pageableTable from '@/mixins/pageableTable';
 
-    export default {
-        name: 'AssetList',
-        mixins: [pageableTable],
-        data() {
-            return {
-                multipleMode: false,
-                search: "",
-                url: "/asset/all",
-                downloading: false,
-                        statusOptions:[{"label":"正常","value":"NORMAL"},{"label":"出售中","value":"ON_SALE"},{"label":"已转让","value":"TRANSFERRED"}],
+export default {
+    name: 'AssetList',
+    mixins: [pageableTable],
+    data() {
+        return {
+            multipleMode: false,
+            search: '',
+            url: '/asset/all',
+            downloading: false,
+            statusOptions: [
+                { label: '正常', value: 'NORMAL' },
+                { label: '出售中', value: 'ON_SALE' },
+                { label: '已转让', value: 'TRANSFERRED' }
+            ]
+        };
+    },
+    computed: {
+        selection() {
+            return this.$refs.table.selection.map(i => i.id);
+        }
+    },
+    methods: {
+        statusFormatter(row, column, cellValue, index) {
+            let selectedOption = this.statusOptions.find(i => i.value === cellValue);
+            if (selectedOption) {
+                return selectedOption.label;
             }
+            return '';
         },
-        computed: {
-            selection() {
-                return this.$refs.table.selection.map(i => i.id);
+        beforeGetData() {
+            return { search: this.search, query: { del: false } };
+        },
+        toggleMultipleMode(multipleMode) {
+            this.multipleMode = multipleMode;
+            if (!multipleMode) {
+                this.$refs.table.clearSelection();
             }
         },
-        methods: {
-                    statusFormatter(row, column, cellValue, index) {
-                        let selectedOption = this.statusOptions.find(i => i.value === cellValue);
-                        if (selectedOption) {
-                            return selectedOption.label;
-                        }
-                        return '';
-                    },
-            beforeGetData() {
-                return { search: this.search, query: { del: false } };
-            },
-            toggleMultipleMode(multipleMode) {
-                this.multipleMode = multipleMode;
-                if (!multipleMode) {
-                    this.$refs.table.clearSelection();
+        addRow() {
+            this.$router.push({
+                path: '/assetEdit',
+                query: {
+                    ...this.$route.query
                 }
-            },
-            addRow() {
-                this.$router.push({
-                    path: "/assetEdit",
-                    query: {
-                        ...this.$route.query
-                    }
-                });
-            },
-            editRow(row) {
-                this.$router.push({
-                    path: "/assetEdit",
-                    query: {
+            });
+        },
+        editRow(row) {
+            this.$router.push({
+                path: '/assetEdit',
+                query: {
                     id: row.id
-                    }
-                });
-            },
-            download() {
-                this.downloading = true;
-                this.$axios
-                    .get("/asset/excel", { 
-                        responseType: "blob",
-                        params: { size: 10000 }
-                    })
-                    .then(res => {
-                        console.log(res);
-                        this.downloading = false;
-                        const downloadUrl = window.URL.createObjectURL(new Blob([res.data]));
-                        const link = document.createElement("a");
-                        link.href = downloadUrl;
-                        link.setAttribute(
-                            "download",
-                            res.headers["content-disposition"].split("filename=")[1]
-                        );
-                        document.body.appendChild(link);
-                        link.click();
-                        link.remove();
-                    })
-                    .catch(e => {
-                        console.log(e);
-                        this.downloading = false;
-                        this.$message.error(e.error);
-                    });
-            },
-            operation1() {
-                this.$notify({
-                    title: '提示',
-                    message: this.selection
+                }
+            });
+        },
+        download() {
+            this.downloading = true;
+            this.$axios
+                .get('/asset/excel', {
+                    responseType: 'blob',
+                    params: { size: 10000 }
+                })
+                .then(res => {
+                    console.log(res);
+                    this.downloading = false;
+                    const downloadUrl = window.URL.createObjectURL(new Blob([res.data]));
+                    const link = document.createElement('a');
+                    link.href = downloadUrl;
+                    link.setAttribute('download', res.headers['content-disposition'].split('filename=')[1]);
+                    document.body.appendChild(link);
+                    link.click();
+                    link.remove();
+                })
+                .catch(e => {
+                    console.log(e);
+                    this.downloading = false;
+                    this.$message.error(e.error);
                 });
-            },
-            operation2() {
-                this.$message('操作2');
-            },
-            deleteRow(row) {
-                this.$alert('删除将无法恢复,确认要删除么?', '警告', {type: 'error'}).then(() => {
-                    return this.$http.post(`/asset/del/${row.id}`)
-                }).then(() => {
+        },
+        operation1() {
+            this.$notify({
+                title: '提示',
+                message: this.selection
+            });
+        },
+        operation2() {
+            this.$message('操作2');
+        },
+        deleteRow(row) {
+            this.$alert('删除将无法恢复,确认要删除么?', '警告', { type: 'error' })
+                .then(() => {
+                    return this.$http.post(`/asset/del/${row.id}`);
+                })
+                .then(() => {
                     this.$message.success('删除成功');
                     this.getData();
-                }).catch(e => {
+                })
+                .catch(e => {
                     if (e !== 'cancel') {
                         this.$message.error(e.error);
                     }
-                })
-            },
+                });
         }
     }
+};
 </script>
 <style lang="less" scoped>
 </style>

+ 179 - 0
src/main/vue/src/views/GiftOrderEdit.vue

@@ -0,0 +1,179 @@
+<template>
+    <div class="edit-view">
+        <page-title>
+            <el-button @click="$router.go(-1)" :disabled="saving">取消</el-button>
+            <!-- <el-button @click="onDelete" :disabled="saving" type="danger" v-if="formData.id"> 删除 </el-button>
+            <el-button @click="onSave" :loading="saving" type="primary">保存</el-button> -->
+        </page-title>
+        <div class="edit-view__content-wrapper">
+            <div class="edit-view__content-section">
+                <el-form
+                    :model="formData"
+                    :rules="rules"
+                    ref="form"
+                    label-width="84px"
+                    label-position="right"
+                    size="small"
+                    style="max-width: 500px"
+                >
+                    <el-form-item prop="userId" label="赠送用户ID">
+                        <el-input-number type="number" v-model="formData.userId" disabled></el-input-number>
+                    </el-form-item>
+                    <el-form-item prop="collectionId" label="藏品ID">
+                        <el-input-number type="number" v-model="formData.collectionId" disabled></el-input-number>
+                    </el-form-item>
+                    <el-form-item prop="name" label="名称">
+                        <el-input v-model="formData.name" disabled></el-input>
+                    </el-form-item>
+                    <el-form-item prop="toUserId" label="收到用户ID">
+                        <el-input-number type="number" v-model="formData.toUserId" disabled></el-input-number>
+                    </el-form-item>
+                    <el-form-item prop="payMethod" label="支付方式">
+                        <el-select v-model="formData.payMethod" clearable filterable placeholder="请选择" disabled>
+                            <el-option
+                                v-for="item in payMethodOptions"
+                                :key="item.value"
+                                :label="item.label"
+                                :value="item.value"
+                            >
+                            </el-option>
+                        </el-select>
+                    </el-form-item>
+                    <el-form-item prop="status" label="状态">
+                        <el-select v-model="formData.status" clearable filterable placeholder="请选择" disabled>
+                            <el-option
+                                v-for="item in statusOptions"
+                                :key="item.value"
+                                :label="item.label"
+                                :value="item.value"
+                            >
+                            </el-option>
+                        </el-select>
+                    </el-form-item>
+                    <el-form-item prop="gasPrice" label="gas费">
+                        <el-input-number type="number" v-model="formData.gasPrice" disabled></el-input-number>
+                    </el-form-item>
+                    <el-form-item prop="transactionId" label="交易ID">
+                        <el-input v-model="formData.transactionId" disabled></el-input>
+                    </el-form-item>
+                    <el-form-item prop="payTime" label="支付时间">
+                        <el-date-picker
+                            v-model="formData.payTime"
+                            type="datetime"
+                            value-format="yyyy-MM-dd HH:mm:ss"
+                            placeholder="选择日期时间"
+                            disabled
+                        >
+                        </el-date-picker>
+                    </el-form-item>
+                    <el-form-item prop="cancelTime" label="取消时间">
+                        <el-date-picker
+                            v-model="formData.cancelTime"
+                            type="datetime"
+                            value-format="yyyy-MM-dd HH:mm:ss"
+                            placeholder="选择日期时间"
+                            disabled
+                        >
+                        </el-date-picker>
+                    </el-form-item>
+                    <el-form-item prop="txHash" label="交易hash">
+                        <el-input v-model="formData.txHash" disabled></el-input>
+                    </el-form-item>
+                    <el-form-item prop="gasUsed" label="消耗gas">
+                        <el-input v-model="formData.gasUsed" disabled></el-input>
+                    </el-form-item>
+                    <el-form-item prop="blockNumber" label="区块高度">
+                        <el-input v-model="formData.blockNumber" disabled></el-input>
+                    </el-form-item>
+                    <el-form-item class="form-submit">
+                        <!-- <el-button @click="onSave" :loading="saving" type="primary"> 保存 </el-button>
+                        <el-button @click="onDelete" :disabled="saving" type="danger" v-if="formData.id">
+                            删除
+                        </el-button> -->
+                        <el-button @click="$router.go(-1)" :disabled="saving">取消</el-button>
+                    </el-form-item>
+                </el-form>
+            </div>
+        </div>
+    </div>
+</template>
+<script>
+export default {
+    name: 'GiftOrderEdit',
+    created() {
+        if (this.$route.query.id) {
+            this.$http
+                .get('giftOrder/get/' + this.$route.query.id)
+                .then(res => {
+                    this.formData = res;
+                })
+                .catch(e => {
+                    console.log(e);
+                    this.$message.error(e.error);
+                });
+        }
+    },
+    data() {
+        return {
+            saving: false,
+            formData: {},
+            rules: {},
+            payMethodOptions: [
+                { label: '微信', value: 'WEIXIN' },
+                { label: '支付宝', value: 'ALIPAY' }
+            ],
+            statusOptions: [
+                { label: '未支付', value: 'NOT_PAID' },
+                { label: '已支付,处理中', value: 'PROCESSING' },
+                { label: '已完成', value: 'FINISH' },
+                { label: '已取消', value: 'CANCELLED' }
+            ]
+        };
+    },
+    methods: {
+        onSave() {
+            this.$refs.form.validate(valid => {
+                if (valid) {
+                    this.submit();
+                } else {
+                    return false;
+                }
+            });
+        },
+        submit() {
+            let data = { ...this.formData };
+
+            this.saving = true;
+            this.$http
+                .post('/giftOrder/save', data, { body: 'json' })
+                .then(res => {
+                    this.saving = false;
+                    this.$message.success('成功');
+                    this.$router.go(-1);
+                })
+                .catch(e => {
+                    console.log(e);
+                    this.saving = false;
+                    this.$message.error(e.error);
+                });
+        },
+        onDelete() {
+            this.$confirm('删除将无法恢复,确认要删除么?', '警告', { type: 'error' })
+                .then(() => {
+                    return this.$http.post(`/giftOrder/del/${this.formData.id}`);
+                })
+                .then(() => {
+                    this.$message.success('删除成功');
+                    this.$router.go(-1);
+                })
+                .catch(e => {
+                    if (e !== 'cancel') {
+                        console.log(e);
+                        this.$message.error((e || {}).error || '删除失败');
+                    }
+                });
+        }
+    }
+};
+</script>
+<style lang="less" scoped></style>

+ 226 - 0
src/main/vue/src/views/GiftOrderList.vue

@@ -0,0 +1,226 @@
+<template>
+    <div class="list-view">
+        <page-title>
+            <!-- <el-button
+                @click="addRow"
+                type="primary"
+                icon="el-icon-plus"
+                :disabled="fetchingData || downloading"
+                class="filter-item"
+            >
+                新增
+            </el-button> -->
+            <el-button
+                @click="download"
+                icon="el-icon-upload2"
+                :loading="downloading"
+                :disabled="fetchingData"
+                class="filter-item"
+            >
+                导出
+            </el-button>
+        </page-title>
+        <div class="filters-container">
+            <el-select v-model="status" placeholder="筛选状态" clearable @change="getData" style="margin-right: 10px">
+                <el-option
+                    v-for="item in statusOptions"
+                    :key="item.value"
+                    :value="item.value"
+                    :label="item.label"
+                ></el-option>
+            </el-select>
+            <created-at-picker v-model="payTime" @input="getData" name="支付"></created-at-picker>
+            <el-input
+                placeholder="搜索..."
+                v-model="search"
+                clearable
+                class="filter-item search"
+                @keyup.enter.native="getData"
+            >
+                <el-button @click="getData" slot="append" icon="el-icon-search"> </el-button>
+            </el-input>
+        </div>
+        <el-table
+            :data="tableData"
+            row-key="id"
+            ref="table"
+            header-row-class-name="table-header-row"
+            header-cell-class-name="table-header-cell"
+            row-class-name="table-row"
+            cell-class-name="table-cell"
+            :height="tableHeight"
+            v-loading="fetchingData"
+        >
+            <el-table-column v-if="multipleMode" align="center" type="selection" width="50"> </el-table-column>
+            <el-table-column prop="id" label="ID" width="100"> </el-table-column>
+            <el-table-column prop="userId" label="赠送用户ID" width="100px"> </el-table-column>
+            <el-table-column prop="nickname" label="赠送用户"> </el-table-column>
+            <el-table-column prop="collectionId" label="藏品ID"> </el-table-column>
+            <el-table-column prop="name" label="名称"> </el-table-column>
+            <el-table-column prop="toUserId" label="收到用户ID" width="100px"> </el-table-column>
+            <el-table-column prop="toNickname" label="收到用户"> </el-table-column>
+            <el-table-column prop="payMethod" label="支付方式"> </el-table-column>
+            <el-table-column prop="status" label="状态"> </el-table-column>
+            <el-table-column prop="gasPrice" label="gas费"> </el-table-column>
+            <el-table-column prop="transactionId" label="交易ID" show-overflow-tooltip> </el-table-column>
+            <el-table-column prop="payTime" label="支付时间" width="140"> </el-table-column>
+            <el-table-column prop="txHash" label="交易hash" show-overflow-tooltip> </el-table-column>
+            <el-table-column prop="gasUsed" label="消耗gas"> </el-table-column>
+            <el-table-column prop="blockNumber" label="区块高度"> </el-table-column>
+            <el-table-column label="操作" align="center" fixed="right" width="150">
+                <template slot-scope="{ row }">
+                    <el-button @click="editRow(row)" type="primary" size="mini" plain>查看</el-button>
+                    <!-- <el-button @click="deleteRow(row)" type="danger" size="mini" plain>删除</el-button> -->
+                </template>
+            </el-table-column>
+        </el-table>
+        <div class="pagination-wrapper">
+            <!-- <div class="multiple-mode-wrapper">
+                <el-button v-if="!multipleMode" @click="toggleMultipleMode(true)">批量编辑</el-button>
+                <el-button-group v-else>
+                    <el-button @click="operation1">批量操作1</el-button>
+                    <el-button @click="operation2">批量操作2</el-button>
+                    <el-button @click="toggleMultipleMode(false)">取消</el-button>
+                </el-button-group>
+            </div> -->
+            <el-pagination
+                background
+                @size-change="onSizeChange"
+                @current-change="onCurrentChange"
+                :current-page="page"
+                :page-sizes="[10, 20, 30, 40, 50]"
+                :page-size="pageSize"
+                layout="total, sizes, prev, pager, next, jumper"
+                :total="totalElements"
+            >
+            </el-pagination>
+        </div>
+    </div>
+</template>
+<script>
+import { mapState } from 'vuex';
+import pageableTable from '@/mixins/pageableTable';
+
+export default {
+    name: 'GiftOrderList',
+    mixins: [pageableTable],
+    data() {
+        return {
+            multipleMode: false,
+            search: '',
+            url: '/giftOrder/all',
+            downloading: false,
+            payMethodOptions: [
+                { label: '微信', value: 'WEIXIN' },
+                { label: '支付宝', value: 'ALIPAY' }
+            ],
+            statusOptions: [
+                { label: '未支付', value: 'NOT_PAID' },
+                { label: '已支付,处理中', value: 'PROCESSING' },
+                { label: '已完成', value: 'FINISH' },
+                { label: '已取消', value: 'CANCELLED' }
+            ],
+            payTime: '',
+            status: ''
+        };
+    },
+    computed: {
+        selection() {
+            return this.$refs.table.selection.map(i => i.id);
+        }
+    },
+    methods: {
+        payMethodFormatter(row, column, cellValue, index) {
+            let selectedOption = this.payMethodOptions.find(i => i.value === cellValue);
+            if (selectedOption) {
+                return selectedOption.label;
+            }
+            return '';
+        },
+        statusFormatter(row, column, cellValue, index) {
+            let selectedOption = this.statusOptions.find(i => i.value === cellValue);
+            if (selectedOption) {
+                return selectedOption.label;
+            }
+            return '';
+        },
+        beforeGetData() {
+            return { search: this.search, query: { del: false, status: this.status, payTime: this.payTime } };
+        },
+        toggleMultipleMode(multipleMode) {
+            this.multipleMode = multipleMode;
+            if (!multipleMode) {
+                this.$refs.table.clearSelection();
+            }
+        },
+        addRow() {
+            this.$router.push({
+                path: '/giftOrderEdit',
+                query: {
+                    ...this.$route.query
+                }
+            });
+        },
+        editRow(row) {
+            this.$router.push({
+                path: '/giftOrderEdit',
+                query: {
+                    id: row.id
+                }
+            });
+        },
+        download() {
+            this.downloading = true;
+            let params = this.beforeGetData();
+            params.size = 10000;
+            params.query.projectId = this.$store.state.projectId;
+            this.$axios
+                .post('/giftOrder/excel', params, {
+                    responseType: 'blob'
+                })
+                .then(res => {
+                    console.log(res);
+                    this.downloading = false;
+                    const downloadUrl = window.URL.createObjectURL(new Blob([res.data]));
+                    const link = document.createElement('a');
+                    link.href = downloadUrl;
+                    link.setAttribute('download', '转赠订单.xlsx');
+                    document.body.appendChild(link);
+                    link.click();
+                    link.remove();
+                })
+                .catch(e => {
+                    console.log(e);
+                    this.downloading = false;
+                    this.$message.error(e.error);
+                });
+        },
+        operation1() {
+            this.$notify({
+                title: '提示',
+                message: this.selection
+            });
+        },
+        operation2() {
+            this.$message('操作2');
+        },
+        deleteRow(row) {
+            this.$alert('删除将无法恢复,确认要删除么?', '警告', { type: 'error' })
+                .then(() => {
+                    return this.$http.post(`/giftOrder/del/${row.id}`);
+                })
+                .then(() => {
+                    this.$message.success('删除成功');
+                    this.getData();
+                })
+                .catch(e => {
+                    if (e !== 'cancel') {
+                        this.$message.error(e.error);
+                    }
+                });
+        }
+    }
+};
+</script>
+<style lang="less" scoped>
+</style>

+ 1 - 1
src/main/vue/src/views/OrderList.vue

@@ -155,7 +155,7 @@ export default {
             return '';
         },
         beforeGetData() {
-            return { search: this.search, query: { del: false, status: this.status, createdAt: this.createdAt } };
+            return { search: this.search, query: { del: false, status: this.status, createdAt: this.createdAt, source: 'OFFICIAL' } };
         },
         toggleMultipleMode(multipleMode) {
             this.multipleMode = multipleMode;

+ 236 - 0
src/main/vue/src/views/OrderUsedList.vue

@@ -0,0 +1,236 @@
+<template>
+    <div class="list-view">
+        <page-title>
+            <!-- <el-button
+                @click="addRow"
+                type="primary"
+                icon="el-icon-plus"
+                :disabled="fetchingData || downloading"
+                class="filter-item"
+            >
+                新增
+            </el-button> -->
+            <el-button
+                @click="download"
+                icon="el-icon-upload2"
+                :loading="downloading"
+                :disabled="fetchingData"
+                class="filter-item"
+            >
+                导出
+            </el-button>
+        </page-title>
+        <div class="filters-container">
+            <el-select v-model="status" placeholder="筛选状态" clearable @change="getData" style="margin-right: 10px">
+                <el-option
+                    v-for="item in statusOptions"
+                    :key="item.value"
+                    :value="item.value"
+                    :label="item.label"
+                ></el-option>
+            </el-select>
+            <created-at-picker v-model="createdAt" @input="getData" name="下单"></created-at-picker>
+            <el-input
+                placeholder="搜索..."
+                v-model="search"
+                clearable
+                class="filter-item search"
+                @keyup.enter.native="getData"
+            >
+                <el-button @click="getData" slot="append" icon="el-icon-search"> </el-button>
+            </el-input>
+        </div>
+        <el-table
+            :data="tableData"
+            row-key="id"
+            ref="table"
+            header-row-class-name="table-header-row"
+            header-cell-class-name="table-header-cell"
+            row-class-name="table-row"
+            cell-class-name="table-cell"
+            :height="tableHeight"
+            v-loading="fetchingData"
+        >
+            <el-table-column v-if="multipleMode" align="center" type="selection" width="50"> </el-table-column>
+            <el-table-column prop="id" label="ID" width="100"> </el-table-column>
+            <el-table-column prop="userId" label="用户ID"> </el-table-column>
+            <el-table-column prop="collectionId" label="藏品ID"> </el-table-column>
+            <el-table-column prop="name" label="名称" show-overflow-tooltip> </el-table-column>
+            <el-table-column prop="pic" label="图片" width="80">
+                <template slot-scope="{ row }">
+                    <el-image
+                        style="width: 30px; height: 30px"
+                        :src="row.pic[0].thumb || row.pic[0].url"
+                        fit="cover"
+                        :preview-src-list="row.pic.map(i => i.thumb || i.url)"
+                    ></el-image>
+                </template>
+            </el-table-column>
+            <el-table-column prop="price" label="价格"> </el-table-column>
+            <el-table-column prop="gasPrice" label="gas费"> </el-table-column>
+            <el-table-column prop="totalPrice" label="总价"> </el-table-column>
+            <el-table-column prop="status" label="状态" :formatter="statusFormatter"> </el-table-column>
+            <el-table-column prop="payMethod" label="支付方式" :formatter="payMethodFormatter"> </el-table-column>
+            <el-table-column prop="transactionId" label="交易ID" show-overflow-tooltip> </el-table-column>
+            <el-table-column prop="createdAt" label="下单时间" width="140"> </el-table-column>
+            <el-table-column prop="payTime" label="支付时间" width="140"> </el-table-column>
+            <el-table-column prop="txHash" label="链上hash" show-overflow-tooltip> </el-table-column>
+            <el-table-column prop="gasUsed" label="消耗gas"></el-table-column>
+            <el-table-column prop="invitor" label="推广用户"></el-table-column>
+            <el-table-column label="操作" align="center" fixed="right" width="150">
+                <template slot-scope="{ row }">
+                    <el-button @click="editRow(row)" type="primary" size="mini" plain>查看</el-button>
+                    <!-- <el-button @click="deleteRow(row)" type="danger" size="mini" plain>删除</el-button> -->
+                </template>
+            </el-table-column>
+        </el-table>
+        <div class="pagination-wrapper">
+            <!-- <div class="multiple-mode-wrapper">
+                <el-button v-if="!multipleMode" @click="toggleMultipleMode(true)">批量编辑</el-button>
+                <el-button-group v-else>
+                    <el-button @click="operation1">批量操作1</el-button>
+                    <el-button @click="operation2">批量操作2</el-button>
+                    <el-button @click="toggleMultipleMode(false)">取消</el-button>
+                </el-button-group>
+            </div> -->
+            <el-pagination
+                background
+                @size-change="onSizeChange"
+                @current-change="onCurrentChange"
+                :current-page="page"
+                :page-sizes="[10, 20, 30, 40, 50]"
+                :page-size="pageSize"
+                layout="total, sizes, prev, pager, next, jumper"
+                :total="totalElements"
+            >
+            </el-pagination>
+        </div>
+    </div>
+</template>
+<script>
+import { mapState } from 'vuex';
+import pageableTable from '@/mixins/pageableTable';
+
+export default {
+    name: 'OrderUsedList',
+    mixins: [pageableTable],
+    data() {
+        return {
+            multipleMode: false,
+            search: '',
+            url: '/order/all',
+            downloading: false,
+            statusOptions: [
+                { label: '未支付', value: 'NOT_PAID' },
+                { label: '已支付,处理中', value: 'PROCESSING' },
+                { label: '已完成', value: 'FINISH' },
+                { label: '已取消', value: 'CANCELLED' }
+            ],
+            payMethodOptions: [
+                { label: '微信', value: 'WEIXIN' },
+                { label: '支付宝', value: 'ALIPAY' }
+            ],
+            status: null,
+            createdAt: ''
+        };
+    },
+    computed: {
+        selection() {
+            return this.$refs.table.selection.map(i => i.id);
+        }
+    },
+    methods: {
+        statusFormatter(row, column, cellValue, index) {
+            let selectedOption = this.statusOptions.find(i => i.value === cellValue);
+            if (selectedOption) {
+                return selectedOption.label;
+            }
+            return '';
+        },
+        payMethodFormatter(row, column, cellValue, index) {
+            let selectedOption = this.payMethodOptions.find(i => i.value === cellValue);
+            if (selectedOption) {
+                return selectedOption.label;
+            }
+            return '';
+        },
+        beforeGetData() {
+            return { search: this.search, query: { del: false, status: this.status, createdAt: this.createdAt, source: 'TRANSFER' } };
+        },
+        toggleMultipleMode(multipleMode) {
+            this.multipleMode = multipleMode;
+            if (!multipleMode) {
+                this.$refs.table.clearSelection();
+            }
+        },
+        addRow() {
+            this.$router.push({
+                path: '/orderEdit',
+                query: {
+                    ...this.$route.query
+                }
+            });
+        },
+        editRow(row) {
+            this.$router.push({
+                path: '/orderEdit',
+                query: {
+                    id: row.id
+                }
+            });
+        },
+        download() {
+            this.downloading = true;
+            let params = this.beforeGetData();
+            params.size = 10000;
+            params.query.projectId = this.$store.state.projectId;
+            this.$axios
+                .post('/order/excel', params, {
+                    responseType: 'blob',
+                })
+                .then(res => {
+                    console.log(res);
+                    this.downloading = false;
+                    const downloadUrl = window.URL.createObjectURL(new Blob([res.data]));
+                    const link = document.createElement('a');
+                    link.href = downloadUrl;
+                    link.setAttribute('download', '订单.xlsx');
+                    document.body.appendChild(link);
+                    link.click();
+                    link.remove();
+                })
+                .catch(e => {
+                    console.log(e);
+                    this.downloading = false;
+                    this.$message.error(e.error);
+                });
+        },
+        operation1() {
+            this.$notify({
+                title: '提示',
+                message: this.selection
+            });
+        },
+        operation2() {
+            this.$message('操作2');
+        },
+        deleteRow(row) {
+            this.$alert('删除将无法恢复,确认要删除么?', '警告', { type: 'error' })
+                .then(() => {
+                    return this.$http.post(`/order/del/${row.id}`);
+                })
+                .then(() => {
+                    this.$message.success('删除成功');
+                    this.getData();
+                })
+                .catch(e => {
+                    if (e !== 'cancel') {
+                        this.$message.error(e.error);
+                    }
+                });
+        }
+    }
+};
+</script>
+<style lang="less" scoped>
+</style>

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

@@ -5,6 +5,7 @@ import com.izouma.nineth.domain.*;
 import com.izouma.nineth.repo.*;
 import org.junit.jupiter.api.Test;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.Pageable;
 
 import java.time.LocalDateTime;
 import java.util.Arrays;
@@ -77,7 +78,7 @@ class AssetServiceTest extends ApplicationTests {
     @Test
     public void stat() {
         Map<User, Integer> match = assetService.holdQuery(Arrays.asList(
-                       "【熊猫柯斯】-虎虎生威"),
+                        "【熊猫柯斯】-虎虎生威"),
                 LocalDateTime.of(2021, 12, 31, 9, 59, 59),
                 LocalDateTime.of(2021, 12, 31, 10, 0, 0));
         System.out.println("用户ID,昵称,手机,持有套数");
@@ -87,4 +88,9 @@ class AssetServiceTest extends ApplicationTests {
         }
 
     }
+
+    @Test
+    public void userHistory() {
+        assetService.userHistory(44L, 1, Pageable.unpaged());
+    }
 }

この差分においてかなりの量のファイルが変更されているため、一部のファイルを表示していません