Kaynağa Gözat

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

wangqifan 3 yıl önce
ebeveyn
işleme
1d79f8e89d
100 değiştirilmiş dosya ile 3277 ekleme ve 190 silme
  1. 7 0
      run_java.sh
  2. 2 0
      src/main/java/com/izouma/nineth/config/Constants.java
  3. 5 0
      src/main/java/com/izouma/nineth/config/RedisKeys.java
  4. 2 0
      src/main/java/com/izouma/nineth/domain/AirDrop.java
  5. 1 0
      src/main/java/com/izouma/nineth/domain/AppVersion.java
  6. 5 0
      src/main/java/com/izouma/nineth/domain/Asset.java
  7. 99 0
      src/main/java/com/izouma/nineth/domain/AuctionActivity.java
  8. 107 0
      src/main/java/com/izouma/nineth/domain/AuctionOrder.java
  9. 25 0
      src/main/java/com/izouma/nineth/domain/AuctionPassRecord.java
  10. 52 0
      src/main/java/com/izouma/nineth/domain/AuctionRecord.java
  11. 2 0
      src/main/java/com/izouma/nineth/domain/BlindBoxItem.java
  12. 2 0
      src/main/java/com/izouma/nineth/domain/Collection.java
  13. 2 0
      src/main/java/com/izouma/nineth/domain/CompanyCollection.java
  14. 3 1
      src/main/java/com/izouma/nineth/domain/NewsLike.java
  15. 32 0
      src/main/java/com/izouma/nineth/domain/PurchaserPrivilege.java
  16. 2 0
      src/main/java/com/izouma/nineth/domain/Showroom.java
  17. 4 1
      src/main/java/com/izouma/nineth/domain/User.java
  18. 4 0
      src/main/java/com/izouma/nineth/domain/UserAddress.java
  19. 1 1
      src/main/java/com/izouma/nineth/domain/UserProperty.java
  20. 40 0
      src/main/java/com/izouma/nineth/dto/AssetDTO.java
  21. 31 0
      src/main/java/com/izouma/nineth/dto/auction/AuctionInputDTO.java
  22. 48 0
      src/main/java/com/izouma/nineth/dto/auction/AuctionRecordDTO.java
  23. 27 0
      src/main/java/com/izouma/nineth/dto/oasis/OasisDistrictCollectionDTO.java
  24. 45 0
      src/main/java/com/izouma/nineth/dto/oasis/OasisDistrictDTO.java
  25. 19 0
      src/main/java/com/izouma/nineth/dto/oasis/OasisLoginDTO.java
  26. 22 0
      src/main/java/com/izouma/nineth/enums/AuctionOrderStatus.java
  27. 17 0
      src/main/java/com/izouma/nineth/enums/AuctionPaymentType.java
  28. 17 0
      src/main/java/com/izouma/nineth/enums/AuctionRecordType.java
  29. 16 0
      src/main/java/com/izouma/nineth/enums/AuctionSource.java
  30. 20 0
      src/main/java/com/izouma/nineth/enums/AuctionStatus.java
  31. 16 0
      src/main/java/com/izouma/nineth/enums/AuctionType.java
  32. 3 0
      src/main/java/com/izouma/nineth/enums/BalanceType.java
  33. 1 0
      src/main/java/com/izouma/nineth/enums/BannerType.java
  34. 2 1
      src/main/java/com/izouma/nineth/enums/TransferReason.java
  35. 1 0
      src/main/java/com/izouma/nineth/event/OrderNotifyEvent.java
  36. 1 1
      src/main/java/com/izouma/nineth/listener/CreateOrderListener.java
  37. 10 9
      src/main/java/com/izouma/nineth/listener/OrderNotifyListener.java
  38. 1 1
      src/main/java/com/izouma/nineth/listener/RegisterListener.java
  39. 1 1
      src/main/java/com/izouma/nineth/listener/UpdateActivityStockListener.java
  40. 1 1
      src/main/java/com/izouma/nineth/listener/UpdateQuotaListener.java
  41. 1 1
      src/main/java/com/izouma/nineth/listener/UpdateSaleListener.java
  42. 1 1
      src/main/java/com/izouma/nineth/listener/UpdateStockListener.java
  43. 4 0
      src/main/java/com/izouma/nineth/repo/AppVersionRepo.java
  44. 11 0
      src/main/java/com/izouma/nineth/repo/AssetRepo.java
  45. 51 0
      src/main/java/com/izouma/nineth/repo/AuctionActivityRepo.java
  46. 35 0
      src/main/java/com/izouma/nineth/repo/AuctionOrderRepo.java
  47. 21 0
      src/main/java/com/izouma/nineth/repo/AuctionPassRecordRepo.java
  48. 35 0
      src/main/java/com/izouma/nineth/repo/AuctionRecordRepo.java
  49. 4 0
      src/main/java/com/izouma/nineth/repo/CollectionRepo.java
  50. 4 0
      src/main/java/com/izouma/nineth/repo/CompanyCollectionRepo.java
  51. 2 0
      src/main/java/com/izouma/nineth/repo/NewsLikeRepo.java
  52. 3 0
      src/main/java/com/izouma/nineth/repo/ShowroomRepo.java
  53. 3 0
      src/main/java/com/izouma/nineth/repo/UserBalanceRepo.java
  54. 8 1
      src/main/java/com/izouma/nineth/repo/UserRepo.java
  55. 7 0
      src/main/java/com/izouma/nineth/security/WebSecurityConfig.java
  56. 21 5
      src/main/java/com/izouma/nineth/service/AirDropService.java
  57. 117 18
      src/main/java/com/izouma/nineth/service/AssetService.java
  58. 315 0
      src/main/java/com/izouma/nineth/service/AuctionActivityService.java
  59. 607 0
      src/main/java/com/izouma/nineth/service/AuctionOrderService.java
  60. 224 0
      src/main/java/com/izouma/nineth/service/AuctionRecordService.java
  61. 5 0
      src/main/java/com/izouma/nineth/service/CacheService.java
  62. 1 1
      src/main/java/com/izouma/nineth/service/CaptchaService.java
  63. 52 0
      src/main/java/com/izouma/nineth/service/CollectionService.java
  64. 109 1
      src/main/java/com/izouma/nineth/service/CompanyCollectionService.java
  65. 1 3
      src/main/java/com/izouma/nineth/service/MintOrderService.java
  66. 25 5
      src/main/java/com/izouma/nineth/service/NewsLikeService.java
  67. 22 11
      src/main/java/com/izouma/nineth/service/OrderCancelService.java
  68. 77 18
      src/main/java/com/izouma/nineth/service/OrderPayService.java
  69. 15 16
      src/main/java/com/izouma/nineth/service/OrderService.java
  70. 2 1
      src/main/java/com/izouma/nineth/service/SandPayService.java
  71. 10 2
      src/main/java/com/izouma/nineth/service/ShowroomService.java
  72. 26 2
      src/main/java/com/izouma/nineth/service/UserBalanceService.java
  73. 2 0
      src/main/java/com/izouma/nineth/service/UserBankCardService.java
  74. 129 0
      src/main/java/com/izouma/nineth/service/UserService.java
  75. 0 28
      src/main/java/com/izouma/nineth/service/WithdrawApplyScheduleService.java
  76. 5 2
      src/main/java/com/izouma/nineth/service/WithdrawApplyService.java
  77. 5 3
      src/main/java/com/izouma/nineth/web/AppVersionController.java
  78. 25 6
      src/main/java/com/izouma/nineth/web/AssetController.java
  79. 77 0
      src/main/java/com/izouma/nineth/web/AuctionActivityController.java
  80. 124 0
      src/main/java/com/izouma/nineth/web/AuctionOrderController.java
  81. 86 0
      src/main/java/com/izouma/nineth/web/AuctionRecordController.java
  82. 18 0
      src/main/java/com/izouma/nineth/web/AuthenticationController.java
  83. 12 0
      src/main/java/com/izouma/nineth/web/CollectionController.java
  84. 63 4
      src/main/java/com/izouma/nineth/web/CompanyCollectionController.java
  85. 5 0
      src/main/java/com/izouma/nineth/web/HmPayController.java
  86. 5 3
      src/main/java/com/izouma/nineth/web/NewsController.java
  87. 14 1
      src/main/java/com/izouma/nineth/web/NewsLikeController.java
  88. 8 0
      src/main/java/com/izouma/nineth/web/OrderController.java
  89. 6 4
      src/main/java/com/izouma/nineth/web/OrderPayController.java
  90. 38 13
      src/main/java/com/izouma/nineth/web/OrderPayControllerV2.java
  91. 10 0
      src/main/java/com/izouma/nineth/web/PayEaseController.java
  92. 5 0
      src/main/java/com/izouma/nineth/web/SandPayController.java
  93. 5 5
      src/main/java/com/izouma/nineth/web/SmsController.java
  94. 34 0
      src/main/java/com/izouma/nineth/web/UserBalanceController.java
  95. 2 2
      src/main/java/com/izouma/nineth/web/UserController.java
  96. 1 5
      src/main/java/com/izouma/nineth/web/WithdrawApplyController.java
  97. 11 11
      src/main/resources/application.yaml
  98. 0 0
      src/main/resources/genjson/AuctionOrder.json
  99. 69 0
      src/main/vue/src/router.js
  100. 3 0
      src/main/vue/src/views/AppVersionEdit.vue

+ 7 - 0
run_java.sh

@@ -0,0 +1,7 @@
+cd /usr/local/src/raex_back_dev
+git pull
+sh install-jar.sh
+mvn clean package
+systemctl stop 9th_test
+mv -f target/9th-0.0.1-SNAPSHOT.jar /var/www/9th_test/9th-0.0.1-SNAPSHOT.jar
+systemctl start 9th_test

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

@@ -37,5 +37,7 @@ public interface Constants {
         String GIFT     = "gift";
         String MINT     = "mintOrder";
         String RECHARGE = "recharge";
+
+        String AUCTION = "auctionOrder";
     }
 }

+ 5 - 0
src/main/java/com/izouma/nineth/config/RedisKeys.java

@@ -42,4 +42,9 @@ public class RedisKeys {
     public static final String PAY_TMP = "payTmp::";
 
     public static final String FACE_AUTH = "faceAuth::";
+
+    public static final String AUCTION_STATUS = "auctionStatus::";
+
+    public static final String AUCTION_ORDER_LOCK = "auctionOrderLock::";
+
 }

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

@@ -69,4 +69,6 @@ public class AirDrop extends BaseEntity {
 
     @Column(columnDefinition = "tinyint unsigned default 0")
     private boolean auto = false;
+
+    private Long oasisId;
 }

+ 1 - 0
src/main/java/com/izouma/nineth/domain/AppVersion.java

@@ -19,4 +19,5 @@ public class AppVersion extends BaseEntity {
     private boolean review;
     private String  downloadUrl;
     private int     versionNum;
+    private String  channel;
 }

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

@@ -170,6 +170,9 @@ public class Asset extends CollectionBaseEntity {
 
     private Long fromAssetId;
 
+    //地块ID
+    private Long oasisId;
+
     @ApiModelProperty("类型")
     @Enumerated(EnumType.STRING)
     private CollectionType type;
@@ -215,6 +218,7 @@ public class Asset extends CollectionBaseEntity {
     @Column(columnDefinition = "bit(1) default 0")
     private boolean safeFlag;
 
+    private String prefixName;
 
     public static Asset create(Collection collection, User user) {
         return Asset.builder()
@@ -243,6 +247,7 @@ public class Asset extends CollectionBaseEntity {
                 .oldHoldDays(collection.getHoldDays())
                 .source(AssetSource.OFFICIAL)
                 .tags(new HashSet<>(collection.getTags()))
+                .prefixName(collection.getPrefixName())
                 .build();
     }
 

+ 99 - 0
src/main/java/com/izouma/nineth/domain/AuctionActivity.java

@@ -0,0 +1,99 @@
+package com.izouma.nineth.domain;
+
+import com.izouma.nineth.annotations.Searchable;
+import com.izouma.nineth.converter.FileObjectConverter;
+import com.izouma.nineth.converter.FileObjectListConverter;
+import com.izouma.nineth.enums.AuctionSource;
+import com.izouma.nineth.enums.AuctionStatus;
+import com.izouma.nineth.enums.AuctionType;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import javax.persistence.*;
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+import java.util.List;
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+@Builder
+@Entity
+@ApiModel("拍卖藏品")
+public class AuctionActivity extends BaseEntity {
+    @ApiModelProperty("起拍人ID")
+    private Long             sellerId;
+    @ApiModelProperty("起拍人昵称")
+    private String           seller;
+    @ApiModelProperty("起拍人头像")
+    private String           sellerAvatar;
+    @ApiModelProperty("拍卖名称")
+    @Searchable
+    private String           name;
+    @Enumerated(EnumType.STRING)
+    @ApiModelProperty("拍卖类型")
+    private AuctionType      auctionType;
+    @ApiModelProperty("铸造者")
+    private String           minter;
+    @ApiModelProperty("藏品ID")
+    private Long             assetId;
+    @ApiModelProperty("图片")
+    @Column(columnDefinition = "TEXT")
+    @Convert(converter = FileObjectListConverter.class)
+    private List<FileObject> pic;
+    @Column(columnDefinition = "TEXT")
+    @Convert(converter = FileObjectConverter.class)
+    private FileObject       model3d;
+    @ApiModelProperty("详情")
+    @Column(columnDefinition = "TEXT")
+    private String           detail;
+    @ApiModelProperty("分类")
+    private String           category;
+    @ApiModelProperty("起拍价")
+    private BigDecimal       startingPrice;
+    @ApiModelProperty("保证金")
+    private BigDecimal       deposit;
+    @ApiModelProperty("一口价")
+    private BigDecimal       fixedPrice;
+    @ApiModelProperty("开始时间")
+    private LocalDateTime    startTime;
+    @ApiModelProperty("加价幅度")
+    private BigDecimal       increment;
+    @ApiModelProperty("截止时间")
+    private LocalDateTime    endTime;
+    //每次出价实时更新
+    @ApiModelProperty("成交价")
+    private BigDecimal       purchasePrice;
+    @ApiModelProperty("买家id")
+    private Long             purchaserId;
+    @ApiModelProperty("当前竞价id")
+    private Long             recordId;
+    @ApiModelProperty("买家")
+    private String           purchaser;
+    @ApiModelProperty("状态")
+    @Enumerated(EnumType.STRING)
+    private AuctionStatus    status;
+    @ApiModelProperty("来源")
+    private AuctionSource    source;
+    @ApiModelProperty("版税比例")
+    private int              royalties;
+    @ApiModelProperty("手续费比例")
+    private int              serviceCharge;
+    @Column(columnDefinition = "int(11) default 0")
+    @ApiModelProperty("围观次数")
+    private int              likes;
+    @Column(columnDefinition = "int(11) default 0")
+    @ApiModelProperty("出价次数")
+    private int              bids;
+
+    private boolean hasFixedPrice;
+    private boolean liked;
+
+    @ApiModelProperty("上架")
+    @Column(columnDefinition = "tinyint unsigned default 0")
+    private boolean onShelf = false;
+}

+ 107 - 0
src/main/java/com/izouma/nineth/domain/AuctionOrder.java

@@ -0,0 +1,107 @@
+package com.izouma.nineth.domain;
+
+import com.izouma.nineth.annotations.Searchable;
+import com.izouma.nineth.annotations.SearchableOne;
+import com.izouma.nineth.converter.FileObjectListConverter;
+import com.izouma.nineth.enums.*;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import javax.persistence.*;
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+import java.util.List;
+
+@Entity
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+@Builder
+public class AuctionOrder extends BaseEntityNoID {
+    @Id
+    private Long id;
+
+    @ApiModelProperty("用户ID")
+    @SearchableOne
+    private Long userId;
+
+    private String nickname;
+
+    @ApiModelProperty("拍卖ID")
+    private Long auctionId;
+
+    @ApiModelProperty("名称")
+    @SearchableOne
+    private String name;
+
+    @ApiModelProperty("图片")
+    @Column(columnDefinition = "TEXT")
+    @Convert(converter = FileObjectListConverter.class)
+    private List<FileObject> pic;
+
+    @ApiModelProperty("版税比例")
+    private int royalties;
+
+    @ApiModelProperty("手续费比例")
+    private int serviceCharge;
+
+    @Enumerated(EnumType.STRING)
+    @ApiModelProperty("拍卖类型")
+    private AuctionSource source;
+
+    @Enumerated(EnumType.STRING)
+    @ApiModelProperty("支付类型")
+    private AuctionPaymentType paymentType;
+
+    @ApiModelProperty("价格")
+    @Column(precision = 10, scale = 2)
+    private BigDecimal price;
+
+//    @ApiModelProperty("gas费")
+//    @Column(precision = 10, scale = 2)
+//    private BigDecimal gasPrice;
+
+    @ApiModelProperty("总价")
+    @Column(precision = 10, scale = 2)
+    private BigDecimal totalPrice;
+
+    @ApiModelProperty("状态")
+    @Enumerated(EnumType.STRING)
+    private AuctionOrderStatus status;
+
+    @ApiModelProperty("支付方式")
+    @Enumerated(EnumType.STRING)
+    private PayMethod payMethod;
+
+    @ApiModelProperty("交易ID")
+    @Searchable
+    @Column(length = 90)
+    private String transactionId;
+
+    @ApiModelProperty("支付时间")
+    private LocalDateTime payTime;
+
+    @ApiModelProperty("取消时间")
+    private LocalDateTime cancelTime;
+
+    @ApiModelProperty("退款时间")
+    private LocalDateTime refundTime;
+
+    @ApiModelProperty("收货人")
+    private String contactName;
+
+    @ApiModelProperty("收货电话")
+    private String contactPhone;
+
+    @ApiModelProperty("收货地址")
+    private String address;
+
+    @ApiModelProperty("拍卖记录id")
+    private Long auctionRecordId;
+
+    @ApiModelProperty("拍卖记录id")
+    private String courierId;
+}

+ 25 - 0
src/main/java/com/izouma/nineth/domain/AuctionPassRecord.java

@@ -0,0 +1,25 @@
+package com.izouma.nineth.domain;
+
+import io.swagger.annotations.ApiModel;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import javax.persistence.Entity;
+import java.math.BigDecimal;
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+@Builder
+@Entity
+@ApiModel("流拍记录表")
+public class AuctionPassRecord extends BaseEntity {
+    private Long auctionId;
+
+    private Long userId;
+
+    private BigDecimal purchasePrice;
+
+}

+ 52 - 0
src/main/java/com/izouma/nineth/domain/AuctionRecord.java

@@ -0,0 +1,52 @@
+package com.izouma.nineth.domain;
+
+import com.izouma.nineth.enums.AuctionRecordType;
+import com.izouma.nineth.enums.AuctionType;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import javax.persistence.Entity;
+import javax.persistence.EnumType;
+import javax.persistence.Enumerated;
+import java.math.BigDecimal;
+
+@Entity
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+@Builder
+public class AuctionRecord extends BaseEntity {
+    @ApiModelProperty("用户ID")
+    private Long              userId;
+    @ApiModelProperty("用户头像")
+    private String            avatar;
+    @ApiModelProperty("用户昵称")
+    private String            user;
+    @ApiModelProperty("拍卖活动ID")
+    private Long              auctionId;
+    @ApiModelProperty("拍卖活动")
+    private String            name;
+    @ApiModelProperty("拍卖活动图片")
+    private String            auctionPic;
+    @Enumerated(EnumType.STRING)
+    @ApiModelProperty("类型")
+    private AuctionRecordType type;
+    @ApiModelProperty("是否竞得")
+    private boolean           purchased;
+    @ApiModelProperty("出价")
+    private BigDecimal        bidderPrice;
+    @ApiModelProperty("是否支付保证金")
+    private boolean           payDeposit;
+    @Enumerated(EnumType.STRING)
+    @ApiModelProperty("拍卖类型")
+    private AuctionType       auctionType;
+//    @ApiModelProperty("收货人")
+//    private String            contactName;
+//    @ApiModelProperty("收货电话")
+//    private String            contactPhone;
+//    @ApiModelProperty("收货地址")
+//    private String            address;
+}

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

@@ -31,6 +31,8 @@ public class BlindBoxItem extends BaseEntity {
 
     private Long collectionId;
 
+    private Long oasisId;
+
     @ApiModelProperty("名称")
     @Searchable
     private String name;

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

@@ -105,6 +105,8 @@ public class Collection extends CollectionBaseEntity {
     @ApiModelProperty("持有者者ID")
     private Long ownerId;
 
+    private Long oasisId;
+
     @ApiModelProperty("铸造者头像")
     private String ownerAvatar;
 

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

@@ -66,6 +66,8 @@ public class CompanyCollection extends BaseEntity {
     @ApiModelProperty("限购识别码")
     private String countId;
 
+    private Long oasisId;
+
     @Column(columnDefinition = "TEXT")
     @Convert(converter = PropertyListConverter.class)
     @ApiModelProperty("特性")

+ 3 - 1
src/main/java/com/izouma/nineth/domain/NewsLike.java

@@ -13,7 +13,7 @@ import javax.persistence.Table;
 @Data
 @Entity
 @Table(name = "like_info", indexes =
-        {@Index(columnList = "userId"), @Index(columnList = "newsId"), @Index(columnList = "showroomId")})
+        {@Index(columnList = "userId"), @Index(columnList = "newsId"), @Index(columnList = "showroomId"), @Index(columnList = "auctionId")})
 @AllArgsConstructor
 @NoArgsConstructor
 @Builder
@@ -25,4 +25,6 @@ public class NewsLike extends BaseEntity {
     private Long newsId;
 
     private Long showroomId;
+
+    private Long auctionId;
 }

+ 32 - 0
src/main/java/com/izouma/nineth/domain/PurchaserPrivilege.java

@@ -0,0 +1,32 @@
+package com.izouma.nineth.domain;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.time.LocalDateTime;
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+@Builder
+public class PurchaserPrivilege extends BaseEntity {
+    private Long userId;
+
+    @ApiModelProperty("头衔")
+    private String title;
+
+    @ApiModelProperty("拍卖证书")
+    private String certificate;
+
+    @ApiModelProperty("展厅服务")
+    private Long showroomId;
+
+    @ApiModelProperty("优先拍卖")
+    private boolean priority;
+
+    @ApiModelProperty("优先拍卖结束时间")
+    private LocalDateTime priorityExpireAt;
+}

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

@@ -88,4 +88,6 @@ public class Showroom extends BaseEntity {
 
     @Transient
     private Integer num;
+
+    private Long oasisId;
 }

+ 4 - 1
src/main/java/com/izouma/nineth/domain/User.java

@@ -157,8 +157,11 @@ public class User extends UserBaseEntity implements Serializable {
     @Column(columnDefinition = "tinyint unsigned")
     private boolean minter;
 
+    /**
+     * 0 无光 1 绿光 2 金光
+     */
     @ApiModelProperty("使用藏品图片")
-    @Column(columnDefinition = "tinyint unsigned")
+    @Column(columnDefinition = "tinyint unsigned default 0")
     private boolean useCollectionPic;
 
     @Column(columnDefinition = "int(11) default 0")

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

@@ -35,4 +35,8 @@ public class UserAddress extends BaseEntity {
     private String phone;
 
     private boolean def;
+
+    public String getDetail() {
+        return this.getProvinceName() + " " + this.getCityName() + " " + this.getDistrictName() + " " + this.getAddress();
+    }
 }

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

@@ -8,7 +8,7 @@ import org.springframework.data.redis.core.RedisHash;
 
 import javax.persistence.Id;
 
-@RedisHash(value = "UserProperty", timeToLive = 86400L)
+@RedisHash(value = "UserProperty")
 @Data
 @AllArgsConstructor
 @NoArgsConstructor

+ 40 - 0
src/main/java/com/izouma/nineth/dto/AssetDTO.java

@@ -0,0 +1,40 @@
+package com.izouma.nineth.dto;
+
+import com.izouma.nineth.converter.FileObjectListConverter;
+import com.izouma.nineth.domain.Asset;
+import com.izouma.nineth.domain.FileObject;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import javax.persistence.Convert;
+import java.util.List;
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+@Builder
+public class AssetDTO {
+
+    @Convert(converter = FileObjectListConverter.class)
+    private List<FileObject> pic;
+
+    private String minter;
+
+    private List<Asset> assets;
+
+    private int num;
+
+    private String prefixName;
+
+    public static AssetDTO create(List<Asset> asset) {
+        return AssetDTO.builder()
+                .pic(asset.get(0).getPic())
+                .minter(asset.get(0).getMinter())
+                .assets(asset)
+                .num(asset.size())
+                .prefixName(asset.get(0).getPrefixName())
+                .build();
+    }
+}

+ 31 - 0
src/main/java/com/izouma/nineth/dto/auction/AuctionInputDTO.java

@@ -0,0 +1,31 @@
+package com.izouma.nineth.dto.auction;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class AuctionInputDTO {
+    @ApiModelProperty("藏品id")
+    private Long          assetId;
+    @ApiModelProperty("起拍价")
+    private BigDecimal    startingPrice;
+    @ApiModelProperty("保证金")
+    private BigDecimal    deposit;
+    @ApiModelProperty("一口价")
+    private BigDecimal    fixedPrice;
+    @ApiModelProperty("开始时间")
+    private LocalDateTime startTime;
+    @ApiModelProperty("加价幅度")
+    private BigDecimal    increment;
+    @ApiModelProperty("截止时间")
+    private LocalDateTime endTime;
+
+    private String tradeCode;
+}

+ 48 - 0
src/main/java/com/izouma/nineth/dto/auction/AuctionRecordDTO.java

@@ -0,0 +1,48 @@
+package com.izouma.nineth.dto.auction;
+
+import com.izouma.nineth.domain.FileObject;
+import com.izouma.nineth.enums.*;
+import com.izouma.nineth.service.AuctionOrderService;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import net.bytebuddy.agent.builder.AgentBuilder;
+
+import javax.persistence.EnumType;
+import javax.persistence.Enumerated;
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+import java.util.List;
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class AuctionRecordDTO {
+    @ApiModelProperty("用户ID")
+    private Long               userId;
+    @ApiModelProperty("创作者")
+    private String             minter;
+    @ApiModelProperty("拍卖活动ID")
+    private Long               auctionId;
+    @ApiModelProperty("拍卖活动")
+    private String             name;
+    @ApiModelProperty("拍卖活动图片")
+    private List<FileObject>   auctionPic;
+    @Enumerated(EnumType.STRING)
+    @ApiModelProperty("类型")
+    private AuctionRecordType  type;
+    @ApiModelProperty("是否竞得")
+    private boolean            purchased;
+    @ApiModelProperty("出价")
+    private BigDecimal         bidderPrice;
+    private Long               actPurchasedId;
+    private AuctionStatus      auctionStatus;
+    private Long               orderId;
+    private LocalDateTime      endTime;
+    private LocalDateTime      createdTime;
+    private BigDecimal         deposit;
+    private AuctionType        auctionType;
+    private AuctionOrderStatus orderStatus;
+    private AuctionOrderStatus depositStatus;
+}

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

@@ -0,0 +1,27 @@
+package com.izouma.nineth.dto.oasis;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.math.BigDecimal;
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class OasisDistrictCollectionDTO {
+    private Long       oasisId;
+    private String     collectionName;
+    private BigDecimal originPrice;
+    private BigDecimal sellPrice;
+    private String     status;
+    private String     source;
+    private Long       ownerId;
+    private String     owner;
+    private String     ownerName;
+    private String     ownerAvatar;
+    private boolean    salable;
+    private boolean    scanOnly;
+    private Long       collectionId;
+    private String     url;
+}

+ 45 - 0
src/main/java/com/izouma/nineth/dto/oasis/OasisDistrictDTO.java

@@ -0,0 +1,45 @@
+package com.izouma.nineth.dto.oasis;
+
+import com.izouma.nineth.converter.FileObjectConverter;
+import com.izouma.nineth.converter.FileObjectListConverter;
+import com.izouma.nineth.converter.PrivilegeListConverter;
+import com.izouma.nineth.converter.PropertyListConverter;
+import com.izouma.nineth.domain.CollectionProperty;
+import com.izouma.nineth.domain.FileObject;
+import com.izouma.nineth.domain.Privilege;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import javax.persistence.Convert;
+import java.math.BigDecimal;
+import java.util.List;
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class OasisDistrictDTO {
+    private Long                     id;
+    private Long                     oasisId;
+    private String                   name;
+    @Convert(converter = FileObjectListConverter.class)
+    private List<FileObject>         pic;
+    @Convert(converter = FileObjectConverter.class)
+    private FileObject               model3d;
+    private String                   detail;
+    private String                   category;
+    private int                      total;
+    private BigDecimal               price;
+    private BigDecimal               originalPrice;
+
+    private int                      maxCount;
+    @Convert(converter = PropertyListConverter.class)
+    @ApiModelProperty("特性")
+    private List<CollectionProperty> properties;
+    @Convert(converter = PrivilegeListConverter.class)
+    @ApiModelProperty("特权")
+    private List<Privilege>          privileges;
+    @ApiModelProperty("是否可转售")
+    private boolean                  canResale;
+}

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

@@ -0,0 +1,19 @@
+package com.izouma.nineth.dto.oasis;
+
+import com.izouma.nineth.domain.Showroom;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class OasisLoginDTO {
+    private Long     assetId;
+    private Long     oasisId;
+    private String   url;
+    private String   source;
+    private String   token;
+    private Long     userId;
+    private Showroom showroom;
+}

+ 22 - 0
src/main/java/com/izouma/nineth/enums/AuctionOrderStatus.java

@@ -0,0 +1,22 @@
+package com.izouma.nineth.enums;
+
+public enum AuctionOrderStatus {
+    NOT_PAID("未支付"),
+    FINISH("已完成"),
+    CANCELLED("已取消"),
+    REFUNDING("退款中"),
+    REFUNDED("已退款"),
+    DELIVERY("待发货"),
+    RECEIVE("待收货"),
+    AIR_DROP("待空投");
+
+    private final String description;
+
+    AuctionOrderStatus(String description) {
+        this.description = description;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+}

+ 17 - 0
src/main/java/com/izouma/nineth/enums/AuctionPaymentType.java

@@ -0,0 +1,17 @@
+package com.izouma.nineth.enums;
+
+public enum AuctionPaymentType {
+    DEPOSIT("保证金"),
+    PURCHASE_PRICE("成交金"),
+    FIXED_PRICE("一口价");
+
+    private final String description;
+
+    AuctionPaymentType(String description) {
+        this.description = description;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+}

+ 17 - 0
src/main/java/com/izouma/nineth/enums/AuctionRecordType.java

@@ -0,0 +1,17 @@
+package com.izouma.nineth.enums;
+
+public enum AuctionRecordType {
+    DEPOSIT("保证金"),
+    BIDDER("竞拍"),
+    FIXEDPRICE("一口价");
+
+    private final String description;
+
+    AuctionRecordType(String description) {
+        this.description = description;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+}

+ 16 - 0
src/main/java/com/izouma/nineth/enums/AuctionSource.java

@@ -0,0 +1,16 @@
+package com.izouma.nineth.enums;
+
+public enum AuctionSource {
+    OFFICIAL("官方拍卖"),
+    TRANSFER("转让拍卖");
+
+    private final String description;
+
+    AuctionSource(String description) {
+        this.description = description;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+}

+ 20 - 0
src/main/java/com/izouma/nineth/enums/AuctionStatus.java

@@ -0,0 +1,20 @@
+package com.izouma.nineth.enums;
+
+public enum AuctionStatus {
+    NOTSTARTED("未开始"),
+    ONGOING("进行中"),
+    PURCHASED("成交"),
+    FIXED_PRICE_PURCHASED("一口价成交"),
+    PASS("流拍"),
+    FINISH("完成");
+
+    private final String description;
+
+    AuctionStatus(String description) {
+        this.description = description;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+}

+ 16 - 0
src/main/java/com/izouma/nineth/enums/AuctionType.java

@@ -0,0 +1,16 @@
+package com.izouma.nineth.enums;
+
+public enum AuctionType {
+    NFT("虚拟藏品"),
+    ENTITY("实物");
+
+    private final String description;
+
+    AuctionType(String description) {
+        this.description = description;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+}

+ 3 - 0
src/main/java/com/izouma/nineth/enums/BalanceType.java

@@ -4,6 +4,9 @@ public enum BalanceType {
 
     WITHDRAW("提现"),
     SELL("藏品出售"),
+    AUCTION("藏品拍卖"),
+    AUCTION_RETURN("保证金退款"),
+    REWARD("拍卖奖励"),
     RETURN("失败退回"),
     PAY("支付"),
     RECHARGE("充值"),

+ 1 - 0
src/main/java/com/izouma/nineth/enums/BannerType.java

@@ -5,6 +5,7 @@ public enum BannerType {
     DISCOVER("探索"),
     MINTER("铸造者"),
     MARKET("市场"),
+    AUCTION("拍卖"),
     PC_ACT("PC官方活动"),
     PC_TITLE("PC首页大图");
 

+ 2 - 1
src/main/java/com/izouma/nineth/enums/TransferReason.java

@@ -3,7 +3,8 @@ package com.izouma.nineth.enums;
 public enum TransferReason {
     TRANSFER("转让"),
     GIFT("转赠"),
-    DESTROY("销毁")
+    DESTROY("销毁"),
+    AUCTION("拍卖")
     ;
 
     TransferReason(String description) {

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

@@ -15,6 +15,7 @@ public class OrderNotifyEvent implements Serializable {
     public static final String TYPE_MINT_ORDER = "mint_order";
     public static final String TYPE_GIFT_ORDER = "gift_order";
     public static final String TYPE_RECHARGE   = "recharge";
+    public static final String TYPE_AUCTION_ORDER   = "auction_order";
 
     private Long      orderId;
     private PayMethod payMethod;

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

@@ -25,7 +25,7 @@ import java.util.concurrent.TimeUnit;
         consumerGroup = "${general.create-order-group}",
         topic = "${general.create-order-topic}",
         consumeMode = ConsumeMode.ORDERLY)
-@ConditionalOnProperty(value = "general.notify-server", havingValue = "false", matchIfMissing = true)
+@ConditionalOnProperty(value = "general.notify-server", havingValue = "true")
 public class CreateOrderListener implements RocketMQListener<CreateOrderEvent> {
     private OrderService                  orderService;
     private RedisTemplate<String, Object> redisTemplate;

+ 10 - 9
src/main/java/com/izouma/nineth/listener/OrderNotifyListener.java

@@ -1,11 +1,7 @@
 package com.izouma.nineth.listener;
 
-import com.izouma.nineth.enums.PayMethod;
 import com.izouma.nineth.event.OrderNotifyEvent;
-import com.izouma.nineth.service.GiftOrderService;
-import com.izouma.nineth.service.MintOrderService;
-import com.izouma.nineth.service.OrderService;
-import com.izouma.nineth.service.UserBalanceService;
+import com.izouma.nineth.service.*;
 import lombok.AllArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.rocketmq.spring.annotation.ConsumeMode;
@@ -23,10 +19,11 @@ import org.springframework.stereotype.Service;
         consumeMode = ConsumeMode.CONCURRENTLY, consumeThreadMax = 2)
 @ConditionalOnProperty(value = "general.notify-server", havingValue = "true")
 public class OrderNotifyListener implements RocketMQListener<OrderNotifyEvent> {
-    private OrderService       orderService;
-    private MintOrderService   mintOrderService;
-    private GiftOrderService   giftOrderService;
-    private UserBalanceService userBalanceService;
+    private OrderService        orderService;
+    private MintOrderService    mintOrderService;
+    private GiftOrderService    giftOrderService;
+    private UserBalanceService  userBalanceService;
+    private AuctionOrderService auctionOrderService;
 
     @Override
     public void onMessage(OrderNotifyEvent e) {
@@ -43,6 +40,10 @@ public class OrderNotifyListener implements RocketMQListener<OrderNotifyEvent> {
             case OrderNotifyEvent.TYPE_RECHARGE:
                 userBalanceService.recharge(e.getOrderId(), e.getPayMethod(), e.getTransactionId());
                 break;
+            case OrderNotifyEvent.TYPE_AUCTION_ORDER:
+                //拍卖回调
+                auctionOrderService.notify(e.getOrderId(), e.getPayMethod(), e.getTransactionId());
+                break;
             case OrderNotifyEvent.TYPE_ORDER:
             default:
                 orderService.notifyOrder(e.getOrderId(), e.getPayMethod(), e.getTransactionId());

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

@@ -26,7 +26,7 @@ import java.util.regex.Pattern;
         consumerGroup = "${general.register-group}",
         topic = "${general.register-topic}",
         consumeMode = ConsumeMode.ORDERLY)
-@ConditionalOnProperty(value = "general.notify-server", havingValue = "false", matchIfMissing = true)
+@ConditionalOnProperty(value = "general.notify-server", havingValue = "true")
 public class RegisterListener implements RocketMQListener<RegisterEvent> {
     private final JwtTokenUtil                  jwtTokenUtil;
     private       UserService                   userService;

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

@@ -16,7 +16,7 @@ import org.springframework.stereotype.Service;
         consumerGroup = "${general.update-activity-stock-group}",
         topic = "${general.update-activity-stock-topic}",
         consumeMode = ConsumeMode.ORDERLY)
-@ConditionalOnProperty(value = "general.notify-server", havingValue = "false", matchIfMissing = true)
+@ConditionalOnProperty(value = "general.notify-server", havingValue = "true")
 public class UpdateActivityStockListener implements RocketMQListener<Long> {
 
     private MintActivityService mintActivityService;

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

@@ -16,7 +16,7 @@ import org.springframework.stereotype.Service;
         consumerGroup = "${general.update-quota-group}",
         topic = "${general.update-quota-topic}",
         consumeMode = ConsumeMode.ORDERLY)
-@ConditionalOnProperty(value = "general.notify-server", havingValue = "false", matchIfMissing = true)
+@ConditionalOnProperty(value = "general.notify-server", havingValue = "true")
 public class UpdateQuotaListener implements RocketMQListener<Long> {
 
     private CollectionService collectionService;

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

@@ -22,7 +22,7 @@ import java.util.Set;
         consumerGroup = "${general.update-sale-group}",
         topic = "${general.update-sale-topic}",
         consumeMode = ConsumeMode.ORDERLY)
-@ConditionalOnProperty(value = "general.notify-server", havingValue = "false", matchIfMissing = true)
+@ConditionalOnProperty(value = "general.notify-server", havingValue = "true")
 public class UpdateSaleListener implements RocketMQListener<Long> {
 
     private CollectionService             collectionService;

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

@@ -22,7 +22,7 @@ import java.util.Set;
         consumerGroup = "${general.update-stock-group}",
         topic = "${general.update-stock-topic}",
         consumeMode = ConsumeMode.ORDERLY)
-@ConditionalOnProperty(value = "general.notify-server", havingValue = "false", matchIfMissing = true)
+@ConditionalOnProperty(value = "general.notify-server", havingValue = "true")
 public class UpdateStockListener implements RocketMQListener<Long> {
 
     private CollectionService             collectionService;

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

@@ -18,4 +18,8 @@ public interface AppVersionRepo extends JpaRepository<AppVersion, Long>, JpaSpec
     Optional<AppVersion> findByPlatformAndVersionAndDelFalse(String platform, String version);
 
     Optional<AppVersion> findFirstByPlatformAndReviewFalseAndDelFalseOrderByVersionNumDesc(String platform);
+
+    @Query(value = "select * from app_version a where a.platform = ?1 and a.channel = ?2 and a.review = false and a.del = false " +
+            "order by a.version_num desc",nativeQuery = true)
+    Optional<AppVersion> findLatest(String platform, String channel);
 }

+ 11 - 0
src/main/java/com/izouma/nineth/repo/AssetRepo.java

@@ -14,6 +14,7 @@ import java.time.LocalDateTime;
 import java.util.Collection;
 import java.util.List;
 import java.util.Optional;
+import java.util.Set;
 
 public interface AssetRepo extends JpaRepository<Asset, Long>, JpaSpecificationExecutor<Asset> {
     @Query("update Asset t set t.del = true where t.id = ?1")
@@ -27,6 +28,8 @@ public interface AssetRepo extends JpaRepository<Asset, Long>, JpaSpecificationE
 
     List<Asset> findByCollectionIdInAndStatus(Iterable<Long> collectionId, AssetStatus status);
 
+    List<Asset> findAllByCollectionIdInAndStatusIn(List<Long> collectionId, Iterable<AssetStatus> statuses);
+
     List<Asset> findByCreatedAtBefore(LocalDateTime localDateTime);
 
     List<Asset> findByConsignmentTrue();
@@ -43,6 +46,8 @@ public interface AssetRepo extends JpaRepository<Asset, Long>, JpaSpecificationE
     @Query("select a from Asset a join User u on a.userId = u.id where a.consignment = true and u.settleAccountId is null")
     List<Asset> findNoAccount();
 
+    Set<Asset> findAllByUserIdInAndCollectionId(List<Long> ids, Long collectionId);
+
     List<Asset> findByTxHash(String hash);
 
     List<Asset> findByIdIn(Iterable<Long> ids);
@@ -67,6 +72,8 @@ public interface AssetRepo extends JpaRepository<Asset, Long>, JpaSpecificationE
     @Query(value = "select c.id, c.pic, c.model3d, c.minter_avatar, c.owner_avatar, c.detail from asset c", nativeQuery = true)
     List<List<String>> selectResource();
 
+    List<Asset> findAllByOwnerIdAndStatusAndOasisIdNotNull(Long userId, AssetStatus status);
+
     @Modifying
     @Transactional
     @Query(value = "update asset c set c.pic = ?2, c.model3d = ?3, c.minter_avatar = ?4, " +
@@ -76,6 +83,8 @@ public interface AssetRepo extends JpaRepository<Asset, Long>, JpaSpecificationE
 
     Page<Asset> findByUserIdAndStatusAndNameLike(Long userId, AssetStatus status, String name, Pageable pageable);
 
+    List<Asset> findAllByOasisIdInAndStatusIn(List<Long> oasisIds, List<AssetStatus> assetStatuses);
+
     List<Asset> findAllByUserIdAndCollectionIdAndStatus(Long userId, Long collectionId, AssetStatus status);
 
     @Modifying
@@ -92,4 +101,6 @@ public interface AssetRepo extends JpaRepository<Asset, Long>, JpaSpecificationE
     @Query(nativeQuery = true, value = "select id from asset where user_id = ?1 and collection_id in ?2 " +
             "and status = 'NORMAL' limit 1")
     Long findDiscount(Long userId, Collection<Long> ids);
+
+    List<Asset> findByStatus(AssetStatus status);
 }

+ 51 - 0
src/main/java/com/izouma/nineth/repo/AuctionActivityRepo.java

@@ -0,0 +1,51 @@
+package com.izouma.nineth.repo;
+
+import com.izouma.nineth.domain.AuctionActivity;
+import com.izouma.nineth.enums.AuctionStatus;
+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.Collection;
+import java.util.List;
+
+public interface AuctionActivityRepo extends JpaRepository<AuctionActivity, Long>, JpaSpecificationExecutor<AuctionActivity> {
+    @Query("update AuctionActivity t set t.del = true where t.id = ?1")
+    @Modifying
+    @Transactional
+    void softDelete(Long id);
+
+    @Query("select status from AuctionActivity where id = ?1")
+    String getStatus(Long id);
+
+    @Modifying
+    @Transactional
+    @Query("update AuctionActivity set status = ?2 where id = ?1")
+    void updateStatus(Long id, AuctionStatus status);
+
+    @Query("update AuctionActivity t set t.likes = t.likes + ?2 where t.id = ?1")
+    @Modifying
+    @Transactional
+    void addLike(Long id, int num);
+
+    @Transactional
+    @Modifying
+    @Query("update AuctionActivity c set c.status = ?2 where c.id = ?1")
+    void scheduleOffShelf(Long id, AuctionStatus status);
+
+    List<AuctionActivity> findAllByStatus(AuctionStatus auctionStatus);
+
+    List<AuctionActivity> findByAssetId(Long assetId);
+
+    List<AuctionActivity> findByStartTimeBeforeAndStatusIn(LocalDateTime startTime, Collection<AuctionStatus> status);
+
+    List<AuctionActivity> findByStartTimeBeforeAndStatus(LocalDateTime startTime, AuctionStatus status);
+
+    @Modifying
+    @Transactional
+    @Query("update AuctionActivity set onShelf = ?2 where assetId = ?1 and onShelf <> ?2")
+    void updateOnShelf(Long assetId, boolean onShelf);
+}

+ 35 - 0
src/main/java/com/izouma/nineth/repo/AuctionOrderRepo.java

@@ -0,0 +1,35 @@
+package com.izouma.nineth.repo;
+
+import com.izouma.nineth.domain.AuctionOrder;
+import com.izouma.nineth.enums.AuctionPaymentType;
+import com.izouma.nineth.enums.AuctionOrderStatus;
+import com.izouma.nineth.enums.AuctionStatus;
+import com.izouma.nineth.service.AuctionOrderService;
+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.Collection;
+import java.util.List;
+
+public interface AuctionOrderRepo extends JpaRepository<AuctionOrder, Long>, JpaSpecificationExecutor<AuctionOrder> {
+    @Query("update AuctionOrder t set t.del = true where t.id = ?1")
+    @Modifying
+    @Transactional
+    void softDelete(Long id);
+
+    AuctionOrder findByUserIdAndAuctionIdAndPaymentTypeAndStatusIn(Long userId, Long auctionId, AuctionPaymentType paymentType, Collection<AuctionOrderStatus> status);
+
+    List<AuctionOrder> findAllByAuctionIdAndPaymentTypeAndStatus(Long auctionId, AuctionPaymentType paymentType, AuctionOrderStatus status);
+
+    List<AuctionOrder> findByStatusAndCreatedAtBeforeAndDelFalse(AuctionOrderStatus status, LocalDateTime createdAt);
+
+    AuctionOrder findFirstByAuctionRecordIdOrderByCreatedAt(Long recordId);
+
+    AuctionOrder findFirstByAuctionRecordIdOrderByIdDesc(Long recordId);
+
+    AuctionOrder findFirstByAuctionIdAndPaymentTypeAndStatusNotInAndUserIdOrderByIdDesc(Long auctionId, AuctionPaymentType paymentType, Collection<AuctionOrderStatus> status, Long userId);
+}

+ 21 - 0
src/main/java/com/izouma/nineth/repo/AuctionPassRecordRepo.java

@@ -0,0 +1,21 @@
+package com.izouma.nineth.repo;
+
+import com.izouma.nineth.domain.AuctionPassRecord;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
+import org.springframework.data.jpa.repository.Modifying;
+import org.springframework.data.jpa.repository.Query;
+
+import javax.transaction.Transactional;
+import java.util.List;
+
+public interface AuctionPassRecordRepo extends JpaRepository<AuctionPassRecord, Long>, JpaSpecificationExecutor<AuctionPassRecord> {
+    @Query("update AuctionPassRecord t set t.del = true where t.id = ?1")
+    @Modifying
+    @Transactional
+    void softDelete(Long id);
+
+    @Query(nativeQuery = true, value = "select r.user_id  from auction_pass_record r " +
+            "GROUP BY r.user_id HAVING count(*) > 5")
+    List<Long> checkUserId();
+}

+ 35 - 0
src/main/java/com/izouma/nineth/repo/AuctionRecordRepo.java

@@ -0,0 +1,35 @@
+package com.izouma.nineth.repo;
+
+import com.izouma.nineth.domain.AuctionRecord;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
+import org.springframework.data.jpa.repository.Modifying;
+import org.springframework.data.jpa.repository.Query;
+
+import javax.transaction.Transactional;
+import java.util.List;
+
+public interface AuctionRecordRepo extends JpaRepository<AuctionRecord, Long>, JpaSpecificationExecutor<AuctionRecord> {
+    @Query("update AuctionRecord t set t.del = true where t.id = ?1")
+    @Modifying
+    @Transactional
+    void softDelete(Long id);
+
+    AuctionRecord findTopByAuctionIdAndUserIdOrderByIdDesc(Long auctionId, Long userId);
+
+    @Modifying
+    @Transactional
+    void deleteAllByAuctionId(Long auctionId);
+
+    @Query(nativeQuery = true, value = "WITH ranked_messages AS (" +
+            " SELECT m.*, ROW_NUMBER() OVER (PARTITION BY auction_id ORDER BY id DESC) AS rn" +
+            "    FROM auction_record AS m where user_id = ?1 and auction_type = ?2)" +
+            " SELECT * FROM ranked_messages WHERE rn = 1;")
+    List<AuctionRecord> findByUserId(Long userId, String auctionType);
+
+    @Query(nativeQuery = true, value = "WITH ranked_messages AS (" +
+            " SELECT m.user_id, ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY id DESC) AS rn" +
+            "    FROM auction_record AS m where auction_id = ?1 and type = 'DEPOSIT' and pay_deposit = true)" +
+            " SELECT * FROM ranked_messages WHERE rn = 1 limit ?2;")
+    List<Long> findByAuctionId(Long auctionId, int size);
+}

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

@@ -171,4 +171,8 @@ public interface CollectionRepo extends JpaRepository<Collection, Long>, JpaSpec
 
     @Query("select count(id) from Collection where source = 'TRANSFER' and name like ?1")
     int countAllByNameLike(String name);
+
+    Collection findFirstByOnShelfAndAssetId(boolean onShelf, Long assetId);
+
+    List<Collection> findAllByOasisIdInAndSourceInAndStockGreaterThan(List<Long> oasisIds, List<CollectionSource> sources, int sale);
 }

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

@@ -1,16 +1,20 @@
 package com.izouma.nineth.repo;
 
 import com.izouma.nineth.domain.CompanyCollection;
+import com.izouma.nineth.enums.CollectionStatus;
 import org.springframework.data.jpa.repository.JpaRepository;
 import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
 import org.springframework.data.jpa.repository.Modifying;
 import org.springframework.data.jpa.repository.Query;
 
 import javax.transaction.Transactional;
+import java.util.List;
 
 public interface CompanyCollectionRepo extends JpaRepository<CompanyCollection, Long>, JpaSpecificationExecutor<CompanyCollection> {
     @Query("update CompanyCollection t set t.del = true where t.id = ?1")
     @Modifying
     @Transactional
     void softDelete(Long id);
+
+    List<CompanyCollection> findAllByOasisIdInAndStatusNot(List<Long> ids, CollectionStatus status);
 }

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

@@ -20,5 +20,7 @@ public interface NewsLikeRepo extends JpaRepository<NewsLike, Long>, JpaSpecific
 
     List<NewsLike> findByUserIdAndShowroomId(Long userId, Long showroomId);
 
+    List<NewsLike> findByUserIdAndAuctionId(Long userId, Long auctionId);
+
     List<NewsLike> findByUserIdAndShowroomIdIn(Long userId, Collection<Long> showroomId);
 }

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

@@ -63,4 +63,7 @@ public interface ShowroomRepo extends JpaRepository<Showroom, Long>, JpaSpecific
 
     @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);
+
+    Optional<Showroom> findByOasisId(Long oasisId);
+
 }

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

@@ -9,6 +9,7 @@ import org.springframework.data.jpa.repository.Query;
 import javax.transaction.Transactional;
 import java.math.BigDecimal;
 import java.util.List;
+import java.util.Optional;
 
 public interface UserBalanceRepo extends JpaRepository<UserBalance, Long>, JpaSpecificationExecutor<UserBalance> {
 
@@ -21,4 +22,6 @@ public interface UserBalanceRepo extends JpaRepository<UserBalance, Long>, JpaSp
     @Transactional
     int unlock(Long userId);
 
+    Optional<UserBalance> findByUserId(Long userId);
+
 }

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

@@ -24,6 +24,11 @@ public interface UserRepo extends JpaRepository<User, Long>, JpaSpecificationExe
     @Query("update User u set u.del = true where u.id = ?1")
     void softDelete(Long id);
 
+    @Transactional
+    @Modifying
+    @Query("update User u set u.del = true where u.del = false and u.id in ?1")
+    void softDeleteIn(Collection<Long> id);
+
     Optional<User> findByUsernameAndDelFalse(String username);
 
     List<User> findAllByAuthoritiesContainsAndDelFalse(Authority authority);
@@ -173,7 +178,9 @@ public interface UserRepo extends JpaRepository<User, Long>, JpaSpecificationExe
 
     List<User> findAllByCollectionIdAndCollectionInvitor(Long collectionId, Long collectionInvitor);
 
-    int countAllByCollectionIdAndCollectionInvitor(Long collectionId, Long collectionInvitor);
+    List<User> findAllByCollectionIdAndCollectionInvitorAndSettleAccountIdIsNotNull(Long collectionId, Long collectionInvitor);
+
+    int countAllByCollectionIdAndCollectionInvitorAndSettleAccountIdIsNotNull(Long collectionId, Long collectionInvitor);
 
     long countAllByDelFalse();
 

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

@@ -122,9 +122,16 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
                 .antMatchers("/hmpay/**").permitAll()
                 .antMatchers("/payease/**").permitAll()
                 .antMatchers("/order/calcSettle").permitAll()
+                .antMatchers("/auctionOrder/all").permitAll()
+                .antMatchers("/auctionOrder/get/**").permitAll()
+                .antMatchers("/auctionActivity/all").permitAll()
+                .antMatchers("/auctionActivity/get/**").permitAll()
+                .antMatchers("/auctionRecord/all").permitAll()
                 .antMatchers("/ossNotify").permitAll()
                 .antMatchers("/priceList/list").permitAll()
                 .antMatchers("/user/collectionInvitorList").permitAll()
+                .antMatchers("/auth/oasisLogin").permitAll()
+                .antMatchers("/auth/oasisLoginPhone").permitAll()
                 .antMatchers("/payOrder/v2/**/sandQuick").permitAll()
                 .antMatchers("/pay/v2/**/sandQuick").permitAll()
                 .antMatchers("/user/faceAuthNotify/*").permitAll()

+ 21 - 5
src/main/java/com/izouma/nineth/service/AirDropService.java

@@ -12,6 +12,8 @@ import lombok.AllArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang3.ObjectUtils;
 import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Lazy;
 import org.springframework.data.domain.Page;
 import org.springframework.scheduling.annotation.Async;
 import org.springframework.stereotype.Service;
@@ -21,24 +23,35 @@ import java.util.List;
 import java.util.stream.Collectors;
 
 @Service
-@AllArgsConstructor
 @Slf4j
 public class AirDropService {
-
+    @Autowired
     private AirDropRepo             airDropRepo;
+    @Autowired
     private CouponRepo              couponRepo;
+    @Autowired
     private UserCouponRepo          userCouponRepo;
+    @Autowired
     private CollectionRepo          collectionRepo;
+    @Autowired
     private UserRepo                userRepo;
+    @Lazy
+    @Autowired
     private AssetService            assetService;
+    @Autowired
     private CollectionService       collectionService;
+    @Autowired
     private ShowroomService         showroomService;
+    @Autowired
     private TokenHistoryRepo        tokenHistoryRepo;
+    @Autowired
     private AssetRepo               assetRepo;
+    @Autowired
     private CollectionPrivilegeRepo collectionPrivilegeRepo;
 
     public Page<AirDrop> all(PageQuery pageQuery) {
-        return airDropRepo.findAll(JpaUtils.toSpecification(pageQuery, AirDrop.class), JpaUtils.toPageRequest(pageQuery));
+        return airDropRepo
+                .findAll(JpaUtils.toSpecification(pageQuery, AirDrop.class), JpaUtils.toPageRequest(pageQuery));
     }
 
     public AirDrop create(AirDrop record) {
@@ -122,6 +135,7 @@ public class AirDropService {
 
                                 //创建展厅
                                 if (collection.getType() == CollectionType.SHOWROOM) {
+                                    asset.setOasisId(record.getOasisId());
                                     showroomService.save(asset);
                                 }
                                 //铸造空投的t+0
@@ -169,7 +183,8 @@ public class AirDropService {
                 asset.setCreatedAt(time.plusSeconds((long) (Math.random() * 120)));
                 assetRepo.save(asset);
 
-                for (TokenHistory tokenHistory : tokenHistoryRepo.findByTokenIdOrderByCreatedAtDesc(asset.getTokenId())) {
+                for (TokenHistory tokenHistory : tokenHistoryRepo
+                        .findByTokenIdOrderByCreatedAtDesc(asset.getTokenId())) {
                     tokenHistory.setCreatedAt(asset.getCreatedAt());
                     tokenHistoryRepo.save(tokenHistory);
                 }
@@ -200,7 +215,8 @@ public class AirDropService {
                 asset.setCreatedAt(time.plusSeconds((long) (Math.random() * 120)));
                 assetRepo.save(asset);
 
-                for (TokenHistory tokenHistory : tokenHistoryRepo.findByTokenIdOrderByCreatedAtDesc(asset.getTokenId())) {
+                for (TokenHistory tokenHistory : tokenHistoryRepo
+                        .findByTokenIdOrderByCreatedAtDesc(asset.getTokenId())) {
                     tokenHistory.setCreatedAt(asset.getCreatedAt());
                     tokenHistoryRepo.save(tokenHistory);
                 }

+ 117 - 18
src/main/java/com/izouma/nineth/service/AssetService.java

@@ -1,15 +1,13 @@
 package com.izouma.nineth.service;
 
-import cn.hutool.core.convert.Convert;
+import com.google.common.collect.Lists;
 import com.izouma.nineth.TokenHistory;
 import com.izouma.nineth.config.Constants;
 import com.izouma.nineth.config.GeneralProperties;
 import com.izouma.nineth.converter.LongArrayConverter;
 import com.izouma.nineth.domain.Collection;
 import com.izouma.nineth.domain.*;
-import com.izouma.nineth.dto.PageQuery;
-import com.izouma.nineth.dto.PageWrapper;
-import com.izouma.nineth.dto.UserHistory;
+import com.izouma.nineth.dto.*;
 import com.izouma.nineth.enums.*;
 import com.izouma.nineth.exception.BusinessException;
 import com.izouma.nineth.repo.*;
@@ -18,16 +16,18 @@ import com.izouma.nineth.utils.SecurityUtils;
 import com.izouma.nineth.utils.TokenUtils;
 import lombok.AllArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections.CollectionUtils;
 import org.apache.commons.lang3.ObjectUtils;
 import org.apache.commons.lang3.RandomStringUtils;
+import org.apache.commons.lang3.StringUtils;
 import org.apache.rocketmq.spring.core.RocketMQTemplate;
 import org.springframework.beans.BeanUtils;
 import org.springframework.cache.annotation.Cacheable;
-import org.springframework.context.ApplicationContext;
 import org.springframework.data.domain.Page;
 import org.springframework.data.domain.PageImpl;
 import org.springframework.data.domain.Pageable;
 import org.springframework.data.jpa.domain.Specification;
+import org.springframework.scheduling.annotation.Async;
 import org.springframework.scheduling.annotation.Scheduled;
 import org.springframework.security.crypto.password.PasswordEncoder;
 import org.springframework.stereotype.Service;
@@ -39,6 +39,7 @@ import java.time.temporal.ChronoUnit;
 import java.util.*;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.ForkJoinPool;
+import java.util.concurrent.atomic.AtomicInteger;
 import java.util.stream.Collectors;
 
 @Service
@@ -49,7 +50,6 @@ public class AssetService {
     private AssetRepo               assetRepo;
     private UserRepo                userRepo;
     private CollectionRepo          collectionRepo;
-    private ApplicationContext      applicationContext;
     private OrderRepo               orderRepo;
     private TokenHistoryRepo        tokenHistoryRepo;
     private SysConfigService        sysConfigService;
@@ -61,22 +61,60 @@ public class AssetService {
     private PasswordEncoder         passwordEncoder;
     private MintActivityRepo        mintActivityRepo;
     private DestroyRecordRepo       destroyRecordRepo;
+    private AirDropService          airDropService;
+    private HCChainService          hcChainService;
 
     public Page<Asset> all(PageQuery pageQuery) {
         Page<Asset> all = assetRepo
                 .findAll(JpaUtils.toSpecification(pageQuery, Asset.class), JpaUtils.toPageRequest(pageQuery));
-        Map<String, Object> query = pageQuery.getQuery();
-        if (query.containsKey("userId")) {
-            List<Long> orderId = orderRepo
-                    .findAllByUserIdAndOpenedFalse(Convert.convert(Long.class, query.get("userId")));
-            return all.map(asset -> {
-                if (orderId.contains(asset.getOrderId())) {
-                    asset.setOpened(false);
-                }
-                return asset;
+//        Map<String, Object> query = pageQuery.getQuery();
+//        if (query.containsKey("userId")) {
+//            List<Long> orderId = orderRepo
+//                    .findAllByUserIdAndOpenedFalse(Convert.convert(Long.class, query.get("userId")));
+//            return all.map(asset -> {
+//                if (orderId.contains(asset.getOrderId())) {
+//                    asset.setOpened(false);
+//                }
+//                return asset;
+//            });
+//        }
+        return all;
+    }
+
+    public List<AssetDTO> superimposition(PageQuery pageQuery) {
+        List<AssetDTO> assetDTOs = new ArrayList<>();
+        // 根据条件查询所有资产
+        List<Asset> assets = assetRepo.findAll(JpaUtils.toSpecification(pageQuery, Asset.class));
+        if (CollectionUtils.isEmpty(assets)) {
+            return assetDTOs;
+        }
+        // 取出资产中未开启盲盒数据
+        List<Asset> blindBoxClosedAssets = assets.stream().filter(asset -> !asset.isOpened() && CollectionType.BLIND_BOX.equals(asset.getType())).collect(Collectors.toList());
+        if (CollectionUtils.isNotEmpty(blindBoxClosedAssets)) {
+            blindBoxClosedAssets.forEach(asset -> {
+                assetDTOs.add(AssetDTO.create(Lists.newArrayList(asset)));
+            });
+            // 移除资产中未开启盲盒数据
+            assets.removeAll(blindBoxClosedAssets);
+        }
+        // 取出资产中所有未设置prefixName的值
+        List<Asset> prefixNameIsNullAssets = assets.stream().filter(asset -> StringUtils.isBlank(asset.getPrefixName())).collect(Collectors.toList());
+        if (CollectionUtils.isNotEmpty(prefixNameIsNullAssets)) {
+            prefixNameIsNullAssets.forEach(asset -> {
+                assetDTOs.add(AssetDTO.create(Lists.newArrayList(asset)));
+            });
+            assets.removeAll(prefixNameIsNullAssets);
+        }
+        if (CollectionUtils.isNotEmpty(assets)) {
+            // 取出资产中所有prefixName
+            List<String> prefixNames = assets.stream().map(Asset::getPrefixName).distinct().collect(Collectors.toList());
+            // 将资产中相同prefixName归类(除未开启盲盒和未设置prefixName)
+            prefixNames.forEach(str -> {
+                List<Asset> collect = assets.stream().filter(asset -> str.equals(asset.getPrefixName())).collect(Collectors.toList());
+                assetDTOs.add(AssetDTO.create(collect));
             });
         }
-        return all;
+        return assetDTOs;
     }
 
     public Asset createAsset(Collection collection, User user, Long orderId, BigDecimal price, String type,
@@ -84,6 +122,7 @@ public class AssetService {
         Asset asset = Asset.create(collection, user);
         asset.setTokenId(TokenUtils.genTokenId());
         asset.setNumber(number);
+        asset.setOasisId(collection.getOasisId());
         asset.setOrderId(orderId);
         asset.setPrice(price);
         asset.setTags(new HashSet<>());
@@ -111,6 +150,28 @@ public class AssetService {
                 .price(price)
                 .build());
         rocketMQTemplate.syncSend(generalProperties.getMintTopic(), asset.getId());
+        if (asset.getOasisId() != null & asset.getSource().equals(AssetSource.OFFICIAL)) {
+            AirDrop airDrop = new AirDrop();
+            airDrop.setName("建筑空投展厅");
+            airDrop.setCollectionId(207012L);
+            List<Long> userIds = new ArrayList<>();
+            userIds.add(user.getId());
+            List<Long> nums = new ArrayList<>();
+            nums.add(1L);
+            airDrop.setType(AirDropType.asset);
+            List<DropTarget> dropTargets = new ArrayList<>();
+            DropTarget dropTarget = new DropTarget();
+            dropTarget.setNickname(user.getNickname());
+            dropTarget.setNum(1);
+            dropTarget.setPhone(user.getPhone());
+            dropTarget.setUserId(user.getId());
+            dropTargets.add(dropTarget);
+            airDrop.setTargets(dropTargets);
+            airDrop.setUserIds(userIds);
+            airDrop.setNum(nums);
+            airDropService.create(airDrop);
+
+        }
         return asset;
     }
 
@@ -123,8 +184,10 @@ public class AssetService {
         Asset asset = Asset.create(winItem, user, holdDays);
         asset.setTokenId(TokenUtils.genTokenId());
         asset.setNumber(number);
+        asset.setOasisId(winItem.getOasisId());
         asset.setOrderId(orderId);
         asset.setPrice(price);
+        asset.setPrefixName(collection.getPrefixName());
         asset.setTags(new HashSet<>());
         if (blindBox.getTags() != null) {
             asset.getTags().addAll(blindBox.getTags());
@@ -178,6 +241,7 @@ public class AssetService {
                 .minterId(asset.getMinterId())
                 .minterAvatar(asset.getMinterAvatar())
                 .owner(owner.getNickname())
+                .oasisId(asset.getOasisId())
                 .ownerId(owner.getId())
                 .ownerAvatar(owner.getAvatar())
                 .detail(asset.getDetail())
@@ -268,6 +332,7 @@ public class AssetService {
                 .minterAvatar(asset.getMinterAvatar())
                 .owner(owner.getNickname())
                 .ownerId(owner.getId())
+                .oasisId(asset.getOasisId())
                 .ownerAvatar(owner.getAvatar())
                 .detail(asset.getDetail())
                 .type(CollectionType.DEFAULT)
@@ -402,6 +467,7 @@ public class AssetService {
         newAsset.setPrice(price);
         newAsset.setSellPrice(null);
         newAsset.setOrderId(orderId);
+        newAsset.setOasisId(asset.getOasisId());
         newAsset.setFromAssetId(asset.getId());
         newAsset.setType(CollectionType.DEFAULT);
         newAsset.setSource(TransferReason.GIFT == reason ? AssetSource.GIFT : AssetSource.TRANSFER);
@@ -426,7 +492,16 @@ public class AssetService {
         asset.setPublicShow(false);
         asset.setConsignment(false);
         asset.setPublicCollectionId(null);
-        asset.setStatus(TransferReason.GIFT == reason ? AssetStatus.GIFTED : AssetStatus.TRANSFERRED);
+        switch (reason) {
+            case GIFT:
+                asset.setStatus(AssetStatus.GIFTED);
+                break;
+            case AUCTION:
+                asset.setStatus(AssetStatus.AUCTIONED);
+                break;
+            case TRANSFER:
+                asset.setStatus(AssetStatus.TRANSFERRED);
+        }
         asset.setOwner(newOwner.getNickname());
         asset.setOwnerId(newOwner.getId());
         asset.setOwnerAvatar(newOwner.getAvatar());
@@ -726,7 +801,7 @@ public class AssetService {
         userRepo.addDestroyPoint(userId, 1);
     }
 
-    public int getRoyalties(Long minterId, int royalties,Long userId) {
+    public int getRoyalties(Long minterId, int royalties, Long userId) {
         if (royalties == 3) {
             return 3;
         }
@@ -743,4 +818,28 @@ public class AssetService {
         }
         return royalties;
     }
+
+    @Async
+    public void hcChain() throws ExecutionException, InterruptedException {
+        new ForkJoinPool(1000).submit(() -> {
+            AtomicInteger num = new AtomicInteger();
+            assetRepo.findByStatus(AssetStatus.NORMAL).parallelStream()
+                    .forEach(asset -> {
+                        if (asset.getHcTxHash() == null) {
+                            User user = userRepo.findById(asset.getUserId()).orElse(null);
+                            if (user != null) {
+                                if (user.getHcChainAddress() == null) {
+                                    user.setHcChainAddress(hcChainService.createAccount(asset.getUserId()));
+                                }
+                                NFT nft = hcChainService.mint(user.getHcChainAddress(), asset.getTokenId());
+                                asset.setHcTokenId(nft.getTokenId());
+                                asset.setHcTxHash(nft.getTxHash());
+                                asset.setGasUsed(nft.getGasUsed());
+                                assetRepo.save(asset);
+                            }
+                        }
+                        log.info("hcChain:" + num.getAndIncrement());
+                    });
+        }).get();
+    }
 }

+ 315 - 0
src/main/java/com/izouma/nineth/service/AuctionActivityService.java

@@ -0,0 +1,315 @@
+package com.izouma.nineth.service;
+
+import cn.hutool.core.collection.CollUtil;
+import com.izouma.nineth.config.RedisKeys;
+import com.izouma.nineth.domain.Asset;
+import com.izouma.nineth.domain.AuctionActivity;
+import com.izouma.nineth.domain.User;
+import com.izouma.nineth.dto.PageQuery;
+import com.izouma.nineth.dto.auction.AuctionInputDTO;
+import com.izouma.nineth.enums.*;
+import com.izouma.nineth.exception.BusinessException;
+import com.izouma.nineth.repo.AssetRepo;
+import com.izouma.nineth.repo.AuctionActivityRepo;
+import com.izouma.nineth.repo.TokenHistoryRepo;
+import com.izouma.nineth.repo.UserRepo;
+import com.izouma.nineth.utils.JpaUtils;
+import com.izouma.nineth.utils.SecurityUtils;
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.ObjectUtils;
+import org.springframework.core.env.Environment;
+import org.springframework.data.domain.Page;
+import org.springframework.data.redis.core.BoundValueOperations;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.scheduling.TaskScheduler;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.security.crypto.password.PasswordEncoder;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.PostConstruct;
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+import java.time.ZoneId;
+import java.util.*;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
+
+@Slf4j
+@Service
+@AllArgsConstructor
+public class AuctionActivityService {
+
+    private final AuctionActivityRepo           auctionActivityRepo;
+    private final AssetRepo                     assetRepo;
+    private final UserRepo                      userRepo;
+    private final PasswordEncoder               passwordEncoder;
+    private final RedisTemplate<String, Object> redisTemplate;
+    private final CacheService                  cacheService;
+    private final TaskScheduler                 taskScheduler;
+    private final Environment                   env;
+    private final TokenHistoryRepo              tokenHistoryRepo;
+    private final SysConfigService              sysConfigService;
+
+    private final Map<Long, ScheduledFuture<?>> tasks = new HashMap<>();
+
+    @PostConstruct
+    public void init() {
+        if (Arrays.asList(env.getActiveProfiles()).contains("dev")) {
+            return;
+        }
+        List<AuctionActivity> activities = auctionActivityRepo.findByStartTimeBeforeAndStatus(LocalDateTime.now(),
+                AuctionStatus.NOTSTARTED);
+        for (AuctionActivity activity : activities) {
+            onShelfTask(activity);
+        }
+    }
+
+    public Page<AuctionActivity> all(PageQuery pageQuery) {
+        return auctionActivityRepo
+                .findAll(JpaUtils.toSpecification(pageQuery, AuctionActivity.class), JpaUtils.toPageRequest(pageQuery));
+    }
+
+    public AuctionActivity createFromAsset(AuctionInputDTO dto) {
+        Asset asset = assetRepo.findById(dto.getAssetId()).orElseThrow(new BusinessException("暂无"));
+
+        //拍卖周期
+        BigDecimal auctionCycle = sysConfigService.getBigDecimal("auction_cycle");
+
+        AuctionActivity auctionActivity = new AuctionActivity();
+        auctionActivity.setAuctionType(AuctionType.NFT);
+        auctionActivity.setAssetId(dto.getAssetId());
+        auctionActivity.setStatus(AuctionStatus.ONGOING);
+        auctionActivity.setBids(0);
+        auctionActivity.setCategory(asset.getCategory());
+        auctionActivity.setEndTime(LocalDateTime.now()
+                .plusHours(auctionCycle.multiply(new BigDecimal("24")).intValue()));
+        auctionActivity.setDeposit(dto.getDeposit());
+        if (Arrays.asList(env.getActiveProfiles()).contains("staging")) {
+            auctionActivity.setEndTime(LocalDateTime.now().plusMinutes(8));
+        }
+        auctionActivity.setDetail(asset.getDetail());
+        auctionActivity.setFixedPrice(dto.getFixedPrice());
+        auctionActivity.setIncrement(dto.getIncrement());
+        auctionActivity.setMinter(asset.getMinter());
+        auctionActivity.setPic(asset.getPic());
+        auctionActivity.setModel3d(asset.getModel3d());
+        auctionActivity.setName(asset.getName());
+        auctionActivity.setSeller(asset.getOwner());
+        auctionActivity.setSellerId(asset.getOwnerId());
+        auctionActivity.setStartTime(LocalDateTime.now());
+        auctionActivity.setSource(AuctionSource.TRANSFER);
+        //固定值 or 资产值
+        auctionActivity.setServiceCharge(asset.getServiceCharge());
+        auctionActivity.setRoyalties(asset.getRoyalties());
+
+        auctionActivity.setStartingPrice(dto.getStartingPrice());
+        auctionActivity.setHasFixedPrice(auctionActivity.getFixedPrice() != null);
+        return save(auctionActivity, dto.getTradeCode());
+    }
+
+
+    public AuctionActivity save(AuctionActivity record, String tradeCode) {
+        if (record.getSource().equals(AuctionSource.OFFICIAL)) {
+            record.setStatus(AuctionStatus.NOTSTARTED);
+        }
+        if (record.getSource().equals(AuctionSource.TRANSFER) && !record.getSellerId().equals(9859L)) {
+            User user = userRepo.findById(record.getSellerId()).orElseThrow(new BusinessException("无用户信息"));
+            if (!passwordEncoder.matches(tradeCode, user.getTradeCode())) {
+                throw new BusinessException("交易密码错误");
+            }
+            if (!AuthStatus.SUCCESS.equals(user.getAuthStatus())) {
+                throw new BusinessException("未实名或实名未通过");
+            }
+            BigDecimal userBuy = tokenHistoryRepo.userBuy(record.getSellerId());
+            BigDecimal num = sysConfigService.getBigDecimal("auction_lvzhoushi_num");
+            if (userBuy.compareTo(num) < 0) {
+                throw new BusinessException("绿洲石不足");
+            }
+
+            Asset asset = assetRepo.findById(record.getAssetId()).orElseThrow(new BusinessException("未找到该藏品"));
+            if (!asset.getOwnerId().equals(SecurityUtils.getAuthenticatedUser().getId())) {
+                throw new BusinessException("非本人藏品,无法操作.");
+            }
+            if (!asset.getStatus().equals(AssetStatus.NORMAL)) {
+                throw new BusinessException("藏品状态异常,无法操作.");
+            }
+            if (asset.isPublicShow() || asset.isConsignment()) {
+//                throw new BusinessException("藏品已寄售,取消寄售后再申请拍卖。");
+                throw new BusinessException("请先下架藏品");
+            }
+
+            //是否二次拍卖
+            List<AuctionActivity> activity = auctionActivityRepo.findByAssetId(asset.getId());
+            if (CollUtil.isNotEmpty(activity)) {
+                if (activity.stream().anyMatch(ac -> !AuctionStatus.PASS.equals(ac.getStatus()))) {
+                    throw new BusinessException("已有拍卖");
+                }
+                log.info("下架流拍拍卖:assetId-{}", asset.getId());
+                auctionActivityRepo.updateOnShelf(asset.getId(), false);
+            }
+
+            asset.setStatus(AssetStatus.AUCTIONING);
+            assetRepo.save(asset);
+        }
+
+        //上架
+        record.setOnShelf(true);
+        AuctionActivity saved = auctionActivityRepo.save(record);
+        if (saved.getStatus().equals(AuctionStatus.NOTSTARTED)) {
+            onShelfTask(saved);
+        }
+        return saved;
+    }
+
+    public synchronized String changeStatus(Long id, AuctionStatus status) {
+        BoundValueOperations<String, Object> ops = redisTemplate.boundValueOps(RedisKeys.AUCTION_STATUS + id);
+        if (ops.get() == null) {
+            Boolean success = ops.setIfAbsent(Optional.ofNullable(auctionActivityRepo.getStatus(id))
+                    .orElse(AuctionStatus.NOTSTARTED.toString()), 7, TimeUnit.DAYS);
+            log.info("创建redis拍卖活动状态:{}", success);
+        }
+        String stock = (String) ops.getAndSet(status.toString());
+        syncStatus(id);
+        return stock;
+    }
+
+    //    @Debounce(key = "#id", delay = 500)
+    public void syncStatus(Long id) {
+        String stock = (String) redisTemplate.opsForValue().get(RedisKeys.AUCTION_STATUS + id);
+        if (stock != null) {
+            log.info("同步拍卖活动状态信息{},{}", id, stock);
+            auctionActivityRepo.updateStatus(id, AuctionStatus.valueOf(stock));
+            cacheService.clearAuction(id);
+        }
+    }
+
+    public synchronized String getStatus(Long id) {
+        BoundValueOperations<String, Object> ops = redisTemplate.boundValueOps(RedisKeys.AUCTION_STATUS + id);
+        String stock = (String) ops.get();
+        if (stock == null) {
+            Boolean success = ops.setIfAbsent(Optional.ofNullable(auctionActivityRepo.getStatus(id))
+                    .orElse(AuctionStatus.NOTSTARTED.toString()), 7, TimeUnit.DAYS);
+            log.info("创建redis拍卖活动状态:{}", success);
+            return (String) ops.get();
+        }
+        return stock;
+    }
+
+    private void onShelfTask(AuctionActivity record) {
+        ScheduledFuture<?> task = tasks.get(record.getId());
+        if (task != null) {
+            if (!task.cancel(true)) {
+                return;
+            }
+        }
+        if (record.getStatus().equals(AuctionStatus.NOTSTARTED)) {
+            if (record.getStartTime().minusSeconds(2).isAfter(LocalDateTime.now())) {
+                Date date = Date.from(record.getStartTime().atZone(ZoneId.systemDefault()).toInstant());
+                ScheduledFuture<?> future = taskScheduler.schedule(() -> {
+
+//                    this.changeStatus(record.getId(), AuctionStatus.ONGOING);
+                    auctionActivityRepo.updateStatus(record.getId(), AuctionStatus.ONGOING);
+                    tasks.remove(record.getId());
+                }, date);
+                tasks.put(record.getId(), future);
+            } else {
+//                this.changeStatus(record.getId(), AuctionStatus.ONGOING);
+                auctionActivityRepo.updateStatus(record.getId(), AuctionStatus.ONGOING);
+            }
+        }
+    }
+
+    public void offShelfTask(AuctionActivity record) {
+        Long id = record.getId();
+        ScheduledFuture<?> task = tasks.get(id);
+        if (task != null) {
+            if (!task.cancel(true)) {
+                return;
+            }
+        }
+//        AuctionActivity recordNew = auctionActivityRepo.findById(id)
+//                .orElseThrow(new BusinessException("无数据"));
+        if (record.getStatus().equals(AuctionStatus.ONGOING)) {
+            if (record.getEndTime().minusSeconds(2).isAfter(LocalDateTime.now())) {
+                Date date = Date.from(record.getEndTime().atZone(ZoneId.systemDefault()).toInstant());
+                ScheduledFuture<?> future = taskScheduler.schedule(() -> {
+                    AuctionActivity recordNew1 = auctionActivityRepo.findById(id)
+                            .orElseThrow(new BusinessException("无数据"));
+
+                    if (ObjectUtils.isNotEmpty(recordNew1.getPurchasePrice())) {
+                        log.info("拍卖成交{}", recordNew1.getId());
+//                        this.changeStatus(recordNew1.getId(), AuctionStatus.PURCHASED);
+                        auctionActivityRepo.updateStatus(recordNew1.getId(), AuctionStatus.PURCHASED);
+                    } else {
+                        //没有成交价,无人出价过
+                        log.info("拍卖流拍Task-else{}", recordNew1.getId());
+                        auctionActivityRepo.scheduleOffShelf(recordNew1.getId(), AuctionStatus.PASS);
+
+                        if (AuctionSource.TRANSFER.equals(recordNew1.getSource())) {
+                            Asset asset = assetRepo.findById(recordNew1.getAssetId())
+                                    .orElseThrow(new BusinessException("暂无"));
+                            asset.setStatus(AssetStatus.NORMAL);
+                            asset.setConsignment(false);
+                            asset.setPublicShow(false);
+                            assetRepo.save(asset);
+                        }
+                    }
+                    tasks.remove(id);
+                }, date);
+                tasks.put(id, future);
+            } else {
+                AuctionActivity recordNew1 = auctionActivityRepo.findById(id)
+                        .orElseThrow(new BusinessException("无数据"));
+                if (ObjectUtils.isNotEmpty(recordNew1.getPurchasePrice())) {
+                    log.info("拍卖成交{}", id);
+                    auctionActivityRepo.scheduleOffShelf(id, AuctionStatus.PURCHASED);
+                } else {
+                    log.info("拍卖流拍Task-else-else{}", id);
+                    auctionActivityRepo.scheduleOffShelf(id, AuctionStatus.PASS);
+
+                    if (AuctionSource.TRANSFER.equals(recordNew1.getSource())) {
+                        Asset asset = assetRepo.findById(recordNew1.getAssetId())
+                                .orElseThrow(new BusinessException("暂无"));
+                        asset.setStatus(AssetStatus.NORMAL);
+                        asset.setConsignment(false);
+                        asset.setPublicShow(false);
+                        assetRepo.save(asset);
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * 定时下架拍卖
+     * (每隔1分钟执行一次)
+     */
+    @Scheduled(cron = "0 */1 * * * ?")
+    public void passAuction() {
+        List<AuctionActivity> activities = auctionActivityRepo.findAllByStatus(AuctionStatus.ONGOING);
+        activities.forEach(activity -> {
+            if (activity.getEndTime().isBefore(LocalDateTime.now())) {
+                if (ObjectUtils.isNotEmpty(activity.getPurchasePrice())) {
+                    log.info("拍卖成交{}", activity.getId());
+//                    this.changeStatus(activity.getId(), AuctionStatus.PURCHASED);
+                    auctionActivityRepo.updateStatus(activity.getId(), AuctionStatus.PURCHASED);
+                } else {
+                    //没有成交价,无人出价过
+                    log.info("拍卖流拍Task-else-else{}", activity.getId());
+//                    this.changeStatus(activity.getId(), AuctionStatus.PASS);
+                    auctionActivityRepo.updateStatus(activity.getId(), AuctionStatus.PASS);
+
+                    if (AuctionSource.TRANSFER.equals(activity.getSource())) {
+                        Asset asset = assetRepo.findById(activity.getAssetId())
+                                .orElseThrow(new BusinessException("暂无"));
+                        asset.setStatus(AssetStatus.NORMAL);
+                        asset.setConsignment(false);
+                        asset.setPublicShow(false);
+                        assetRepo.save(asset);
+                    }
+                }
+            }
+        });
+    }
+}

+ 607 - 0
src/main/java/com/izouma/nineth/service/AuctionOrderService.java

@@ -0,0 +1,607 @@
+package com.izouma.nineth.service;
+
+import com.izouma.nineth.annotations.RedisLock;
+import com.izouma.nineth.config.Constants;
+import com.izouma.nineth.config.RedisKeys;
+import com.izouma.nineth.domain.*;
+import com.izouma.nineth.dto.PageQuery;
+import com.izouma.nineth.enums.*;
+import com.izouma.nineth.exception.BusinessException;
+import com.izouma.nineth.repo.*;
+import com.izouma.nineth.service.sms.SmsService;
+import com.izouma.nineth.utils.JpaUtils;
+import com.izouma.nineth.utils.SecurityUtils;
+import com.izouma.nineth.utils.SnowflakeIdWorker;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.ObjectUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Lazy;
+import org.springframework.data.domain.Page;
+import org.springframework.data.redis.core.BoundValueOperations;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Service;
+
+import javax.persistence.Transient;
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.time.LocalDateTime;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Optional;
+import java.util.concurrent.TimeUnit;
+
+@Slf4j
+@Service
+public class AuctionOrderService {
+
+    @Autowired
+    private AuctionOrderRepo              auctionOrderRepo;
+    @Autowired
+    private SysConfigService              sysConfigService;
+    @Autowired
+    private UserRepo                      userRepo;
+    @Autowired
+    private AssetService                  assetService;
+    @Autowired
+    private AuctionActivityRepo           auctionActivityRepo;
+    @Autowired
+    private AuctionRecordRepo             auctionRecordRepo;
+    @Autowired
+    private AssetRepo                     assetRepo;
+    @Autowired
+    private UserAddressRepo               userAddressRepo;
+    @Autowired
+    private RedisTemplate<String, Object> redisTemplate;
+    @Autowired
+    private SnowflakeIdWorker             snowflakeIdWorker;
+    @Autowired
+    private AuctionPassRecordRepo         auctionPassRecordRepo;
+    @Lazy
+    @Autowired
+    private OrderPayService               orderPayService;
+    @Autowired
+    private SmsService                    smsService;
+    @Autowired
+    private UserBalanceService            userBalanceService;
+    @Autowired
+    private ShowroomService               showroomService;
+    @Autowired
+    private CollectionRepo                collectionRepo;
+    @Autowired
+    private ShowroomRepo                  showroomRepo;
+    @Autowired
+    private UserBalanceRepo               userBalanceRepo;
+
+    public Page<AuctionOrder> all(PageQuery pageQuery) {
+        return auctionOrderRepo
+                .findAll(JpaUtils.toSpecification(pageQuery, AuctionOrder.class), JpaUtils.toPageRequest(pageQuery));
+    }
+
+    @RedisLock("'createAuctionOrder::'+#auctionId")
+    public AuctionOrder create(Long userId, Long auctionId, Long addressId, Long auctionRecordId, AuctionPaymentType type) {
+        User user = userRepo.findById(userId).orElseThrow(new BusinessException("无用户"));
+
+        AuctionActivity auction = auctionActivityRepo.findById(auctionId)
+                .orElseThrow(new BusinessException("无拍卖信息"));
+
+        if (!auction.isOnShelf()) {
+            throw new BusinessException("拍卖已结束");
+        }
+
+        String status = auctionActivityRepo.getStatus(auctionId);
+        switch (AuctionStatus.valueOf(status)) {
+            case NOTSTARTED:
+                throw new BusinessException("拍卖还未开始");
+//            case PURCHASED:
+//                throw new BusinessException("拍卖成交中");
+            case PASS:
+                throw new BusinessException("已经流拍");
+            case FINISH:
+                throw new BusinessException("拍卖已结束");
+            case FIXED_PRICE_PURCHASED:
+                if (AuctionPaymentType.FIXED_PRICE.equals(type)) {
+                    throw new BusinessException("一口价成交中");
+                }
+        }
+
+        if (user.getId().equals(auction.getSellerId())) {
+            throw new BusinessException("不可自己出价自己");
+        }
+
+        if (AuctionPaymentType.PURCHASE_PRICE.equals(type)) {
+            if (auction.getEndTime().isAfter(LocalDateTime.now())) {
+                throw new BusinessException("拍卖还未结束");
+            }
+            AuctionRecord record = auctionRecordRepo.findTopByAuctionIdAndUserIdOrderByIdDesc(auctionId, userId);
+            if (ObjectUtils.isEmpty(record) || !record.isPayDeposit()) {
+                throw new BusinessException("未支付保证金");
+            }
+            if (record.getBidderPrice().compareTo(auction.getPurchasePrice()) != 0) {
+                throw new BusinessException("与成交价不否");
+            }
+            int time = sysConfigService.getInt("auction_cancel_time");
+            if (LocalDateTime.now().isAfter(auction.getEndTime().plusMinutes(time))) {
+                throw new BusinessException("超过支付时长");
+            }
+
+//            AuctionOrder order = auctionOrderRepo
+//                    .findByUserIdAndAuctionIdAndPaymentTypeAndStatusIn(user.getId(), auction.getId(),
+//                            AuctionPaymentType.PURCHASE_PRICE, Arrays
+//                                    .asList(AuctionOrderStatus.NOT_PAID, AuctionOrderStatus.FINISH));
+//            if (ObjectUtils.isNotEmpty(order)) {
+//                if (AuctionOrderStatus.FINISH.equals(order.getStatus())) {
+//                    throw new BusinessException("成交金已交过,无需再交");
+//                }
+//                throw new BusinessException("成交金未支付,取消后再支付");
+//            }
+
+        } else {
+            if (auction.getEndTime().isBefore(LocalDateTime.now())) {
+                throw new BusinessException("拍卖已结束");
+            }
+            if (AuctionPaymentType.DEPOSIT.equals(type)) {
+                return this.createDeposit(user, auction);
+            }
+        }
+
+        UserAddress userAddress = null;
+        if (addressId != null) {
+            userAddress = userAddressRepo.findById(addressId).orElseThrow(new BusinessException("地址信息不存在"));
+        }
+
+        try {
+
+            auctionActivityRepo.updateStatus(auctionId, AuctionPaymentType.FIXED_PRICE
+                    .equals(type) ? AuctionStatus.FIXED_PRICE_PURCHASED : AuctionStatus.PURCHASED);
+
+            if (AuctionSource.TRANSFER.equals(auction.getSource())) {
+                Asset asset = assetRepo.findById(auction.getAssetId()).orElseThrow(new BusinessException("资产不存在"));
+                asset.setStatus(AssetStatus.AUCTION_TRADING);
+                assetRepo.save(asset);
+            }
+
+            BigDecimal price = AuctionPaymentType.FIXED_PRICE.equals(type) ? auction.getFixedPrice() : auction
+                    .getPurchasePrice();
+
+            AuctionOrder order = AuctionOrder.builder()
+                    .id(snowflakeIdWorker.nextId())
+                    .auctionId(auction.getId())
+                    .userId(user.getId())
+                    .nickname(user.getNickname())
+                    .paymentType(type)
+                    .name(auction.getName())
+                    .pic(auction.getPic())
+                    .serviceCharge(auction.getServiceCharge())
+                    .royalties(auction.getRoyalties())
+                    .source(auction.getSource())
+                    .price(price)
+                    .totalPrice(price)
+                    .auctionRecordId(auctionRecordId)
+                    .status(AuctionOrderStatus.NOT_PAID)
+                    .contactName(Optional.ofNullable(userAddress).map(UserAddress::getName).orElse(null))
+                    .contactPhone(Optional.ofNullable(userAddress).map(UserAddress::getPhone).orElse(null))
+                    .address(Optional.ofNullable(userAddress).map(UserAddress::getDetail).orElse(null))
+                    .build();
+
+            return auctionOrderRepo.save(order);
+        } catch (Exception e) {
+            auctionActivityRepo.updateStatus(auctionId, AuctionStatus.ONGOING);
+            throw e;
+        }
+    }
+
+
+    public AuctionOrder createDeposit(User user, AuctionActivity auction) {
+        if (user.getId().equals(auction.getSellerId())) {
+            throw new BusinessException("不可自己出价自己的");
+        }
+
+        //竞拍人绿魔卡余额限制
+        BigDecimal minAmount = sysConfigService.getBigDecimal("auction_min_amount");
+        if (!user.isWalletEnabled()) {
+            throw new BusinessException("请开通绿魔卡,并充值" + minAmount + "元");
+        } else {
+            UserBalance userBalance = userBalanceRepo.findByUserId(user.getId()).orElse(new UserBalance(user.getId()));
+            if (minAmount.compareTo(userBalance.getBalance()) > 0) {
+                throw new BusinessException("绿魔卡余额不足" + minAmount + "元,请先充值");
+            }
+        }
+
+        //保证金
+//        BigDecimal deposit = sysConfigService.getBigDecimal("deposit");
+        AuctionOrder order = auctionOrderRepo
+                .findByUserIdAndAuctionIdAndPaymentTypeAndStatusIn(user.getId(), auction.getId(),
+                        AuctionPaymentType.DEPOSIT, Arrays
+                                .asList(AuctionOrderStatus.NOT_PAID, AuctionOrderStatus.FINISH));
+        if (ObjectUtils.isNotEmpty(order)) {
+            if (AuctionOrderStatus.FINISH.equals(order.getStatus())) {
+                throw new BusinessException("保证金已交过,无需再交");
+            }
+            throw new BusinessException("保证金未支付,取消后再重新出价");
+        }
+
+        AuctionRecord auctionRecord = AuctionRecord.builder()
+                .auctionId(auction.getId())
+                .type(AuctionRecordType.DEPOSIT)
+                .bidderPrice(auction.getDeposit())
+                .auctionPic(null)
+                .userId(SecurityUtils.getAuthenticatedUser().getId())
+                .avatar(SecurityUtils.getAuthenticatedUser().getAvatar())
+                .name(auction.getName())
+                .purchased(false)
+                .auctionType(auction.getAuctionType())
+                .build();
+        AuctionRecord record = auctionRecordRepo.save(auctionRecord);
+
+        order = AuctionOrder.builder()
+                .id(snowflakeIdWorker.nextId())
+                .auctionId(auction.getId())
+                .userId(user.getId())
+                .nickname(user.getNickname())
+                .paymentType(AuctionPaymentType.DEPOSIT)
+                .name(auction.getName())
+                .pic(auction.getPic())
+                .serviceCharge(auction.getServiceCharge())
+                .royalties(auction.getRoyalties())
+                .source(auction.getSource())
+                .price(auction.getDeposit())
+                .totalPrice(auction.getDeposit())
+                .auctionRecordId(record.getId())
+                .status(AuctionOrderStatus.NOT_PAID)
+                .build();
+
+
+        return auctionOrderRepo.save(order);
+
+    }
+
+    @Transient
+    public void notify(Long id, PayMethod payMethod, String transactionId) {
+        AuctionOrder order = auctionOrderRepo.findById(id).orElseThrow(new BusinessException("无记录"));
+        if (!order.getStatus().equals(AuctionOrderStatus.NOT_PAID)) {
+            throw new BusinessException("订单已处理");
+        }
+        AuctionActivity auction = auctionActivityRepo.findById(order.getAuctionId())
+                .orElseThrow(new BusinessException("无拍卖活动"));
+
+        if (auction.getAuctionType().equals(AuctionType.ENTITY)) {
+            order.setStatus(AuctionOrderStatus.DELIVERY);
+        } else {
+            order.setStatus(AuctionOrderStatus.FINISH);
+        }
+        order.setPayMethod(payMethod);
+        order.setTransactionId(transactionId);
+        order.setPayTime(LocalDateTime.now());
+        //存订单
+        auctionOrderRepo.save(order);
+
+        if (AuctionPaymentType.DEPOSIT.equals(order.getPaymentType())) {
+            //改出价记录表
+            AuctionRecord record = auctionRecordRepo.findById(order.getAuctionRecordId())
+                    .orElseThrow(new BusinessException("无出价记录"));
+            record.setPayDeposit(true);
+            auctionRecordRepo.save(record);
+            return;
+        }
+
+        //此拍卖结束
+        //修改买家和成交价
+        auction.setStatus(AuctionStatus.FINISH);
+        auction.setPurchaserId(order.getUserId());
+        auction.setPurchasePrice(order.getTotalPrice());
+        auctionActivityRepo.save(auction);
+        log.info("拍卖结束:{}", order.getAuctionId());
+
+        if (AuctionSource.TRANSFER.equals(order.getSource())) {
+            Asset asset = assetRepo.findById(auction.getAssetId()).orElseThrow(new BusinessException("资产不存在"));
+            if (asset.isPublicShow()) {
+                //取消公开展示
+                assetService.cancelPublic(asset);
+            }
+            User user = userRepo.findById(order.getUserId()).orElseThrow(new BusinessException("无用户"));
+            //转让流程
+            assetService.transfer(asset, order.getTotalPrice(), user, TransferReason.AUCTION, order.getId());
+
+            // 发送短信提醒用户转让成功
+            if (asset.getUserId() != null) {
+                smsService.sellOut(userRepo.findPhoneById(asset.getUserId()));
+            }
+
+            //用户冲余额
+            BigDecimal amount = order.getTotalPrice()
+                    .multiply(BigDecimal.valueOf(100 - order.getRoyalties() - order.getServiceCharge()))
+                    .divide(new BigDecimal("100"), 2, RoundingMode.HALF_UP);
+
+            userBalanceService.addBalance(asset.getUserId(), amount, id, BalanceType.AUCTION);
+
+        }
+
+        //改出价记录表为竞得(一口价无出价表)
+        if (ObjectUtils.isNotEmpty(order.getAuctionRecordId())) {
+            AuctionRecord record = auctionRecordRepo.findById(order.getAuctionRecordId())
+                    .orElseThrow(new BusinessException("无出价记录"));
+            record.setPurchased(true);
+            auctionRecordRepo.save(record);
+        }
+
+
+        //退保证金
+        List<AuctionOrder> orders = auctionOrderRepo.findAllByAuctionIdAndPaymentTypeAndStatus(order.getAuctionId(),
+                AuctionPaymentType.DEPOSIT, AuctionOrderStatus.FINISH);
+        //退款
+        orders.forEach(this::refund);
+    }
+
+    public void cancel(AuctionOrder order) {
+        if (!getOrderLock(order.getId())) {
+            log.error("订单取消失败 {}, redis锁了", order.getId());
+            return;
+        }
+
+        boolean isRefund = false;
+        try {
+            AuctionActivity auction = auctionActivityRepo.findById(order.getAuctionId())
+                    .orElseThrow(new BusinessException("无记录"));
+
+            if (AuctionPaymentType.PURCHASE_PRICE.equals(order.getPaymentType())) {
+                //如果是拍卖,需获取取消订单的时长
+                int time = sysConfigService.getInt("auction_cancel_time");
+                if (LocalDateTime.now().isAfter(auction.getEndTime().plusMinutes(time))) {
+                    //超过支付时长
+                    log.info("取消订单流拍:{}", auction.getId());
+                    auctionActivityRepo.updateStatus(order.getAuctionId(), AuctionStatus.PASS);
+                    //添加到流拍记录表里
+                    auctionPassRecordRepo.save(AuctionPassRecord.builder()
+                            .auctionId(auction.getId())
+                            .userId(auction.getPurchaserId())
+                            .purchasePrice(auction.getPurchasePrice())
+                            .build());
+                    //流拍不退自己的保证金
+                    isRefund = true;
+
+                    if (AuctionSource.TRANSFER.equals(order.getSource())) {
+                        //改回资产状态
+                        Asset asset = assetRepo.findById(auction.getAssetId())
+                                .orElseThrow(new BusinessException("资产不存在"));
+                        asset.setStatus(AssetStatus.NORMAL);
+                        assetRepo.save(asset);
+                    }
+
+                }
+            } else if (AuctionPaymentType.DEPOSIT.equals(order.getPaymentType())) {
+                //删除出价记录
+                auctionRecordRepo.softDelete(order.getAuctionRecordId());
+            } else {
+                //拍卖是否结束
+                if (LocalDateTime.now().isBefore(auction.getEndTime())) {
+                    //返回拍卖状态
+                    auctionActivityRepo.updateStatus(order.getAuctionId(), AuctionStatus.ONGOING);
+                } else {
+                    //最后一个出价的人得
+                    auctionActivityRepo.updateStatus(order.getAuctionId(), AuctionStatus.PURCHASED);
+                }
+            }
+
+            order.setStatus(AuctionOrderStatus.CANCELLED);
+            order.setCancelTime(LocalDateTime.now());
+            auctionOrderRepo.save(order);
+            log.info("取消订单{}", order.getId());
+
+        } catch (Exception e) {
+            log.error("订单取消错误 orderId: " + order.getId(), e);
+        }
+
+        if (isRefund) {
+            //退其余保证金
+            List<AuctionOrder> orders = auctionOrderRepo
+                    .findAllByAuctionIdAndPaymentTypeAndStatus(order.getAuctionId(),
+                            AuctionPaymentType.DEPOSIT, AuctionOrderStatus.FINISH);
+            //退款
+            orders.stream()
+                    .filter(o -> !order.getUserId().equals(o.getUserId()))
+                    .forEach(this::refund);
+        }
+        releaseOrderLock(order.getId());
+    }
+
+    /**
+     * 退款方法
+     *
+     * @param order 订单
+     */
+    private void refund(AuctionOrder order) {
+        log.info("退款拍卖保证金订单{}", order.getId());
+        PayMethod payMethod = order.getPayMethod();
+        if (PayMethod.ALIPAY == payMethod) {
+            if (StringUtils.length(order.getTransactionId()) == 28) {
+                payMethod = PayMethod.HMPAY;
+            } else if (StringUtils.length(order.getTransactionId()) == 30) {
+                payMethod = PayMethod.SANDPAY;
+            }
+        }
+        try {
+            switch (payMethod) {
+                case HMPAY:
+                    orderPayService.refund(order.getId()
+                            .toString(), order.getTransactionId(), order.getTotalPrice(), Constants.PayChannel.HM);
+                    log.info("退款成功{}", order.getId());
+                    break;
+                case SANDPAY:
+                    orderPayService.refund(order.getId()
+                            .toString(), order.getTransactionId(), order.getTotalPrice(), Constants.PayChannel.SAND);
+                    log.info("退款成功{}", order.getId());
+                    break;
+                case PAYEASE:
+                    orderPayService.refund(order.getId()
+                            .toString(), order.getTransactionId(), order.getTotalPrice(), Constants.PayChannel.PE);
+                    log.info("退款成功{}", order.getId());
+                    break;
+                case BALANCE:
+                    userBalanceService.addBalance(order.getUserId(), order.getTotalPrice(), order.getId(), BalanceType.AUCTION_RETURN);
+                    log.info("退款成功{}", order.getId());
+                    break;
+            }
+            order.setRefundTime(LocalDateTime.now());
+            order.setStatus(AuctionOrderStatus.REFUNDED);
+            auctionOrderRepo.save(order);
+        } catch (Exception e) {
+            log.error("拍卖保证金订单退款失败 {} ", order.getId(), e);
+            order.setRefundTime(LocalDateTime.now());
+            order.setStatus(AuctionOrderStatus.REFUNDING);
+            auctionOrderRepo.save(order);
+        }
+    }
+
+    public boolean getOrderLock(Long orderId) {
+        BoundValueOperations<String, Object> ops = redisTemplate.boundValueOps(RedisKeys.AUCTION_ORDER_LOCK + orderId);
+        Boolean flag = ops.setIfAbsent(1, 1, TimeUnit.DAYS);
+        return Boolean.TRUE.equals(flag);
+    }
+
+    public void releaseOrderLock(Long orderId) {
+        redisTemplate.delete(RedisKeys.AUCTION_ORDER_LOCK + orderId);
+    }
+
+    public void passCancel(AuctionOrder order) {
+        if (!getOrderLock(order.getId())) {
+            log.error("订单取消失败 {}, redis锁了", order.getId());
+            return;
+        }
+
+        try {
+            order.setStatus(AuctionOrderStatus.CANCELLED);
+            order.setCancelTime(LocalDateTime.now());
+            auctionOrderRepo.save(order);
+            log.info("取消订单{}", order.getId());
+
+        } catch (Exception e) {
+            log.error("订单取消错误 orderId: " + order.getId(), e);
+        }
+        releaseOrderLock(order.getId());
+    }
+
+    @Scheduled(cron = "0 0/1 * * * ?")
+    public void passOverTimeAuction() {
+        List<AuctionActivity> purchased = auctionActivityRepo.findAllByStatus(AuctionStatus.PURCHASED);
+        if (purchased != null) {
+            int time = sysConfigService.getInt("auction_cancel_time");
+            purchased.forEach(act -> {
+                if (LocalDateTime.now().isAfter(act.getEndTime().plusMinutes(time))) {
+                    List<AuctionOrder> auctionOrders = auctionOrderRepo.findAllByAuctionIdAndPaymentTypeAndStatus(act
+                            .getId(), AuctionPaymentType.PURCHASE_PRICE, AuctionOrderStatus.NOT_PAID);
+                    //创建了订单
+                    auctionOrders.forEach(this::passCancel);
+
+                    act.setStatus(AuctionStatus.PASS);
+                    auctionActivityRepo.save(act);
+                    log.info("拍卖定时任务流拍{}", act.getId());
+
+                    if (AuctionSource.TRANSFER.equals(act.getSource())) {
+                        //改回资产状态
+                        Asset asset = assetRepo.findById(act.getAssetId())
+                                .orElseThrow(new BusinessException("资产不存在"));
+                        asset.setStatus(AssetStatus.NORMAL);
+                        assetRepo.save(asset);
+                    }
+
+                    //退其余保证金
+                    List<AuctionOrder> orders = auctionOrderRepo
+                            .findAllByAuctionIdAndPaymentTypeAndStatus(act.getId(),
+                                    AuctionPaymentType.DEPOSIT, AuctionOrderStatus.FINISH);
+                    //退款
+                    orders.stream()
+                            .filter(o -> !act.getPurchaserId().equals(o.getUserId()))
+                            .forEach(this::refund);
+
+                    //添加到流拍记录表里
+                    auctionPassRecordRepo.save(AuctionPassRecord.builder()
+                            .auctionId(act.getId())
+                            .userId(act.getPurchaserId())
+                            .purchasePrice(act.getPurchasePrice())
+                            .build());
+                }
+            });
+        }
+    }
+
+    /**
+     * 发货
+     *
+     * @param id        编号
+     * @param courierId 快递单号
+     */
+    public void dispatch(Long id, String courierId) {
+        AuctionOrder auctionOrder = auctionOrderRepo.findById(id).orElseThrow(new BusinessException("铸造订单不存在"));
+        auctionOrder.setStatus(AuctionOrderStatus.RECEIVE);
+        auctionOrder.setCourierId(courierId);
+        auctionOrderRepo.save(auctionOrder);
+    }
+
+    /**
+     * 订单
+     *
+     * @param id 编号
+     */
+    public void finish(Long id) {
+        AuctionOrder auctionOrder = auctionOrderRepo.findById(id).orElseThrow(new BusinessException("铸造订单不存在"));
+        auctionOrder.setStatus(AuctionOrderStatus.FINISH);
+        auctionOrderRepo.save(auctionOrder);
+    }
+
+    public void privilege(AuctionOrder order, User user) {
+        if (showroomRepo.findByUserIdAndType(order.getUserId(), "AUCTION").isEmpty()) {
+            //Bidder特殊拍卖展厅服务 创建一个bidder展厅藏品
+            Long collectionId = (long) sysConfigService.getInt("bidder_collection_id");
+            List<Asset> assets = assetRepo.findAllByUserIdAndCollectionIdAndStatus(order.getUserId(), collectionId, AssetStatus.NORMAL);
+            Asset asset;
+            if (assets.isEmpty()) {
+                Collection collection = collectionRepo.findById(collectionId).orElseThrow(new BusinessException("无藏品"));
+                if (!CollectionType.SHOWROOM.equals(collection.getType())) {
+                    throw new BusinessException("不是展厅藏品");
+                }
+                //创建资产
+                asset = assetService.createAsset(collection, user, order.getId(), BigDecimal.ZERO, "拍卖赠送",
+                        null, false);
+            } else {
+                asset = assets.get(0);
+            }
+            //创建展厅
+            showroomService.save(asset, "AUCTION");
+        }
+
+        //一个月的优先拍卖权
+        PurchaserPrivilege.builder()
+                .userId(order.getUserId())
+                .title("元宇宙Bidder")
+                .priority(true)
+                .priorityExpireAt(LocalDateTime.now().plusMonths(1))
+                .build();
+
+
+        //前20名分钱
+        BigDecimal totalPrice = order.getTotalPrice();
+        //手续费
+        int auctionServiceCharge = sysConfigService.getInt("auction_service_charge");
+        BigDecimal serviceCharge = totalPrice.multiply(new BigDecimal(auctionServiceCharge))
+                .divide(new BigDecimal("100"), 2, RoundingMode.HALF_UP);
+
+        //奖励费用
+        BigDecimal subtract = totalPrice.subtract(serviceCharge);
+        int auctionReward = sysConfigService.getInt("auction_reward");
+        BigDecimal reward = subtract.multiply(new BigDecimal(auctionReward))
+                .divide(new BigDecimal("100"), 2, RoundingMode.HALF_UP);
+        List<Long> records = auctionRecordRepo.findByAuctionId(order.getAuctionId(), 20);
+        BigDecimal everyReward = reward.divide(new BigDecimal(records.size()), 2, RoundingMode.HALF_UP);
+        //分奖励
+        records.forEach(userId -> userBalanceService.addBalance(userId, everyReward, order.getId(), BalanceType.REWARD));
+
+
+        //拍卖者所得
+        BigDecimal amount = totalPrice.subtract(serviceCharge).subtract(reward);
+        userBalanceService.addBalance(order.getUserId(), amount, order.getId(), BalanceType.AUCTION);
+
+    }
+
+}

+ 224 - 0
src/main/java/com/izouma/nineth/service/AuctionRecordService.java

@@ -0,0 +1,224 @@
+package com.izouma.nineth.service;
+
+import com.izouma.nineth.config.RedisKeys;
+import com.izouma.nineth.domain.*;
+import com.izouma.nineth.dto.PageQuery;
+import com.izouma.nineth.dto.auction.AuctionRecordDTO;
+import com.izouma.nineth.enums.AuctionOrderStatus;
+import com.izouma.nineth.enums.AuctionPaymentType;
+import com.izouma.nineth.enums.AuctionRecordType;
+import com.izouma.nineth.enums.AuctionStatus;
+import com.izouma.nineth.exception.BusinessException;
+import com.izouma.nineth.repo.*;
+import com.izouma.nineth.utils.JpaUtils;
+import com.izouma.nineth.utils.SecurityUtils;
+import lombok.AllArgsConstructor;
+import org.apache.commons.lang3.ObjectUtils;
+import org.springframework.beans.BeanUtils;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.PageImpl;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.stereotype.Service;
+
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+@Service
+@AllArgsConstructor
+public class AuctionRecordService {
+
+    private AuctionRecordRepo             auctionRecordRepo;
+    private AuctionActivityRepo           auctionActivityRepo;
+    private AuctionOrderRepo              auctionOrderRepo;
+    private RedisTemplate<String, Object> redisTemplate;
+    private UserRepo                      userRepo;
+    private UserBalanceRepo               userBalanceRepo;
+    private SysConfigService              sysConfigService;
+
+    public Page<AuctionRecord> all(PageQuery pageQuery) {
+        return auctionRecordRepo
+                .findAll(JpaUtils.toSpecification(pageQuery, AuctionRecord.class), JpaUtils.toPageRequest(pageQuery));
+    }
+
+    public Page<AuctionRecordDTO> recordInfos(PageQuery pageQuery) {
+
+        Page<AuctionRecord> records = auctionRecordRepo
+                .findAll(JpaUtils.toSpecification(pageQuery, AuctionRecord.class), JpaUtils.toPageRequest(pageQuery));
+
+        List<AuctionRecordDTO> auctionRecordDTOS = new ArrayList<>();
+        records.getContent().forEach(record -> {
+            AuctionActivity auctionActivity = auctionActivityRepo.findById(record.getAuctionId())
+                    .orElse(null);
+            if (auctionActivity == null) {
+                return;
+            }
+            AuctionRecordDTO auctionRecordDTO = new AuctionRecordDTO();
+            auctionRecordDTO.setAuctionId(record.getAuctionId());
+            auctionRecordDTO.setAuctionPic(auctionActivity.getPic());
+            auctionRecordDTO.setMinter(auctionActivity.getMinter());
+            auctionRecordDTO.setBidderPrice(record.getBidderPrice());
+            auctionRecordDTO.setActPurchasedId((auctionActivity.getPurchaserId()));
+            auctionRecordDTO.setName(record.getName());
+            auctionRecordDTO.setDeposit(auctionActivity.getDeposit());
+            auctionRecordDTO.setEndTime(auctionActivity.getEndTime());
+            auctionRecordDTO.setCreatedTime(record.getCreatedAt());
+            auctionRecordDTO.setUserId(record.getUserId());
+            auctionRecordDTO.setType(record.getType());
+            auctionRecordDTO.setPurchased(record.isPurchased());
+            auctionRecordDTO.setAuctionStatus(auctionActivity.getStatus());
+            auctionRecordDTO.setAuctionType(auctionActivity.getAuctionType());
+//            if (auctionActivity.getStatus().equals(AuctionStatus.PURCHASED) || auctionActivity.getStatus()
+//                    .equals(AuctionStatus.FINISH)) {
+//                if (auctionActivity.getRecordId() != null) {
+//                    if (auctionActivity.getRecordId().equals(record.getId())) {
+//                        auctionRecordDTO.setPurchased(true);
+//                    }
+//                }
+//            }
+            if (auctionRecordDTO.getType().equals(AuctionRecordType.DEPOSIT) || auctionRecordDTO.getType()
+                    .equals(AuctionRecordType.BIDDER) || auctionRecordDTO.isPurchased()) {
+                AuctionOrder auctionOrder = auctionOrderRepo.findFirstByAuctionRecordIdOrderByCreatedAt(record.getId());
+                if (auctionOrder != null) {
+                    auctionRecordDTO.setOrderId(auctionOrder.getId());
+                    auctionRecordDTO.setOrderStatus(auctionOrder.getStatus());
+                }
+            }
+            Set<AuctionOrderStatus> auctionOrderStatuses = new HashSet<>();
+            auctionOrderStatuses.add(AuctionOrderStatus.NOT_PAID);
+            auctionOrderStatuses.add(AuctionOrderStatus.CANCELLED);
+            AuctionOrder depositOrder = auctionOrderRepo.findFirstByAuctionIdAndPaymentTypeAndStatusNotInAndUserIdOrderByIdDesc(record
+                    .getAuctionId(), AuctionPaymentType.DEPOSIT, auctionOrderStatuses, SecurityUtils.getAuthenticatedUser()
+                    .getId());
+            if (depositOrder != null) {
+                auctionRecordDTO.setDepositStatus(depositOrder.getStatus());
+            } else {
+                auctionRecordDTO.setDepositStatus(AuctionOrderStatus.FINISH);
+            }
+            auctionRecordDTOS.add(auctionRecordDTO);
+        });
+        return new PageImpl<>(auctionRecordDTOS, records.getPageable(), records.getTotalElements());
+    }
+
+    public List<AuctionRecordDTO> userRecord(Long userId, String type) {
+        List<AuctionRecord> records = auctionRecordRepo.findByUserId(userId, type);
+        List<AuctionRecordDTO> auctionRecordDTOS = new ArrayList<>();
+        records.forEach(record -> {
+            AuctionActivity auctionActivity = auctionActivityRepo.findById(record.getAuctionId())
+                    .orElse(null);
+            if (auctionActivity == null) {
+                return;
+            }
+            AuctionRecordDTO auctionRecordDTO = new AuctionRecordDTO();
+            BeanUtils.copyProperties(record, auctionRecordDTO);
+            auctionRecordDTO.setAuctionPic(auctionActivity.getPic());
+            auctionRecordDTO.setMinter(auctionActivity.getMinter());
+            auctionRecordDTO.setAuctionPic(auctionActivity.getPic());
+            auctionRecordDTO.setActPurchasedId((auctionActivity.getPurchaserId()));
+            auctionRecordDTO.setDeposit(auctionActivity.getDeposit());
+            auctionRecordDTO.setEndTime(auctionActivity.getEndTime());
+            auctionRecordDTO.setAuctionType(auctionActivity.getAuctionType());
+            auctionRecordDTO.setAuctionStatus(auctionActivity.getStatus());
+            auctionRecordDTO.setCreatedTime(record.getCreatedAt());
+//            if (auctionRecordDTO.getType().equals(AuctionRecordType.DEPOSIT) || auctionRecordDTO.isPurchased()) {
+            AuctionOrder auctionOrder = auctionOrderRepo.findFirstByAuctionRecordIdOrderByIdDesc(record.getId());
+            if (auctionOrder != null) {
+                auctionRecordDTO.setOrderId(auctionOrder.getId());
+                auctionRecordDTO.setOrderStatus(auctionOrder.getStatus());
+            }
+//            }
+            Set<AuctionOrderStatus> auctionOrderStatuses = new HashSet<>();
+            auctionOrderStatuses.add(AuctionOrderStatus.NOT_PAID);
+            auctionOrderStatuses.add(AuctionOrderStatus.CANCELLED);
+            AuctionOrder depositOrder = auctionOrderRepo.findFirstByAuctionIdAndPaymentTypeAndStatusNotInAndUserIdOrderByIdDesc(record
+                    .getAuctionId(), AuctionPaymentType.DEPOSIT, auctionOrderStatuses, userId);
+            if (depositOrder != null) {
+                auctionRecordDTO.setDepositStatus(depositOrder.getStatus());
+            } else {
+                auctionRecordDTO.setDepositStatus(AuctionOrderStatus.FINISH);
+            }
+            auctionRecordDTOS.add(auctionRecordDTO);
+        });
+        return auctionRecordDTOS;
+    }
+
+    public AuctionRecord create(Long userId, Long auctionId, BigDecimal amount) {
+        User user = userRepo.findById(userId).orElseThrow(new BusinessException("无用户"));
+
+        //竞拍人绿魔卡余额限制
+        BigDecimal minAmount = sysConfigService.getBigDecimal("auction_min_amount");
+        if (!user.isWalletEnabled()) {
+            throw new BusinessException("请开通绿魔卡,并充值" + minAmount + "元");
+        } else {
+            UserBalance userBalance = userBalanceRepo.findByUserId(user.getId()).orElse(new UserBalance(user.getId()));
+            if (minAmount.compareTo(userBalance.getBalance()) > 0) {
+                throw new BusinessException("绿魔卡余额不足" + minAmount + "元,请先充值");
+            }
+        }
+
+        AuctionActivity auction = auctionActivityRepo.findById(auctionId)
+                .orElseThrow(new BusinessException("暂无"));
+
+        String status = (String) redisTemplate.opsForValue().get(RedisKeys.AUCTION_STATUS + auctionId);
+        if (status == null)
+            status = auction.getStatus().toString();
+        switch (AuctionStatus.valueOf(status)) {
+            case NOTSTARTED:
+                throw new BusinessException("拍卖还未开始");
+            case PURCHASED:
+                throw new BusinessException("拍卖成交中");
+            case PASS:
+            case FINISH:
+                throw new BusinessException("拍卖已结束");
+        }
+
+        AuctionRecord record = auctionRecordRepo.findTopByAuctionIdAndUserIdOrderByIdDesc(auctionId, userId);
+        if (ObjectUtils.isEmpty(record)) {
+            return auctionRecordRepo.save(AuctionRecord.builder()
+                    .auctionId(auctionId)
+                    .userId(userId)
+                    .avatar(user.getAvatar())
+                    .user(user.getNickname())
+                    .name(auction.getName())
+                    .auctionPic(null)
+                    .bidderPrice(amount)
+                    .purchased(false)
+                    .type(AuctionRecordType.BIDDER)
+                    .payDeposit(false)
+                    .auctionType(auction.getAuctionType())
+                    .build());
+        }
+
+        if (auction.getPurchasePrice() != null) {
+            if (auction.getPurchasePrice().compareTo(amount) >= 0) {
+                throw new BusinessException("出价低于当前竞拍价");
+            }
+        } else if (auction.getStartingPrice().compareTo(amount) >= 0) {
+
+            throw new BusinessException("出价低于当前起拍价");
+        }
+        if (SecurityUtils.getAuthenticatedUser().getId().equals(auction.getPurchaserId())) {
+            throw new BusinessException("请勿重复竞价");
+        }
+        AuctionRecord save = new AuctionRecord();
+        BeanUtils.copyProperties(record, save);
+        save.setId(null);
+        save.setUser(SecurityUtils.getAuthenticatedUser().getNickname());
+        save.setBidderPrice(amount);
+        save.setType(AuctionRecordType.BIDDER);
+        save = auctionRecordRepo.save(save);
+
+        if (record.isPayDeposit()) {
+            //保证金支付过,改成交价
+            auction.setPurchasePrice(amount);
+            auction.setPurchaser(SecurityUtils.getAuthenticatedUser().getNickname());
+            auction.setPurchaserId(SecurityUtils.getAuthenticatedUser().getId());
+            auction.setRecordId(save.getId());
+            auction.setBids(auction.getBids() + 1);
+            auctionActivityRepo.save(auction);
+        }
+        return save;
+    }
+}

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

@@ -122,4 +122,9 @@ public class CacheService {
     @CacheEvict(value = "sysConfigGet", allEntries = true)
     public void clearSysConfigGet() {
     }
+
+    @CacheEvict(value = "auctionStatus", key = "#id")
+    public void clearAuction(Long id) {
+    }
+
 }

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

@@ -32,7 +32,7 @@ public class CaptchaService {
 
         // 算术类型
         ArithmeticCaptcha captcha = new ArithmeticCaptcha(150, 48);
-        captcha.setFont(com.pig4cloud.captcha.base.Captcha.FONT_7, 15 * 2);
+        captcha.setFont(6, 15 * 2);
         captcha.setLen(2);  // 几位数运算,默认是两位
         captcha.getArithmeticString();  // 获取运算的公式:3+2=?
         captcha.supportAlgorithmSign(2); // 可设置支持的算法:2 表示只生成带加减法的公式

+ 52 - 0
src/main/java/com/izouma/nineth/service/CollectionService.java

@@ -6,6 +6,7 @@ import com.izouma.nineth.annotations.Debounce;
 import com.izouma.nineth.config.GeneralProperties;
 import com.izouma.nineth.config.RedisKeys;
 import com.izouma.nineth.converter.LongArrayConverter;
+import com.izouma.nineth.converter.StringArrayConverter;
 import com.izouma.nineth.domain.Collection;
 import com.izouma.nineth.domain.*;
 import com.izouma.nineth.dto.*;
@@ -104,6 +105,22 @@ public class CollectionService {
                 });
             }
         }
+
+        // 筛选去除指定名称不展示
+        if (query.containsKey("notLike")) {
+            String notLike = Convert.toStr(query.get("notLike"));
+            query.remove("notLike");
+            StringArrayConverter converter = new StringArrayConverter();
+            List<String> notLikes = converter.convertToEntityAttribute(notLike);
+            specification = specification.and((Specification<Collection>) (root, criteriaQuery, criteriaBuilder) -> {
+                List<Predicate> and = new ArrayList<>();
+                notLikes.forEach(str -> {
+                    and.add(criteriaBuilder.notLike(root.get("name"), "%" + str + "%"));
+                });
+                return criteriaBuilder.and(and.toArray(new Predicate[0]));
+            });
+        }
+
 //        if (pageRequest.getSort().stream().noneMatch(order -> order.getProperty().equals("createdAt"))) {
 //            pageRequest = PageRequest.of(pageRequest.getPageNumber(), pageQuery.getSize(),
 //                    pageRequest.getSort().and(Sort.by("createdAt").descending()));
@@ -356,6 +373,7 @@ public class CollectionService {
             BlindBoxItem blindBoxItem = new BlindBoxItem();
             BeanUtils.copyProperties(collection, blindBoxItem);
             blindBoxItem.setId(null);
+            blindBoxItem.setOasisId(collection.getOasisId());
             blindBoxItem.setCollectionId(item.getCollectionId());
             blindBoxItem.setSale(0);
             blindBoxItem.setTotal(item.getTotal());
@@ -653,4 +671,38 @@ public class CollectionService {
                     criteriaBuilder.not(root.get("ownerId").in(excludeUserId)));
         }, pageable);
     }
+
+    public List<Collection> setOasisScancode(List<Long> oasisIds) {
+        List<CollectionSource> collectionSources = new ArrayList<>();
+        collectionSources.add(CollectionSource.COMPANY);
+        collectionSources.add(CollectionSource.OFFICIAL);
+        List<Collection> collections = collectionRepo
+                .findAllByOasisIdInAndSourceInAndStockGreaterThan(oasisIds, collectionSources, 0);
+        List<Collection> result = new ArrayList<>();
+        collections.forEach(collection -> {
+            collection.setOnShelf(false);
+            collection.setScanCode(true);
+            collection.setSalable(true);
+            collectionRepo.save(collection);
+            result.add(collection);
+        });
+        return result;
+    }
+
+    public List<Collection> setOasisOnShelf(List<Long> oasisIds) {
+        List<CollectionSource> collectionSources = new ArrayList<>();
+        collectionSources.add(CollectionSource.COMPANY);
+        collectionSources.add(CollectionSource.OFFICIAL);
+        List<Collection> collections = collectionRepo
+                .findAllByOasisIdInAndSourceInAndStockGreaterThan(oasisIds, collectionSources, 0);
+        List<Collection> result = new ArrayList<>();
+        collections.forEach(collection -> {
+            collection.setOnShelf(true);
+            collection.setScanCode(false);
+            collection.setSalable(true);
+            collectionRepo.save(collection);
+            result.add(collection);
+        });
+        return result;
+    }
 }

+ 109 - 1
src/main/java/com/izouma/nineth/service/CompanyCollectionService.java

@@ -1,7 +1,11 @@
 package com.izouma.nineth.service;
 
+import com.izouma.nineth.config.GeneralProperties;
 import com.izouma.nineth.domain.*;
 import com.izouma.nineth.dto.PageQuery;
+import com.izouma.nineth.dto.oasis.OasisDistrictCollectionDTO;
+import com.izouma.nineth.dto.oasis.OasisDistrictDTO;
+import com.izouma.nineth.enums.AssetStatus;
 import com.izouma.nineth.enums.CollectionSource;
 import com.izouma.nineth.enums.CollectionStatus;
 import com.izouma.nineth.enums.CollectionType;
@@ -14,6 +18,11 @@ import org.springframework.beans.BeanUtils;
 import org.springframework.data.domain.Page;
 import org.springframework.stereotype.Service;
 
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+
 @Service
 @AllArgsConstructor
 public class CompanyCollectionService {
@@ -23,9 +32,12 @@ public class CompanyCollectionService {
     private UserRepo                userRepo;
     private CollectionPrivilegeRepo collectionPrivilegeRepo;
     private SysConfigService        sysConfigService;
+    private AssetRepo               assetRepo;
+    private GeneralProperties       generalProperties;
 
     public Page<CompanyCollection> all(PageQuery pageQuery) {
-        return companyCollectionRepo.findAll(JpaUtils.toSpecification(pageQuery, CompanyCollection.class), JpaUtils.toPageRequest(pageQuery));
+        return companyCollectionRepo.findAll(JpaUtils.toSpecification(pageQuery, CompanyCollection.class), JpaUtils
+                .toPageRequest(pageQuery));
     }
 
     public void audit(Long id, CollectionStatus status, String reason) {
@@ -85,4 +97,100 @@ public class CompanyCollectionService {
         companyCollectionRepo.save(companyCollection);
     }
 
+
+    public List<OasisDistrictCollectionDTO> oasisSearch(List<Long> oasisIds) {
+        List<OasisDistrictCollectionDTO> oasisDistrictCollectionDTOS = new ArrayList<>();
+        List<AssetStatus> assetStatuses = new ArrayList<>();
+        assetStatuses.add(AssetStatus.NORMAL);
+        assetStatuses.add(AssetStatus.AUCTION_TRADING);
+        assetStatuses.add(AssetStatus.GIFTING);
+        assetStatuses.add(AssetStatus.TRADING);
+        assetStatuses.add(AssetStatus.MINTING);
+        assetStatuses.add(AssetStatus.AUCTIONING);
+        List<Asset> assets = assetRepo
+                .findAllByOasisIdInAndStatusIn(oasisIds, assetStatuses);
+        List<CompanyCollection> companyCollections = companyCollectionRepo
+                .findAllByOasisIdInAndStatusNot(oasisIds, CollectionStatus.SUCCESS);
+        List<CollectionSource> collectionSources = new ArrayList<>();
+        collectionSources.add(CollectionSource.COMPANY);
+        collectionSources.add(CollectionSource.OFFICIAL);
+        List<Collection> officialCollections = collectionRepo
+                .findAllByOasisIdInAndSourceInAndStockGreaterThan(oasisIds, collectionSources, 0);
+
+        assets.forEach(asset -> {
+            OasisDistrictCollectionDTO oasisDistrictCollectionDTO = new OasisDistrictCollectionDTO();
+            oasisDistrictCollectionDTO.setOasisId(asset.getOasisId());
+            oasisDistrictCollectionDTO.setCollectionName(asset.getName());
+            oasisDistrictCollectionDTO.setOriginPrice(asset.getPrice());
+            oasisDistrictCollectionDTO.setScanOnly(false);
+            oasisDistrictCollectionDTO.setOwnerId(asset.getOwnerId());
+            oasisDistrictCollectionDTO.setOwnerName(asset.getOwner());
+            oasisDistrictCollectionDTO.setOwnerAvatar(asset.getOwnerAvatar());
+            oasisDistrictCollectionDTO.setCollectionId(asset.getId());
+            if (!asset.getStatus().equals(AssetStatus.NORMAL)) {
+                oasisDistrictCollectionDTO.setStatus(asset.getStatus().getDescription());
+            } else {
+                if (asset.isPublicShow()) {
+                    Collection collection = collectionRepo.findFirstByOnShelfAndAssetId(true, asset.getId());
+                    oasisDistrictCollectionDTO.setUrl(
+                            generalProperties.getHost() + "/9th/productDetail/" + collection
+                                    .getId() + "?id=" + collection.getId());
+                    if (asset.isConsignment()) {
+                        oasisDistrictCollectionDTO.setStatus("寄售中");
+                    } else {
+                        oasisDistrictCollectionDTO.setStatus("仅展示");
+                    }
+                } else {
+                    oasisDistrictCollectionDTO.setStatus("未展示");
+                }
+            }
+            oasisDistrictCollectionDTO.setSource("二手");
+            oasisDistrictCollectionDTOS.add(oasisDistrictCollectionDTO);
+        });
+
+        officialCollections.forEach(collection -> {
+            OasisDistrictCollectionDTO oasisDistrictCollectionDTO = new OasisDistrictCollectionDTO();
+            oasisDistrictCollectionDTO.setOasisId(collection.getOasisId());
+            oasisDistrictCollectionDTO.setCollectionName(collection.getName());
+            oasisDistrictCollectionDTO.setOriginPrice(collection.getPrice());
+            oasisDistrictCollectionDTO.setSalable(collection.isSalable());
+            oasisDistrictCollectionDTO.setOwnerId(collection.getOwnerId());
+            oasisDistrictCollectionDTO.setOwnerName(collection.getOwner());
+            oasisDistrictCollectionDTO.setOwnerAvatar(collection.getOwnerAvatar());
+            oasisDistrictCollectionDTO.setCollectionId(collection.getId());
+            oasisDistrictCollectionDTO.setScanOnly(collection.isScanCode());
+            oasisDistrictCollectionDTO.setSource("官方");
+            if (collection.isOnShelf()) {
+                oasisDistrictCollectionDTO.setUrl(
+                        generalProperties.getHost() + "/9th/productDetail/" + collection
+                                .getId() + "?id=" + collection.getId());
+                if (collection.isSalable()) {
+                    oasisDistrictCollectionDTO.setStatus("在售");
+                    if (collection.getStock() == 0) {
+                        oasisDistrictCollectionDTO.setStatus("已有订单,订单处理中");
+                    }
+                } else {
+                    oasisDistrictCollectionDTO.setStatus("仅展示");
+                }
+            } else {
+                oasisDistrictCollectionDTO.setStatus("未上架");
+            }
+            oasisDistrictCollectionDTOS.add(oasisDistrictCollectionDTO);
+        });
+
+        companyCollections.forEach(companyCollection -> {
+            OasisDistrictCollectionDTO oasisDistrictCollectionDTO = new OasisDistrictCollectionDTO();
+            oasisDistrictCollectionDTO.setOasisId(companyCollection.getOasisId());
+            oasisDistrictCollectionDTO.setCollectionName(companyCollection.getName());
+            oasisDistrictCollectionDTO.setScanOnly(false);
+            oasisDistrictCollectionDTO.setOriginPrice(companyCollection.getPrice());
+            oasisDistrictCollectionDTO.setOwnerName(companyCollection.getMinter());
+            oasisDistrictCollectionDTO.setCollectionId(companyCollection.getId());
+            oasisDistrictCollectionDTO.setSalable(false);
+            oasisDistrictCollectionDTO.setStatus("审核中");
+            oasisDistrictCollectionDTO.setSource("官方");
+            oasisDistrictCollectionDTOS.add(oasisDistrictCollectionDTO);
+        });
+        return oasisDistrictCollectionDTOS;
+    }
 }

+ 1 - 3
src/main/java/com/izouma/nineth/service/MintOrderService.java

@@ -345,9 +345,7 @@ public class MintOrderService {
                     .mintActivityId(mintActivityId)
                     .contactName(Optional.ofNullable(userAddress).map(UserAddress::getName).orElse(null))
                     .contactPhone(Optional.ofNullable(userAddress).map(UserAddress::getPhone).orElse(null))
-                    .address(Optional.ofNullable(userAddress).map(u ->
-                                    u.getProvinceName() + " " + u.getCityName() + " " + u.getDistrictName() + " " + u.getAddress())
-                            .orElse(null))
+                    .address(Optional.ofNullable(userAddress).map(UserAddress::getDetail).orElse(null))
                     .build());
 
             // 铸造资产

+ 25 - 5
src/main/java/com/izouma/nineth/service/NewsLikeService.java

@@ -5,6 +5,7 @@ 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.AuctionActivityRepo;
 import com.izouma.nineth.repo.NewsLikeRepo;
 import com.izouma.nineth.repo.NewsRepo;
 import com.izouma.nineth.repo.ShowroomRepo;
@@ -19,11 +20,12 @@ import java.util.List;
 @AllArgsConstructor
 public class NewsLikeService {
 
-    private NewsLikeRepo     newsLikeRepo;
-    private NewsRepo         newsRepo;
-    private ShowroomRepo     showroomRepo;
-    private SysConfigService sysConfigService;
-    private HeatInfoRepo     heatInfoRepo;
+    private NewsLikeRepo        newsLikeRepo;
+    private NewsRepo            newsRepo;
+    private ShowroomRepo        showroomRepo;
+    private SysConfigService    sysConfigService;
+    private HeatInfoRepo        heatInfoRepo;
+    private AuctionActivityRepo auctionActivityRepo;
 
     public Page<NewsLike> all(PageQuery pageQuery) {
         return newsLikeRepo.findAll(JpaUtils.toSpecification(pageQuery, NewsLike.class), JpaUtils.toPageRequest(pageQuery));
@@ -75,4 +77,22 @@ public class NewsLikeService {
             showroomRepo.addLike(roomId, -list.size());
         }
     }
+
+    public void likeAuction(Long userId, Long auctionId) {
+        List<NewsLike> list = newsLikeRepo.findByUserIdAndAuctionId(userId, auctionId);
+        if (!list.isEmpty()) return;
+        newsLikeRepo.save(NewsLike.builder()
+                .userId(userId)
+                .auctionId(auctionId)
+                .build());
+        auctionActivityRepo.addLike(auctionId, 1);
+    }
+
+    public void unlikeAuction(Long userId, Long auctionId) {
+        List<NewsLike> list = newsLikeRepo.findByUserIdAndAuctionId(userId, auctionId);
+        if (!list.isEmpty()) {
+            newsLikeRepo.deleteAll(list);
+            auctionActivityRepo.addLike(auctionId, -list.size());
+        }
+    }
 }

+ 22 - 11
src/main/java/com/izouma/nineth/service/OrderCancelService.java

@@ -3,19 +3,13 @@ package com.izouma.nineth.service;
 import com.izouma.nineth.annotations.RedisLock;
 import com.izouma.nineth.config.GeneralProperties;
 import com.izouma.nineth.config.RedisKeys;
-import com.izouma.nineth.domain.GiftOrder;
-import com.izouma.nineth.domain.MintOrder;
-import com.izouma.nineth.domain.Order;
-import com.izouma.nineth.domain.SysConfig;
+import com.izouma.nineth.domain.*;
 import com.izouma.nineth.dto.PayQuery;
+import com.izouma.nineth.enums.AuctionOrderStatus;
 import com.izouma.nineth.enums.MintOrderStatus;
 import com.izouma.nineth.enums.OrderStatus;
-import com.izouma.nineth.enums.PayStatus;
 import com.izouma.nineth.exception.BusinessException;
-import com.izouma.nineth.repo.GiftOrderRepo;
-import com.izouma.nineth.repo.MintOrderRepo;
-import com.izouma.nineth.repo.OrderRepo;
-import com.izouma.nineth.repo.SysConfigRepo;
+import com.izouma.nineth.repo.*;
 import lombok.AllArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
@@ -25,9 +19,7 @@ import org.springframework.stereotype.Service;
 
 import javax.annotation.PostConstruct;
 import java.time.LocalDateTime;
-import java.util.Arrays;
 import java.util.List;
-import java.util.Set;
 import java.util.concurrent.TimeUnit;
 
 @Service
@@ -45,6 +37,8 @@ public class OrderCancelService {
     private final GiftOrderService              giftOrderService;
     private final OrderPayService               orderPayService;
     private final RedisTemplate<String, Object> redisTemplate;
+    private final AuctionOrderRepo              auctionOrderRepo;
+    private final AuctionOrderService           auctionOrderService;
 
     private static int orderCancelInterval = 210;
 
@@ -136,4 +130,21 @@ public class OrderCancelService {
         }
         return true;
     }
+
+    @Scheduled(fixedRate = 30000)
+    public void batchCancelledAuctionOrder() {
+        List<AuctionOrder> orders = auctionOrderRepo
+                .findByStatusAndCreatedAtBeforeAndDelFalse(AuctionOrderStatus.NOT_PAID,
+                        LocalDateTime.now().minusSeconds(orderCancelInterval));
+        orders.parallelStream().forEach(o -> {
+            try {
+                AuctionOrder order = auctionOrderRepo.findById(o.getId()).orElseThrow(new BusinessException("订单不存在"));
+                if (order.getStatus() == AuctionOrderStatus.NOT_PAID) {
+                    auctionOrderService.cancel(order);
+                }
+            } catch (Exception e) {
+                log.error("取消拍卖订单错误 " + o.getId(), e);
+            }
+        });
+    }
 }

+ 77 - 18
src/main/java/com/izouma/nineth/service/OrderPayService.java

@@ -6,6 +6,7 @@ import com.izouma.nineth.config.GeneralProperties;
 import com.izouma.nineth.domain.*;
 import com.izouma.nineth.dto.PayQuery;
 import com.izouma.nineth.dto.UserBankCard;
+import com.izouma.nineth.enums.AuctionOrderStatus;
 import com.izouma.nineth.enums.MintOrderStatus;
 import com.izouma.nineth.enums.OrderStatus;
 import com.izouma.nineth.enums.PayMethod;
@@ -34,24 +35,26 @@ import java.util.stream.Stream;
 public class OrderPayService {
     private static String PAY_CHANNEL = Constants.PayChannel.SAND;
 
-    private final OrderService       orderService;
-    private final OrderRepo          orderRepo;
-    private final MintOrderRepo      mintOrderRepo;
-    private final GiftOrderRepo      giftOrderRepo;
-    private final SandPayService     sandPayService;
-    private final HMPayService       hmPayService;
-    private final GeneralProperties  generalProperties;
-    private final UserBalanceService userBalanceService;
-    private final RocketMQTemplate   rocketMQTemplate;
-    private final GiftOrderService   giftOrderService;
-    private final MintOrderService   mintOrderService;
-    private final UserRepo           userRepo;
-    private final SnowflakeIdWorker  snowflakeIdWorker;
-    private final RechargeOrderRepo  rechargeOrderRepo;
-    private final SysConfigService   sysConfigService;
-    private final PasswordEncoder    passwordEncoder;
-    private final PayEaseService     payEaseService;
-    private final UserBankCardRepo   userBankCardRepo;
+    private final OrderService        orderService;
+    private final OrderRepo           orderRepo;
+    private final MintOrderRepo       mintOrderRepo;
+    private final GiftOrderRepo       giftOrderRepo;
+    private final SandPayService      sandPayService;
+    private final HMPayService        hmPayService;
+    private final GeneralProperties   generalProperties;
+    private final UserBalanceService  userBalanceService;
+    private final RocketMQTemplate    rocketMQTemplate;
+    private final GiftOrderService    giftOrderService;
+    private final MintOrderService    mintOrderService;
+    private final UserRepo            userRepo;
+    private final SnowflakeIdWorker   snowflakeIdWorker;
+    private final RechargeOrderRepo   rechargeOrderRepo;
+    private final SysConfigService    sysConfigService;
+    private final PasswordEncoder     passwordEncoder;
+    private final PayEaseService      payEaseService;
+    private final UserBankCardRepo    userBankCardRepo;
+    private final AuctionOrderRepo    auctionOrderRepo;
+    private final AuctionOrderService auctionOrderService;
 
     public static void setPayChannel(String payChannel) {
         log.info("set pay channel {}", payChannel);
@@ -389,4 +392,60 @@ public class OrderPayService {
         }
         return Optional.ofNullable(query).orElse(PayQuery.builder().exist(false).build());
     }
+
+    @Cacheable(value = "payOrder", key = "'auctionOrder#'+#orderId")
+    public String payAuctionOrder(Long orderId) {
+        AuctionOrder order = auctionOrderRepo.findById(orderId).orElseThrow(new BusinessException("订单不存在"));
+        if (order.getStatus() != AuctionOrderStatus.NOT_PAID) {
+            throw new BusinessException("订单状态错误");
+        }
+        switch (PAY_CHANNEL) {
+            case Constants.PayChannel.SAND:
+                return sandPayService.pay(orderId + "", "拍卖:" + order.getName(), order.getTotalPrice(),
+                        order.getCreatedAt().plusMinutes(3), Constants.OrderNotifyType.AUCTION);
+            case Constants.PayChannel.HM:
+                return hmPayService.requestAlipay(orderId + "", order.getTotalPrice(),
+                        "拍卖:" + order.getName(), HMPayService.getTimeout(order.getCreatedAt(), 180),
+                        Constants.OrderNotifyType.AUCTION, generalProperties.getHost() + "/9th/home");
+        }
+        throw new BusinessException("绿洲宇宙冷却系统已启动,请稍后支付");
+    }
+
+    @Cacheable(value = "payOrder", key = "'auctionOrder#'+#orderId")
+    public String payAuctionQuick(Long orderId) {
+        AuctionOrder order = auctionOrderRepo.findById(orderId).orElseThrow(new BusinessException("订单不存在"));
+        if (order.getStatus() != AuctionOrderStatus.NOT_PAID) {
+            throw new BusinessException("订单状态错误");
+        }
+        return sandPayService.payQuick(orderId + "", "拍卖:" + order.getName(),
+                order.getTotalPrice(), order.getCreatedAt().plusMinutes(3), Constants.OrderNotifyType.AUCTION,
+                generalProperties.getHost() + "/9th/home");
+    }
+
+    public void payAuctionOrderBalance(Long orderId, Long userId, String tradeCode) {
+        AuctionOrder order = auctionOrderRepo.findById(orderId).orElseThrow(new BusinessException("订单不存在"));
+        if (order.getStatus() != AuctionOrderStatus.NOT_PAID) {
+            throw new BusinessException("订单状态错误");
+        }
+        checkTradeCode(userId, tradeCode, order.getUserId());
+        BalanceRecord record = userBalanceService.balancePay(order.getUserId(), order.getTotalPrice(), orderId, "拍卖");
+        auctionOrderService.notify(orderId, PayMethod.BALANCE, record.getId().toString());
+    }
+
+    @Cacheable(value = "payOrder", key = "'auctionOrder#'+#orderId")
+    public Map<String, Object> payAuctionOrderAgreement(Long orderId, String bindCardId) {
+        AuctionOrder order = auctionOrderRepo.findById(orderId).orElseThrow(new BusinessException("订单不存在"));
+        if (order.getStatus() != AuctionOrderStatus.NOT_PAID) {
+            throw new BusinessException("订单状态错误");
+        }
+        if (StringUtils.isEmpty(bindCardId)) {
+            bindCardId = userBankCardRepo.findByUserId(order.getUserId())
+                    .stream().map(UserBankCard::getBindCardId).findFirst().orElse(null);
+        }
+        if (StringUtils.isEmpty(bindCardId)) {
+            throw new BusinessException("请先绑定银行卡");
+        }
+        return payEaseService.pay("拍卖:" + order.getAuctionId(), orderId.toString(), order.getTotalPrice(),
+                order.getUserId().toString(), bindCardId, Constants.OrderNotifyType.AUCTION);
+    }
 }

+ 15 - 16
src/main/java/com/izouma/nineth/service/OrderService.java

@@ -386,11 +386,11 @@ public class OrderService {
                 notifyOrder(order.getId(), PayMethod.WEIXIN, null);
             }
 
-            if (usePoint > 0) {
-                // 扣除积分
-                userRepo.addVipPoint(userId, -usePoint);
-                cacheService.clearUserMy(userId);
-            }
+//            if (usePoint > 0) {
+//                // 扣除积分
+//                userRepo.addVipPoint(userId, -usePoint);
+//                cacheService.clearUserMy(userId);
+//            }
 
             if (ObjectUtils.isNotEmpty(showroomId)) {
                 //通过展厅的购买数量
@@ -407,16 +407,16 @@ public class OrderService {
             return order;
         } catch (Exception e) {
             collectionService.increaseStock(collectionId, qty);
-            if (usePoint > 0) {
-                // 扣除积分
-                userRepo.addVipPoint(userId, usePoint);
-                cacheService.clearUserMy(userId);
-                log.info("订单失败加积分用户ID:{}, 积分:{}", userId, usePoint);
-            }
-            if (vip) {
-                collectionService.decreaseQuota(collectionId, 1);
-                log.info("订单失败加藏品额度CollectionId:{}", collectionId);
-            }
+//            if (usePoint > 0) {
+//                // 扣除积分
+//                userRepo.addVipPoint(userId, usePoint);
+//                cacheService.clearUserMy(userId);
+//                log.info("订单失败加积分用户ID:{}, 积分:{}", userId, usePoint);
+//            }
+//            if (vip) {
+//                collectionService.decreaseQuota(collectionId, 1);
+//                log.info("订单失败加藏品额度CollectionId:{}", collectionId);
+//            }
             throw e;
         }
     }
@@ -722,7 +722,6 @@ public class OrderService {
                         if (asset != null && asset.getUserId() != null) {
                             smsService.sellOut(userRepo.findPhoneById(asset.getUserId()));
                         }
-
                         userBalanceService.realtimeSettleOrder(order);
                     } else {
                         orderRepo.save(order);

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

@@ -9,6 +9,7 @@ import com.izouma.nineth.config.SandPayProperties;
 import com.izouma.nineth.dto.PayQuery;
 import com.izouma.nineth.enums.PayStatus;
 import com.izouma.nineth.exception.BusinessException;
+import com.izouma.nineth.repo.AuctionOrderRepo;
 import com.izouma.nineth.repo.GiftOrderRepo;
 import com.izouma.nineth.repo.MintOrderRepo;
 import com.izouma.nineth.repo.OrderRepo;
@@ -18,7 +19,6 @@ import lombok.AllArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.codec.binary.Base64;
 import org.apache.commons.lang3.StringUtils;
-import org.springframework.data.redis.core.BoundSetOperations;
 import org.springframework.data.redis.core.RedisTemplate;
 import org.springframework.stereotype.Service;
 
@@ -47,6 +47,7 @@ public class SandPayService {
     private final MintOrderRepo                 mintOrderRepo;
     private final SnowflakeIdWorker             snowflakeIdWorker;
     private final GeneralProperties             generalProperties;
+    private final AuctionOrderRepo              auctionOrderRepo;
     private final RedisTemplate<String, Object> redisTemplate;
 
     public static String paddingOrderId(String orderId) {

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

@@ -8,6 +8,7 @@ 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.enums.ShowroomType;
 import com.izouma.nineth.exception.BusinessException;
 import com.izouma.nineth.repo.*;
 import com.izouma.nineth.utils.JpaUtils;
@@ -113,7 +114,7 @@ public class ShowroomService {
         return show;
     }
 
-    public Showroom save(Asset asset) {
+    public Showroom save(Asset asset, String type) {
         if (!AssetStatus.NORMAL.equals(asset.getStatus())) {
             throw new BusinessException("该状态不可创建展厅");
         }
@@ -134,14 +135,20 @@ public class ShowroomService {
                 .avatar(asset.getOwnerAvatar())
                 .assetId(asset.getId())
                 .nickname(asset.getOwner())
-                .type(ShowroomType.USER)
+                .type(ShowroomType.valueOf(type))
                 .status(AuthStatus.SUCCESS)
+                .oasisId(asset.getOasisId())
                 .build();
         showroom = showroomRepo.save(showroom);
 
         return showroom;
     }
 
+
+    public Showroom save(Asset asset) {
+        return this.save(asset, "USER");
+    }
+
     public Showroom save(Long userId, String type) {
         User user = userRepo.findByIdAndDelFalse(userId).orElseThrow(new BusinessException("无用户"));
         if (!user.isCompany()) {
@@ -244,6 +251,7 @@ public class ShowroomService {
                             coll.setAssetId(collection.getAssetId());
                             coll.setStatus(getStatus(collection));
                             coll.setPrice(collection.getPrice());
+                            coll.setName(collection.getName());
                             showCollectionRepo.save(coll);
                         }
                     }

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

@@ -39,7 +39,6 @@ import java.math.BigDecimal;
 import java.math.RoundingMode;
 import java.time.LocalDate;
 import java.time.LocalDateTime;
-import java.time.LocalTime;
 import java.time.temporal.ChronoUnit;
 import java.util.*;
 import java.util.concurrent.ExecutionException;
@@ -555,4 +554,29 @@ public class UserBalanceService {
                 .type(BalanceType.SELL)
                 .build());
     }
-}
+
+    public void addBalance(Long userId, BigDecimal amount, Long orderId, BalanceType type) {
+        //用户冲余额
+        UserBalance userBalance = userBalanceRepo.findByUserId(userId)
+                .orElse(UserBalance.builder()
+                        .balance(BigDecimal.ZERO)
+                        .lastBalance(BigDecimal.ZERO)
+                        .userId(userId)
+                        .build());
+
+        userBalance.setLastBalance(userBalance.getBalance());
+        userBalance.setBalance(userBalance.getBalance().add(amount));
+        userBalanceRepo.save(userBalance);
+        log.info("拍卖冲用户余额{},¥{}", userId, amount);
+
+        balanceRecordRepo.save(BalanceRecord.builder()
+                .time(LocalDateTime.now())
+                .userId(userId)
+                .orderId(orderId)
+                .amount(amount)
+                .balance(userBalance.getBalance())
+                .lastBalance(userBalance.getLastBalance())
+                .type(type)
+                .build());
+    }
+}

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

@@ -70,6 +70,8 @@ public class UserBankCardService {
         if (user != null) {
             user.setSettleAccountId(request.getBindCardId());
             userService.save(user);
+            //加积分加限购
+            userService.savePoint(user);
         }
         userBalanceRepo.unlock(Long.parseLong(request.getUserId()));
     }

+ 129 - 0
src/main/java/com/izouma/nineth/service/UserService.java

@@ -5,6 +5,7 @@ import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
 import cn.binarywang.wx.miniapp.bean.WxMaUserInfo;
 import cn.hutool.core.convert.Convert;
 import com.alibaba.fastjson.JSON;
+import cn.hutool.core.collection.CollUtil;
 import com.alibaba.fastjson.JSONObject;
 import com.alipay.api.AlipayApiException;
 import com.alipay.api.AlipayClient;
@@ -25,6 +26,8 @@ import com.izouma.nineth.config.RedisKeys;
 import com.izouma.nineth.domain.Collection;
 import com.izouma.nineth.domain.*;
 import com.izouma.nineth.dto.*;
+import com.izouma.nineth.dto.oasis.OasisLoginDTO;
+import com.izouma.nineth.enums.AssetStatus;
 import com.izouma.nineth.enums.AuthStatus;
 import com.izouma.nineth.enums.AuthorityName;
 import com.izouma.nineth.enums.HeatType;
@@ -57,10 +60,14 @@ import org.springframework.data.domain.Sort;
 import org.springframework.data.jpa.domain.Specification;
 import org.springframework.data.redis.core.RedisTemplate;
 import org.springframework.scheduling.annotation.Async;
+import org.springframework.scheduling.annotation.Scheduled;
 import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
 import org.springframework.security.crypto.password.PasswordEncoder;
 import org.springframework.stereotype.Service;
 
+import javax.management.openmbean.OpenMBeanAttributeInfoSupport;
+import javax.persistence.criteria.CriteriaBuilder;
+import javax.persistence.criteria.CriteriaQuery;
 import javax.persistence.criteria.Predicate;
 import java.math.BigDecimal;
 import java.math.BigInteger;
@@ -106,6 +113,12 @@ public class UserService {
     private AlipayClient                  alipayClient;
     private SnowflakeIdWorker             snowflakeIdWorker;
     private FaceAuthRepo                  faceAuthRepo;
+    private AuctionPassRecordRepo         auctionPassRecordRepo;
+    private AssetRepo                     assetRepo;
+    private ShowCollectionRepo            showCollectionRepo;
+    private ShowroomService               showroomService;
+    private NewsLikeRepo                  newsLikeRepo;
+    private UserPropertyRepo              userPropertyRepo;
 
     public User update(User user) {
         if (!SecurityUtils.hasRole(AuthorityName.ROLE_ADMIN)) {
@@ -1077,7 +1090,9 @@ public class UserService {
                                     .userId(user.getId())
                                     .idNo(faceAuth.getIdNo())
                                     .realName(faceAuth.getName())
+                                    .status(AuthStatus.SUCCESS)
                                     .build());
+                            identityAuthRepo.deleteDuplicated(user.getId(), identityAuth.getId());
                             user.setAuthStatus(AuthStatus.SUCCESS);
                             user.setAuthId(identityAuth.getId());
                             save(user);
@@ -1089,4 +1104,118 @@ public class UserService {
             }
         });
     }
+
+    public Map<String, Object> oasisInfo(Long userId) {
+        Map<String, Object> map = new HashMap<>();
+        User user = userRepo.findById(userId).orElseThrow(new BusinessException("未找到用户信息"));
+        map.put("nickName", user.getNickname());
+        List<Asset> assets = assetRepo.findAllByOwnerIdAndStatusAndOasisIdNotNull(userId, AssetStatus.NORMAL);
+        List<OasisLoginDTO> oasisLoginDTOS = new ArrayList<>();
+        assets.forEach(asset -> {
+            OasisLoginDTO oasisLoginDTO = new OasisLoginDTO();
+            oasisLoginDTO.setOasisId(asset.getOasisId());
+            oasisLoginDTO.setAssetId(asset.getId());
+            oasisLoginDTO.setSource(asset.getStatus().getDescription());
+            Collection collection = collectionRepo.findFirstByOnShelfAndAssetId(true, asset.getId());
+            if (collection != null) {
+                oasisLoginDTO.setUrl(generalProperties.getHost() + "/9th/productDetail/" + collection
+                        .getId() + "?id=" + collection.getId());
+            } else {
+                oasisLoginDTO.setUrl("未公开展示");
+            }
+
+            Showroom showroom = showroomRepo.findByOasisId(oasisLoginDTO.getOasisId())
+                    .orElseThrow(new BusinessException("无记录 "));
+            List<ShowCollection> origin = showCollectionRepo.findAllByShowroomIdOrderBySort(showroom.getId());
+            List<ShowCollection> neo = new ArrayList<>();
+            if (origin != null) {
+                origin.forEach(orig -> collectionRepo.findById(orig.getCollectionId())
+                        .ifPresent(collection1 -> {
+                            orig.setStatus(showroomService.getStatus(collection1));
+                            orig.setPrice(collection1.getPrice());
+                            neo.add(orig);
+                        }));
+            }
+            showroom.setCollections(neo);
+            User showRoomUser = SecurityUtils.getAuthenticatedUser();
+
+            if (showRoomUser != null && !showRoomUser.isAdmin()) {
+                List<NewsLike> likes = newsLikeRepo.findByUserIdAndShowroomId(showRoomUser
+                        .getId(), showroom.getId());
+                showroom.setLiked(CollUtil.isNotEmpty(likes));
+            }
+            oasisLoginDTO.setShowroom(showroom);
+            oasisLoginDTOS.add(oasisLoginDTO);
+        });
+        map.put("oasisInfo", oasisLoginDTOS);
+        map.put("avatar", SecurityUtils.getAuthenticatedUser().getAvatar());
+        return map;
+    }
+
+    /**
+     * 流拍5次直接删号处罚
+     */
+    @Scheduled(cron = "0 0/10 * * * ?")
+    public void delUser() {
+        List<Long> userIds = auctionPassRecordRepo.checkUserId();
+        if (CollUtil.isNotEmpty(userIds)) {
+            log.info("流拍处罚:{}", userIds);
+            userRepo.softDeleteIn(userIds);
+            //清缓存
+            userIds.forEach(id -> {
+                cacheService.clearUserMy(id);
+                cacheService.clearUser(id);
+            });
+
+        }
+
+    }
+
+    public void savePoint(User user) {
+        //给积分
+        Long invitor = user.getCollectionInvitor();
+        if (ObjectUtils.isEmpty(user.getCollectionId()) || ObjectUtils.isEmpty(invitor)) {
+            return;
+        }
+        Collection collection = collectionRepo.findById(user.getCollectionId()).orElse(null);
+        if (collection == null) {
+            return;
+        }
+        if (user.getVipPoint() < 1) {
+            //有效新用户1个限购
+            user.setVipPoint(100);
+            userRepo.save(user);
+            cacheService.clearUserMy(user.getId());
+            cacheService.clearUser(user.getId());
+        }
+
+        //指标数量
+        int assignment = collection.getAssignment();
+        if (assignment < 1) {
+            return;
+        }
+        int inviteNum = userRepo.countAllByCollectionIdAndCollectionInvitorAndSettleAccountIdIsNotNull(
+                user.getCollectionId(), invitor);
+
+        int point = inviteNum / assignment;
+        if (point < 1) {
+            return;
+        }
+        User parent = userRepo.findById(invitor).orElse(null);
+        if (parent == null) {
+            return;
+        }
+        if (parent.getVipPoint() < 1) {
+            //老用户可有一个限购
+            parent.setVipPoint(100);
+            userRepo.save(parent);
+            cacheService.clearUserMy(user.getId());
+            cacheService.clearUser(user.getId());
+        }
+        UserProperty userProperty = userPropertyRepo.findById(invitor).orElse(new UserProperty(invitor, point));
+        if (userProperty.getMaxCount() < 10 && userProperty.getMaxCount() != point) {
+            userProperty.setMaxCount(point);
+            userPropertyRepo.save(userProperty);
+        }
+    }
 }

+ 0 - 28
src/main/java/com/izouma/nineth/service/WithdrawApplyScheduleService.java

@@ -1,43 +1,15 @@
 package com.izouma.nineth.service;
 
-import com.alibaba.fastjson.JSONObject;
 import com.izouma.nineth.annotations.RedisLock;
-import com.izouma.nineth.config.Constants;
-import com.izouma.nineth.domain.WithdrawApply;
-import com.izouma.nineth.dto.PageQuery;
-import com.izouma.nineth.dto.UserBankCard;
-import com.izouma.nineth.enums.BalanceType;
-import com.izouma.nineth.enums.WithdrawStatus;
-import com.izouma.nineth.exception.BusinessException;
-import com.izouma.nineth.repo.BalanceRecordRepo;
-import com.izouma.nineth.repo.UserBalanceRepo;
-import com.izouma.nineth.repo.UserBankCardRepo;
-import com.izouma.nineth.repo.WithdrawApplyRepo;
 import com.izouma.nineth.utils.DateTimeUtils;
-import com.izouma.nineth.utils.JpaUtils;
-import com.izouma.nineth.utils.SnowflakeIdWorker;
 import lombok.AllArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
-import org.apache.commons.lang3.StringUtils;
-import org.redisson.api.RLock;
-import org.redisson.api.RedissonClient;
-import org.springframework.core.env.Environment;
-import org.springframework.data.domain.Page;
-import org.springframework.scheduling.annotation.Async;
 import org.springframework.scheduling.annotation.Scheduled;
 import org.springframework.stereotype.Service;
 
-import java.math.BigDecimal;
-import java.math.RoundingMode;
 import java.time.LocalDate;
-import java.time.LocalDateTime;
-import java.time.LocalTime;
-import java.util.Arrays;
-import java.util.Optional;
 import java.util.concurrent.ExecutionException;
-import java.util.concurrent.ForkJoinPool;
 import java.util.concurrent.TimeUnit;
-import java.util.regex.Pattern;
 
 @Service
 @AllArgsConstructor

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

@@ -18,12 +18,10 @@ import com.izouma.nineth.utils.SnowflakeIdWorker;
 import lombok.AllArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang3.StringUtils;
-import org.redisson.api.RLock;
 import org.redisson.api.RedissonClient;
 import org.springframework.core.env.Environment;
 import org.springframework.data.domain.Page;
 import org.springframework.scheduling.annotation.Async;
-import org.springframework.scheduling.annotation.Scheduled;
 import org.springframework.stereotype.Service;
 
 import java.math.BigDecimal;
@@ -168,6 +166,11 @@ public class WithdrawApplyService {
     }
 
     @Async
+    @RedisLock(value = "'approveAll'", expire = 1, unit = TimeUnit.HOURS)
+    public void approveAllAsync() throws ExecutionException, InterruptedException {
+        approveAll();
+    }
+
     @RedisLock(value = "'approveAll'", expire = 1, unit = TimeUnit.HOURS)
     public void approveAll() throws ExecutionException, InterruptedException {
         new ForkJoinPool(5).submit(() -> {

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

@@ -9,6 +9,7 @@ import com.izouma.nineth.service.CacheService;
 import com.izouma.nineth.utils.ObjUtils;
 import com.izouma.nineth.utils.excel.ExcelUtils;
 import lombok.AllArgsConstructor;
+import org.apache.commons.lang3.StringUtils;
 import org.springframework.cache.annotation.Cacheable;
 import org.springframework.data.domain.Page;
 import org.springframework.security.access.prepost.PreAuthorize;
@@ -93,10 +94,11 @@ public class AppVersionController extends BaseController {
     }
 
     @GetMapping("/checkUpdate")
-    @Cacheable(value = "checkUpdate", key = "#platform+'@'+#version")
-    public Map<String, Object> checkUpdate(@RequestParam String platform, @RequestParam String version) {
+    @Cacheable(value = "checkUpdate", key = "#platform+'@'+#version+'@'+#channel")
+    public Map<String, Object> checkUpdate(@RequestParam String platform, @RequestParam String version,
+                                           @RequestParam(required = false, defaultValue = "default") String channel) {
         Map<String, Object> map = new HashMap<>();
-        AppVersion appVersion = appVersionRepo.findFirstByPlatformAndReviewFalseAndDelFalseOrderByVersionNumDesc(platform)
+        AppVersion appVersion = appVersionRepo.findLatest(platform, channel)
                 .orElseThrow(new BusinessException("版本不存在"));
         map.put("version", appVersion);
 

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

@@ -4,6 +4,7 @@ import com.fasterxml.jackson.annotation.JsonView;
 import com.izouma.nineth.TokenHistory;
 import com.izouma.nineth.domain.Asset;
 import com.izouma.nineth.domain.GiftOrder;
+import com.izouma.nineth.dto.AssetDTO;
 import com.izouma.nineth.dto.PageQuery;
 import com.izouma.nineth.dto.UserHistory;
 import com.izouma.nineth.enums.CollectionType;
@@ -35,11 +36,11 @@ import java.util.concurrent.ExecutionException;
 @RequestMapping("/asset")
 @AllArgsConstructor
 public class AssetController extends BaseController {
-    private AssetService assetService;
-    private AssetRepo assetRepo;
+    private AssetService     assetService;
+    private AssetRepo        assetRepo;
     private GiftOrderService giftOrderService;
-    private OrderRepo orderRepo;
-    private CacheService cacheService;
+    private OrderRepo        orderRepo;
+    private CacheService     cacheService;
 
     //@PreAuthorize("hasRole('ADMIN')")
 //    @PostMapping("/save")
@@ -61,11 +62,23 @@ public class AssetController extends BaseController {
         return assetService.all(pageQuery);
     }
 
+    /**
+     * 资产查询,除未开启盲盒prefixName相同叠加数量
+     *
+     * @param pageQuery 查询条件
+     * @return 资产叠加后结果
+     */
+    @PostMapping("/superimposition")
+    public List<AssetDTO> superimposition(@RequestBody PageQuery pageQuery) {
+        pageQuery.getQuery().put("userId", SecurityUtils.getAuthenticatedUser().getId());
+        return assetService.superimposition(pageQuery);
+    }
+
     @GetMapping("/get/{id}")
     @JsonView(Asset.View.Basic.class)
     public Asset get(@PathVariable Long id) {
         Asset asset = assetRepo.findById(id).orElseThrow(new BusinessException("无记录"));
-        orderRepo.findByIdAndDelFalse(asset.getOrderId()).ifPresent(order -> asset.setOpened(order.isOpened()));
+//        orderRepo.findByIdAndDelFalse(asset.getOrderId()).ifPresent(order -> asset.setOpened(order.isOpened()));
         return asset;
     }
 
@@ -201,7 +214,13 @@ public class AssetController extends BaseController {
     @PostMapping("/getRoyalties")
     public int getRoyalties(@RequestParam Long id) {
         Asset asset = assetRepo.findById(id).orElseThrow(new BusinessException("无记录"));
-        return assetService.getRoyalties(asset.getMinterId(), asset.getRoyalties(), SecurityUtils.getAuthenticatedUser().getId());
+        return assetService.getRoyalties(asset.getMinterId(), asset.getRoyalties(), SecurityUtils.getAuthenticatedUser()
+                .getId());
+    }
+
+    @GetMapping("/hcChain")
+    public void hcChain() throws ExecutionException, InterruptedException {
+        assetService.hcChain();
     }
 }
 

+ 77 - 0
src/main/java/com/izouma/nineth/web/AuctionActivityController.java

@@ -0,0 +1,77 @@
+package com.izouma.nineth.web;
+
+import com.izouma.nineth.domain.AuctionActivity;
+import com.izouma.nineth.dto.PageQuery;
+import com.izouma.nineth.dto.auction.AuctionInputDTO;
+import com.izouma.nineth.exception.BusinessException;
+import com.izouma.nineth.repo.AuctionActivityRepo;
+import com.izouma.nineth.repo.NewsLikeRepo;
+import com.izouma.nineth.service.AuctionActivityService;
+import com.izouma.nineth.utils.ObjUtils;
+import com.izouma.nineth.utils.SecurityUtils;
+import com.izouma.nineth.utils.excel.ExcelUtils;
+import lombok.AllArgsConstructor;
+import org.springframework.data.domain.Page;
+import org.springframework.web.bind.annotation.*;
+
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.util.List;
+
+@RestController
+@RequestMapping("/auctionActivity")
+@AllArgsConstructor
+public class AuctionActivityController extends BaseController {
+    private AuctionActivityService auctionActivityService;
+    private AuctionActivityRepo    auctionActivityRepo;
+    private NewsLikeRepo           newsLikeRepo;
+
+    //@PreAuthorize("hasRole('ADMIN')")
+    @PostMapping("/save")
+    public AuctionActivity save(@RequestBody AuctionActivity record, @RequestParam(required = false) String code) {
+        if (record.getId() != null) {
+            AuctionActivity orig = auctionActivityRepo.findById(record.getId())
+                    .orElseThrow(new BusinessException("无记录"));
+            ObjUtils.merge(orig, record);
+            return auctionActivityService.save(orig, code);
+        }
+        return auctionActivityService.save(record, code);
+    }
+
+    @PostMapping("/create")
+    public AuctionActivity createFromAsset(@RequestBody AuctionInputDTO dto) {
+        return auctionActivityService.createFromAsset(dto);
+    }
+
+    //@PreAuthorize("hasRole('ADMIN')")
+    @PostMapping("/all")
+    public Page<AuctionActivity> all(@RequestBody PageQuery pageQuery) {
+        return auctionActivityService.all(pageQuery);
+    }
+
+    @GetMapping("/get/{id}")
+    public AuctionActivity get(@PathVariable Long id) {
+        AuctionActivity auctionActivity = auctionActivityRepo.findById(id).orElseThrow(new BusinessException("无记录"));
+        if (SecurityUtils.getAuthenticatedUser() != null) {
+            if (newsLikeRepo.findByUserIdAndAuctionId(SecurityUtils.getAuthenticatedUser().getId(), id).size() > 0) {
+                auctionActivity.setLiked(true);
+                return auctionActivity;
+            }
+        }
+        auctionActivity.setLiked(false);
+        return auctionActivity;
+    }
+
+//    @PostMapping("/del/{id}")
+//    public void del(@PathVariable Long id) {
+//        auctionActivityRepo.softDelete(id);
+//    }
+
+    @GetMapping("/excel")
+    @ResponseBody
+    public void excel(HttpServletResponse response, PageQuery pageQuery) throws IOException {
+        List<AuctionActivity> data = all(pageQuery).getContent();
+        ExcelUtils.export(response, data);
+    }
+}
+

+ 124 - 0
src/main/java/com/izouma/nineth/web/AuctionOrderController.java

@@ -0,0 +1,124 @@
+package com.izouma.nineth.web;
+
+import com.izouma.nineth.domain.AuctionOrder;
+import com.izouma.nineth.dto.PageQuery;
+import com.izouma.nineth.enums.AuctionPaymentType;
+import com.izouma.nineth.exception.BusinessException;
+import com.izouma.nineth.repo.AuctionOrderRepo;
+import com.izouma.nineth.service.AuctionOrderService;
+import com.izouma.nineth.utils.ObjUtils;
+import com.izouma.nineth.utils.excel.ExcelUtils;
+import io.swagger.annotations.ApiModelProperty;
+import io.swagger.annotations.ApiOperation;
+import lombok.AllArgsConstructor;
+import org.springframework.data.domain.Page;
+import org.springframework.web.bind.annotation.*;
+
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.util.List;
+
+@RestController
+@RequestMapping("/auctionOrder")
+@AllArgsConstructor
+public class AuctionOrderController extends BaseController {
+    private AuctionOrderService auctionOrderService;
+    private AuctionOrderRepo    auctionOrderRepo;
+
+    //@PreAuthorize("hasRole('ADMIN')")
+    @PostMapping("/save")
+    public AuctionOrder save(@RequestBody AuctionOrder record) {
+        if (record.getId() != null) {
+            AuctionOrder orig = auctionOrderRepo.findById(record.getId()).orElseThrow(new BusinessException("无记录"));
+            ObjUtils.merge(orig, record);
+            return auctionOrderRepo.save(orig);
+        }
+        return auctionOrderRepo.save(record);
+
+
+    }
+
+    @PostMapping("/create")
+    @ApiModelProperty(value = "创建拍卖订单(支付)")
+    public AuctionOrder create(Long userId, @RequestParam(required = false) Long auctionId,
+                               Long addressId, Long auctionRecordId, AuctionPaymentType type) {
+        return auctionOrderService.create(userId, auctionId, addressId, auctionRecordId, type);
+    }
+
+    @PostMapping("/createFixPrice")
+    @ApiModelProperty(value = "创建拍卖订单(一口价)")
+    public AuctionOrder createFixPrice(Long userId, @RequestParam(required = false) Long auctionId,
+                                       Long addressId, AuctionPaymentType type) {
+//        AuctionActivity auctionActivity = auctionActivityRepo.findById(auctionId)
+//                .orElseThrow(new BusinessException("暂无"));
+//        AuctionRecord auctionRecord = AuctionRecord.builder()
+//                .auctionId(auctionId)
+//                .type(AuctionRecordType.FIXEDPRICE)
+//                .bidderPrice(auctionActivity.getFixedPrice())
+//                .auctionPic(null)
+//                .userId(SecurityUtils.getAuthenticatedUser().getId())
+//                .avatar(SecurityUtils.getAuthenticatedUser().getAvatar())
+//                .name(auctionActivity.getName())
+//                .purchased(false)
+//                .build();
+//        AuctionRecord record = auctionRecordRepo.save(auctionRecord);
+        return auctionOrderService.create(userId, auctionId, addressId, null, type);
+    }
+
+    @PostMapping("/createDeposit")
+    @ApiModelProperty(value = "创建拍卖订单(保证金)")
+    public AuctionOrder createDeposit(Long userId, @RequestParam(required = false) Long auctionId,
+                                      Long addressId, AuctionPaymentType type) {
+
+//        AuctionActivity auctionActivity = auctionActivityRepo.findById(auctionId)
+//                .orElseThrow(new BusinessException("暂无"));
+//        AuctionRecord auctionRecord = AuctionRecord.builder()
+//                .auctionId(auctionId)
+//                .type(AuctionRecordType.DEPOSIT)
+//                .bidderPrice(auctionActivity.getDeposit())
+//                .auctionPic(null)
+//                .userId(SecurityUtils.getAuthenticatedUser().getId())
+//                .avatar(SecurityUtils.getAuthenticatedUser().getAvatar())
+//                .name(auctionActivity.getName())
+//                .purchased(false)
+//                .build();
+//        AuctionRecord record = auctionRecordRepo.save(auctionRecord);
+        return auctionOrderService.create(userId, auctionId, addressId, null, type);
+    }
+
+    //@PreAuthorize("hasRole('ADMIN')")
+    @PostMapping("/all")
+    public Page<AuctionOrder> all(@RequestBody PageQuery pageQuery) {
+        return auctionOrderService.all(pageQuery);
+    }
+
+    @GetMapping("/get/{id}")
+    public AuctionOrder get(@PathVariable Long id) {
+        return auctionOrderRepo.findById(id).orElseThrow(new BusinessException("无记录"));
+    }
+
+    @PostMapping("/del/{id}")
+    public void del(@PathVariable Long id) {
+        auctionOrderRepo.softDelete(id);
+    }
+
+    @GetMapping("/excel")
+    @ResponseBody
+    public void excel(HttpServletResponse response, PageQuery pageQuery) throws IOException {
+        List<AuctionOrder> data = all(pageQuery).getContent();
+        ExcelUtils.export(response, data);
+    }
+
+    @ApiOperation("订单完成")
+    @GetMapping("/finish/{id}")
+    public void finish(@PathVariable Long id) {
+        auctionOrderService.finish(id);
+    }
+
+    @ApiOperation("订单发货")
+    @GetMapping("/delivery")
+    public void delivery(@RequestParam Long id, @RequestParam String courierId) {
+        auctionOrderService.dispatch(id, courierId);
+    }
+}
+

+ 86 - 0
src/main/java/com/izouma/nineth/web/AuctionRecordController.java

@@ -0,0 +1,86 @@
+package com.izouma.nineth.web;
+
+import com.izouma.nineth.domain.AuctionRecord;
+import com.izouma.nineth.dto.auction.AuctionRecordDTO;
+import com.izouma.nineth.service.AuctionRecordService;
+import com.izouma.nineth.dto.PageQuery;
+import com.izouma.nineth.exception.BusinessException;
+import com.izouma.nineth.repo.AuctionRecordRepo;
+import com.izouma.nineth.utils.ObjUtils;
+import com.izouma.nineth.utils.SecurityUtils;
+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.math.BigDecimal;
+import java.util.List;
+
+@RestController
+@RequestMapping("/auctionRecord")
+@AllArgsConstructor
+public class AuctionRecordController extends BaseController {
+    private AuctionRecordService auctionRecordService;
+    private AuctionRecordRepo    auctionRecordRepo;
+
+    //@PreAuthorize("hasRole('ADMIN')")
+    @PostMapping("/save")
+    public AuctionRecord save(@RequestBody AuctionRecord record) {
+        if (record.getId() != null) {
+            AuctionRecord orig = auctionRecordRepo.findById(record.getId()).orElseThrow(new BusinessException("无记录"));
+            ObjUtils.merge(orig, record);
+            return auctionRecordRepo.save(orig);
+        }
+        return auctionRecordRepo.save(record);
+    }
+
+
+    //@PreAuthorize("hasRole('ADMIN')")
+    @PostMapping("/all")
+    public Page<AuctionRecord> all(@RequestBody PageQuery pageQuery) {
+        return auctionRecordService.all(pageQuery);
+    }
+
+    @PostMapping("/recordInfos")
+    public Page<AuctionRecordDTO> recordInfos(@RequestBody PageQuery pageQuery) {
+        return auctionRecordService.recordInfos(pageQuery);
+    }
+
+    @PostMapping("/userRecord")
+    public List<AuctionRecordDTO> userRecord(@RequestParam String type) {
+        return auctionRecordService.userRecord(SecurityUtils.getAuthenticatedUser().getId(), type);
+    }
+
+
+    @GetMapping("/get/{id}")
+    public AuctionRecord get(@PathVariable Long id) {
+        return auctionRecordRepo.findById(id).orElseThrow(new BusinessException("无记录"));
+    }
+
+    @PostMapping("/del/{id}")
+    public void del(@PathVariable Long id) {
+        auctionRecordRepo.softDelete(id);
+    }
+
+    @GetMapping("/excel")
+    @ResponseBody
+    public void excel(HttpServletResponse response, PageQuery pageQuery) throws IOException {
+        List<AuctionRecord> data = all(pageQuery).getContent();
+        ExcelUtils.export(response, data);
+    }
+
+    @GetMapping("/hasPayDeposit")
+    public AuctionRecord hasPayDeposit(Long auctionId) {
+        return auctionRecordRepo
+                .findTopByAuctionIdAndUserIdOrderByIdDesc(auctionId, SecurityUtils.getAuthenticatedUser()
+                        .getId());
+    }
+
+    @PostMapping("/create")
+    public AuctionRecord created(Long auctionId, BigDecimal amount) {
+        return auctionRecordService.create(SecurityUtils.getAuthenticatedUser().getId(), auctionId, amount);
+    }
+}
+

+ 18 - 0
src/main/java/com/izouma/nineth/web/AuthenticationController.java

@@ -33,6 +33,24 @@ public class AuthenticationController {
         return jwtTokenUtil.generateToken(JwtUserFactory.create(user));
     }
 
+    @PostMapping("/oasisLogin")
+    public Map<String, Object> oasisLogin(String phone, String password, Integer expiration) {
+        User user = userService.loginByPhonePwd(phone, password);
+        Map<String, Object> result = userService.oasisInfo(user.getId());
+        result.put("token", jwtTokenUtil.generateToken(JwtUserFactory.create(user)));
+        result.put("userId", user.getId());
+        return result;
+    }
+
+    @PostMapping("/oasisLoginPhone")
+    public Map<String, Object> oasisLogin(String phone, String code) {
+        User user = userService.loginByPhone(phone, code);
+        Map<String, Object> result = userService.oasisInfo(user.getId());
+        result.put("token", jwtTokenUtil.generateToken(JwtUserFactory.create(user)));
+        result.put("userId", user.getId());
+        return result;
+    }
+
     @PostMapping("/loginAdmin")
     public String loginByUserPwdAdmin(String username, String password, Integer expiration) {
         User user = userService.loginByUsernamePwd(username, password);

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

@@ -223,5 +223,17 @@ public class CollectionController extends BaseController {
                                   Pageable pageable) {
         return collectionService.byTag(tagId, excludeUserId, pageable);
     }
+
+    @PreAuthorize("hasAnyRole('ADMIN','COMPANY')")
+    @PostMapping("/onShelfOasis")
+    public List<Collection> onShelfOasis(@RequestBody List<Long> oasisIds) {
+        return collectionService.setOasisOnShelf(oasisIds);
+    }
+
+    @PreAuthorize("hasAnyRole('ADMIN','COMPANY')")
+    @PostMapping("/setScancodeOasis")
+    public List<Collection> setScancodeOasis(@RequestBody List<Long> oasisIds) {
+        return collectionService.setOasisScancode(oasisIds);
+    }
 }
 

+ 63 - 4
src/main/java/com/izouma/nineth/web/CompanyCollectionController.java

@@ -1,6 +1,8 @@
 package com.izouma.nineth.web;
 
 import com.izouma.nineth.domain.CompanyCollection;
+import com.izouma.nineth.dto.oasis.OasisDistrictCollectionDTO;
+import com.izouma.nineth.dto.oasis.OasisDistrictDTO;
 import com.izouma.nineth.enums.CollectionStatus;
 import com.izouma.nineth.service.CompanyCollectionService;
 import com.izouma.nineth.dto.PageQuery;
@@ -10,12 +12,14 @@ import com.izouma.nineth.utils.ObjUtils;
 import com.izouma.nineth.utils.SecurityUtils;
 import com.izouma.nineth.utils.excel.ExcelUtils;
 import lombok.AllArgsConstructor;
+import org.springframework.beans.BeanUtils;
 import org.springframework.data.domain.Page;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.web.bind.annotation.*;
 
 import javax.servlet.http.HttpServletResponse;
 import java.io.IOException;
+import java.util.ArrayList;
 import java.util.List;
 
 @RestController
@@ -42,6 +46,65 @@ public class CompanyCollectionController extends BaseController {
         return companyCollectionRepo.save(record);
     }
 
+    //oasis创建保存地块接口
+    @PreAuthorize("hasAnyRole('ADMIN','COMPANY')")
+    @PostMapping("/saveDistrict")
+    public CompanyCollection saveDistrict(@RequestBody OasisDistrictDTO oasisDistrictDTO) {
+        CompanyCollection record = new CompanyCollection();
+        BeanUtils.copyProperties(oasisDistrictDTO, record);
+        record.setStatus(CollectionStatus.PENDING);
+        record.setCategory("地块");
+        record.setUserId(7958191L);
+        record.setMinter("oasis地块测试");
+        if (record.getId() != null) {
+            CompanyCollection orig = companyCollectionRepo.findById(record.getId())
+                    .orElseThrow(new BusinessException("无记录"));
+            if (CollectionStatus.SUCCESS.equals(orig.getStatus())) {
+                throw new BusinessException("已通过申请,不可编辑");
+            }
+
+            ObjUtils.merge(orig, record);
+            return companyCollectionRepo.save(orig);
+        }
+        record.setUserId(SecurityUtils.getAuthenticatedUser().getId());
+        return companyCollectionRepo.save(record);
+    }
+
+    //oasis创建保存地块接口
+    @PreAuthorize("hasAnyRole('ADMIN','COMPANY')")
+    @PostMapping("/multiDistrict")
+    public List<CompanyCollection> multiDistrict(@RequestBody List<OasisDistrictDTO> oasisDistrictDTOs) {
+        List<CompanyCollection> companyCollections = new ArrayList<>();
+        oasisDistrictDTOs.forEach(oasisDistrictDTO -> {
+            CompanyCollection record = new CompanyCollection();
+            BeanUtils.copyProperties(oasisDistrictDTO, record);
+            record.setStatus(CollectionStatus.PENDING);
+            record.setCategory("地块");
+            record.setUserId(7958191L);
+            record.setMinter("oasis地块测试");
+            if (record.getId() != null) {
+                CompanyCollection orig = companyCollectionRepo.findById(record.getId())
+                        .orElseThrow(new BusinessException("无记录"));
+                if (CollectionStatus.SUCCESS.equals(orig.getStatus())) {
+                    throw new BusinessException("已通过申请,不可编辑");
+                }
+
+                ObjUtils.merge(orig, record);
+                companyCollections.add(orig);
+            }
+            record.setUserId(SecurityUtils.getAuthenticatedUser().getId());
+            companyCollections.add(record);
+        });
+        return companyCollectionRepo.saveAll(companyCollections);
+    }
+
+    //oasis创建地块接口
+    @PreAuthorize("hasAnyRole('ADMIN','COMPANY')")
+    @PostMapping("/oasisSearch")
+    public List<OasisDistrictCollectionDTO> oasisSearch(@RequestBody List<Long> oasisIds) {
+        return companyCollectionService.oasisSearch(oasisIds);
+    }
+
 
     //@PreAuthorize("hasRole('ADMIN')")
     @PostMapping("/all")
@@ -76,9 +139,5 @@ public class CompanyCollectionController extends BaseController {
         companyCollectionService.audit(id, CollectionStatus.FAIL, reason);
     }
 
-//    @PostMapping("/createDistrict")
-//    public void deny(@RequestParam Long id, String reason) {
-//        companyCollectionService.audit(id, CollectionStatus.FAIL, reason);
-//    }
 }
 

+ 5 - 0
src/main/java/com/izouma/nineth/web/HmPayController.java

@@ -68,6 +68,11 @@ public class HmPayController extends BaseController {
                             new OrderNotifyEvent(id, PayMethod.SANDPAY, plat_trx_no,
                                     System.currentTimeMillis(), OrderNotifyEvent.TYPE_RECHARGE));
                     break;
+                case "auctionOrder":
+                    rocketMQTemplate.syncSend(generalProperties.getOrderNotifyTopic(),
+                            new OrderNotifyEvent(id, PayMethod.SANDPAY, plat_trx_no,
+                                    System.currentTimeMillis(), OrderNotifyEvent.TYPE_AUCTION_ORDER));
+                    break;
             }
         }
         return "SUCCESS";

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

@@ -9,7 +9,10 @@ import com.izouma.nineth.service.CacheService;
 import com.izouma.nineth.service.NewsService;
 import com.izouma.nineth.dto.PageQuery;
 import com.izouma.nineth.exception.BusinessException;
+import com.izouma.nineth.repo.NewsLikeRepo;
 import com.izouma.nineth.repo.NewsRepo;
+import com.izouma.nineth.service.CacheService;
+import com.izouma.nineth.service.NewsService;
 import com.izouma.nineth.utils.ObjUtils;
 import com.izouma.nineth.utils.SecurityUtils;
 import com.izouma.nineth.utils.excel.ExcelUtils;
@@ -42,9 +45,7 @@ public class NewsController extends BaseController {
             cacheService.clearNews(orig.getId());
             return orig;
         }
-        record = newsRepo.save(record);
-        cacheService.clearNews(record.getId());
-        return record;
+        return newsRepo.save(record);
     }
 
 
@@ -72,6 +73,7 @@ public class NewsController extends BaseController {
     @PostMapping("/del/{id}")
     public void del(@PathVariable Long id) {
         newsRepo.softDelete(id);
+        cacheService.clearNews(id);
     }
 
     @GetMapping("/excel")

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

@@ -1,4 +1,5 @@
 package com.izouma.nineth.web;
+
 import com.izouma.nineth.domain.NewsLike;
 import com.izouma.nineth.service.NewsLikeService;
 import com.izouma.nineth.dto.PageQuery;
@@ -23,7 +24,7 @@ import java.util.List;
 @AllArgsConstructor
 public class NewsLikeController extends BaseController {
     private NewsLikeService newsLikeService;
-    private NewsLikeRepo newsLikeRepo;
+    private NewsLikeRepo    newsLikeRepo;
 
     //@PreAuthorize("hasRole('ADMIN')")
     @PostMapping("/save")
@@ -85,5 +86,17 @@ public class NewsLikeController extends BaseController {
     public void unlikeRoom(@PathVariable Long id) {
         newsLikeService.unlikeRoom(SecurityUtils.getAuthenticatedUser().getId(), id);
     }
+
+    @GetMapping("/{id}/likeAuction")
+    @ApiOperation("点赞拍卖")
+    public void likeAuction(@PathVariable Long id) {
+        newsLikeService.likeAuction(SecurityUtils.getAuthenticatedUser().getId(), id);
+    }
+
+    @GetMapping("/{id}/unlikeAuction")
+    @ApiOperation("取消点赞拍卖")
+    public void unlikeAuction(@PathVariable Long id) {
+        newsLikeService.unlikeAuction(SecurityUtils.getAuthenticatedUser().getId(), id);
+    }
 }
 

+ 8 - 0
src/main/java/com/izouma/nineth/web/OrderController.java

@@ -1,5 +1,6 @@
 package com.izouma.nineth.web;
 
+import com.izouma.nineth.domain.Asset;
 import com.izouma.nineth.domain.Order;
 import com.izouma.nineth.domain.User;
 import com.izouma.nineth.dto.OrderDTO;
@@ -9,6 +10,7 @@ import com.izouma.nineth.enums.CollectionType;
 import com.izouma.nineth.enums.OrderStatus;
 import com.izouma.nineth.enums.PayMethod;
 import com.izouma.nineth.exception.BusinessException;
+import com.izouma.nineth.repo.AssetRepo;
 import com.izouma.nineth.repo.OrderRepo;
 import com.izouma.nineth.repo.UserRepo;
 import com.izouma.nineth.service.OrderService;
@@ -40,6 +42,7 @@ public class OrderController extends BaseController {
     private OrderService orderService;
     private OrderRepo    orderRepo;
     private UserRepo     userRepo;
+    private AssetRepo    assetRepo;
 
     //@PreAuthorize("hasRole('ADMIN')")
 //    @PostMapping("/save")
@@ -151,6 +154,11 @@ public class OrderController extends BaseController {
         orderRepo.findById(id).ifPresent(order -> {
             order.setOpened(true);
             orderRepo.save(order);
+            List<Asset> assets = assetRepo.findByOrderId(id);
+            assets.forEach(asset -> {
+                asset.setOpened(true);
+                assetRepo.save(asset);
+            });
         });
     }
 

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

@@ -30,7 +30,6 @@ import java.util.regex.Pattern;
 @AllArgsConstructor
 public class OrderPayController {
     private final OrderService     orderService;
-    private final AssetService     assetService;
     private final WxMpService      wxMpService;
     private final GiftOrderService giftOrderService;
     private final OrderRepo        orderRepo;
@@ -96,7 +95,8 @@ public class OrderPayController {
     public String payOrderWeixinPC(@RequestParam Long id, @RequestParam String code, Model model) throws WxPayException, EncoderException, WxErrorException {
         WxMpOAuth2AccessToken accessToken = wxMpService.oauth2getAccessToken(code);
         WxMpUser user = wxMpService.oauth2getUserInfo(accessToken, null);
-        WxPayMpOrderResult payParams = (WxPayMpOrderResult) orderService.payOrderWeixin(id, WxPayConstants.TradeType.JSAPI, user.getOpenId());
+        WxPayMpOrderResult payParams = (WxPayMpOrderResult) orderService
+                .payOrderWeixin(id, WxPayConstants.TradeType.JSAPI, user.getOpenId());
         model.addAttribute("payParams", JSON.toJSONString(payParams));
         return "PayOrderPC";
     }
@@ -162,7 +162,8 @@ public class OrderPayController {
     public String payGiftOrderWeixinPC(@RequestParam Long id, @RequestParam String code, Model model) throws WxPayException, EncoderException, WxErrorException {
         WxMpOAuth2AccessToken accessToken = wxMpService.oauth2getAccessToken(code);
         WxMpUser user = wxMpService.oauth2getUserInfo(accessToken, null);
-        WxPayMpOrderResult payParams = (WxPayMpOrderResult) giftOrderService.payOrderWeixin(id, WxPayConstants.TradeType.JSAPI, user.getOpenId());
+        WxPayMpOrderResult payParams = (WxPayMpOrderResult) giftOrderService
+                .payOrderWeixin(id, WxPayConstants.TradeType.JSAPI, user.getOpenId());
         model.addAttribute("payParams", JSON.toJSONString(payParams));
         return "PayOrderPC";
     }
@@ -213,7 +214,8 @@ public class OrderPayController {
     public String payMintOrderWeixinPC(@RequestParam Long id, @RequestParam String code, Model model) throws WxPayException, EncoderException, WxErrorException {
         WxMpOAuth2AccessToken accessToken = wxMpService.oauth2getAccessToken(code);
         WxMpUser user = wxMpService.oauth2getUserInfo(accessToken, null);
-        WxPayMpOrderResult payParams = (WxPayMpOrderResult) mintOrderService.payOrderWeixin(id, WxPayConstants.TradeType.JSAPI, user.getOpenId());
+        WxPayMpOrderResult payParams = (WxPayMpOrderResult) mintOrderService
+                .payOrderWeixin(id, WxPayConstants.TradeType.JSAPI, user.getOpenId());
         model.addAttribute("payParams", JSON.toJSONString(payParams));
         return "PayOrderPC";
     }

+ 38 - 13
src/main/java/com/izouma/nineth/web/OrderPayControllerV2.java

@@ -1,31 +1,24 @@
 package com.izouma.nineth.web;
 
-import com.alibaba.fastjson.JSON;
-import com.github.binarywang.wxpay.bean.order.WxPayMpOrderResult;
-import com.github.binarywang.wxpay.constant.WxPayConstants;
-import com.github.binarywang.wxpay.exception.WxPayException;
-import com.huifu.adapay.core.exception.BaseAdaPayException;
 import com.izouma.nineth.domain.Order;
 import com.izouma.nineth.enums.OrderStatus;
 import com.izouma.nineth.exception.BusinessException;
 import com.izouma.nineth.repo.OrderRepo;
-import com.izouma.nineth.service.*;
+import com.izouma.nineth.service.OrderPayService;
+import com.izouma.nineth.service.SandPayService;
 import com.izouma.nineth.utils.SecurityUtils;
 import io.swagger.annotations.ApiOperation;
 import lombok.AllArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
-import me.chanjar.weixin.common.error.WxErrorException;
-import me.chanjar.weixin.mp.api.WxMpService;
-import me.chanjar.weixin.mp.bean.result.WxMpOAuth2AccessToken;
-import me.chanjar.weixin.mp.bean.result.WxMpUser;
-import org.apache.commons.codec.EncoderException;
 import org.springframework.stereotype.Controller;
 import org.springframework.ui.Model;
-import org.springframework.web.bind.annotation.*;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.ResponseBody;
 
 import java.math.BigDecimal;
 import java.util.Map;
-import java.util.regex.Pattern;
 
 @Controller
 @RequestMapping({"/payOrder/v2", "/pay/v2"})
@@ -164,4 +157,36 @@ public class OrderPayControllerV2 {
     public String payRechargeQuick(@RequestParam Long userId, @RequestParam BigDecimal amount) {
         return orderPayService.rechargeQuick(userId, amount);
     }
+
+    @RequestMapping(value = "/auction/alipay", method = RequestMethod.GET)
+    @ResponseBody
+    public String payAuctionOrderAlipayH5(Long id) {
+        return orderPayService.payAuctionOrder(id);
+    }
+
+    @RequestMapping(value = "/auction/alipay_wx", method = RequestMethod.GET)
+    public String payAuctionOrderAlipayWx(Long id, Model model) {
+        String payUrl = orderPayService.payAuctionOrder(id);
+        model.addAttribute("payUrl", payUrl);
+        model.addAttribute("orderId", id);
+        return "AlipayHtml";
+    }
+
+    @RequestMapping(value = "/auction/sandQuick", method = RequestMethod.GET, produces = "text/html")
+    @ResponseBody
+    public String payAuctionQuick(@RequestParam Long id) {
+        return orderPayService.payAuctionQuick(id);
+    }
+
+    @RequestMapping(value = "/auction/balance")
+    @ResponseBody
+    public void payAuctionOrderBalance(@RequestParam Long id, @RequestParam String tradeCode) {
+        orderPayService.payAuctionOrderBalance(id, SecurityUtils.getAuthenticatedUser().getId(), tradeCode);
+    }
+
+    @RequestMapping(value = "/auction/agreement")
+    @ResponseBody
+    public Map<String, Object> payAuctionAgreement(@RequestParam Long id, String bindCardId) {
+        return orderPayService.payAuctionOrderAgreement(id, bindCardId);
+    }
 }

+ 10 - 0
src/main/java/com/izouma/nineth/web/PayEaseController.java

@@ -5,6 +5,11 @@ import com.alibaba.fastjson15.JSONObject;
 import com.izouma.nineth.config.GeneralProperties;
 import com.izouma.nineth.enums.PayMethod;
 import com.izouma.nineth.event.OrderNotifyEvent;
+import com.izouma.nineth.service.AuctionOrderService;
+import com.izouma.nineth.service.AuctionOrderService;
+import com.izouma.nineth.service.GiftOrderService;
+import com.izouma.nineth.service.MintOrderService;
+import com.izouma.nineth.service.UserBalanceService;
 import com.upay.sdk.CipherWrapper;
 import com.upay.sdk.onlinepay.executer.OnlinePayOrderExecuter;
 import lombok.AllArgsConstructor;
@@ -53,6 +58,11 @@ public class PayEaseController {
                             new OrderNotifyEvent(id, PayMethod.SANDPAY, serialNumber,
                                     System.currentTimeMillis(), OrderNotifyEvent.TYPE_RECHARGE));
                     break;
+                case "auctionOrder":
+                    rocketMQTemplate.syncSend(generalProperties.getOrderNotifyTopic(),
+                            new OrderNotifyEvent(id, PayMethod.SANDPAY, serialNumber,
+                                    System.currentTimeMillis(), OrderNotifyEvent.TYPE_AUCTION_ORDER));
+                    break;
             }
         }
         return "SUCCESS";

+ 5 - 0
src/main/java/com/izouma/nineth/web/SandPayController.java

@@ -75,6 +75,11 @@ public class SandPayController {
                                         new OrderNotifyEvent(id, PayMethod.SANDPAY, payOrderCode,
                                                 System.currentTimeMillis(), OrderNotifyEvent.TYPE_RECHARGE));
                                 break;
+                            case "auctionOrder":
+                                rocketMQTemplate.syncSend(generalProperties.getOrderNotifyTopic(),
+                                        new OrderNotifyEvent(id, PayMethod.SANDPAY, payOrderCode,
+                                                System.currentTimeMillis(), OrderNotifyEvent.TYPE_AUCTION_ORDER));
+                                break;
                         }
                     }
                     return "respCode=000000";

+ 5 - 5
src/main/java/com/izouma/nineth/web/SmsController.java

@@ -22,11 +22,11 @@ public class SmsController {
 
     @GetMapping("/sendVerify")
     public String sendVerify(@RequestParam String phone) {
-        throw new BusinessException("此接口已停用,请重启APP或刷新网页");
-//        if (!Pattern.matches(Constants.Regex.PHONE, phone)) {
-//            throw new BusinessException("请输入正确的手机号");
-//        }
-//        return smsService.sendVerify(phone);
+//        throw new BusinessException("此接口已停用,请重启APP或刷新网页");
+        if (!Pattern.matches(Constants.Regex.PHONE, phone)) {
+            throw new BusinessException("请输入正确的手机号");
+        }
+        return smsService.sendVerify(phone);
     }
 
     @GetMapping("/sendSecureVerify")

+ 34 - 0
src/main/java/com/izouma/nineth/web/UserBalanceController.java

@@ -1,9 +1,14 @@
 package com.izouma.nineth.web;
 
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import com.github.kevinsawicki.http.HttpRequest;
 import com.izouma.nineth.domain.BalanceRecord;
 import com.izouma.nineth.domain.ExportWithdraw;
 import com.izouma.nineth.domain.UserBalance;
 import com.izouma.nineth.dto.PageQuery;
+import com.izouma.nineth.enums.BalanceType;
+import com.izouma.nineth.enums.PayMethod;
 import com.izouma.nineth.exception.BusinessException;
 import com.izouma.nineth.repo.AutoWithdrawRecordRepo;
 import com.izouma.nineth.repo.BalanceRecordRepo;
@@ -14,6 +19,7 @@ import com.izouma.nineth.utils.DateTimeUtils;
 import com.izouma.nineth.utils.JpaUtils;
 import com.izouma.nineth.utils.SecurityUtils;
 import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.io.IOUtils;
 import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
 import org.springframework.core.io.InputStreamResource;
@@ -29,6 +35,7 @@ import org.springframework.web.multipart.MultipartFile;
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.IOException;
+import java.math.BigDecimal;
 import java.time.Duration;
 import java.time.LocalDate;
 import java.util.concurrent.ExecutionException;
@@ -36,6 +43,7 @@ import java.util.concurrent.ExecutionException;
 @RestController
 @RequestMapping("/userBalance")
 @AllArgsConstructor
+@Slf4j
 public class UserBalanceController extends BaseController {
 
     private final UserBalanceRepo               userBalanceRepo;
@@ -108,4 +116,30 @@ public class UserBalanceController extends BaseController {
 //    public void withdraw() {
 //        userBalanceService.withdraw(SecurityUtils.getAuthenticatedUser().getId());
 //    }
+
+    @PostMapping(value = "/iap")
+    public String iap(@RequestParam String receiptData) {
+        String data = "{\"receipt-data\":\"" + receiptData + "\"}";
+        String body = HttpRequest.post("https://buy.itunes.apple.com/verifyReceipt")
+                .contentType("application/json")
+                .send(data)
+                .body();
+        JSONObject jsonObject = JSON.parseObject(body);
+        int status = jsonObject.getInteger("status");
+        if (status == 21007) {
+            jsonObject = JSON.parseObject(HttpRequest.post("https://sandbox.itunes.apple.com/verifyReceipt")
+                    .contentType("application/json")
+                    .send(data)
+                    .body());
+            status = jsonObject.getInteger("status");
+        }
+        log.info("verifyReceipt {}", JSON.toJSONString(jsonObject, true));
+        if (status == 0) {
+            JSONObject inApp = jsonObject.getJSONObject("receipt").getJSONArray("in_app").getJSONObject(0);
+            BigDecimal amount = inApp.getBigDecimal("product_id");
+            userBalanceService.modifyBalance(SecurityUtils.getAuthenticatedUser().getId(), amount, BalanceType.RECHARGE,
+                    null, false, null);
+        }
+        return "ok";
+    }
 }

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

@@ -297,8 +297,8 @@ public class UserController extends BaseController {
 
     @GetMapping("/collectionInvite")
     public List<User> collectionInvite(@RequestParam Long collectionId) {
-        return userRepo.findAllByCollectionIdAndCollectionInvitor(collectionId, SecurityUtils.getAuthenticatedUser()
-                .getId());
+        return userRepo.findAllByCollectionIdAndCollectionInvitorAndSettleAccountIdIsNotNull(collectionId,
+                SecurityUtils.getAuthenticatedUser().getId());
     }
 
     @PreAuthorize("hasAnyRole('ADMIN')")

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

@@ -1,25 +1,21 @@
 package com.izouma.nineth.web;
 
 import com.izouma.nineth.domain.WithdrawApply;
-import com.izouma.nineth.repo.UserBalanceRepo;
 import com.izouma.nineth.service.WithdrawApplyService;
 import com.izouma.nineth.dto.PageQuery;
 import com.izouma.nineth.exception.BusinessException;
 import com.izouma.nineth.repo.WithdrawApplyRepo;
-import com.izouma.nineth.utils.ObjUtils;
 import com.izouma.nineth.utils.SecurityUtils;
 import com.izouma.nineth.utils.excel.ExcelUtils;
 import lombok.AllArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.data.domain.Page;
-import org.springframework.scheduling.annotation.Scheduled;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.web.bind.annotation.*;
 
 import javax.servlet.http.HttpServletResponse;
 import java.io.IOException;
 import java.math.BigDecimal;
-import java.time.LocalDateTime;
 import java.util.List;
 import java.util.concurrent.ExecutionException;
 
@@ -64,7 +60,7 @@ public class WithdrawApplyController extends BaseController {
     @PreAuthorize("hasRole('ADMIN')")
     @PostMapping("/approveAll")
     public void approveAll() throws ExecutionException, InterruptedException {
-        withdrawApplyService.approveAll();
+        withdrawApplyService.approveAllAsync();
     }
 
     @PreAuthorize("hasRole('ADMIN')")

+ 11 - 11
src/main/resources/application.yaml

@@ -155,7 +155,7 @@ aliyun:
 general:
   host: https://test.raex.vip
   contract-name: raex_new
-  name: RAEX宇宙
+  name: OASISMETA
   org: 华储艺术品中心(深圳)有限公司
   short-name: 华储
   create-order-group: create-order-group-dev
@@ -514,7 +514,7 @@ spring:
     database: 0
     password: tetQsjw!u4!c5$URduo7BH
 general:
-  host: https://nfttest.raex.vip
+  host: https://oasis.raex.vip
   create-order-group: create-order-group-staging
   create-order-topic: create-order-topic-staging
   update-stock-group: update-stock-group-staging
@@ -534,21 +534,21 @@ general:
   broadcast-event-topic: broadcast-event-topic-staging
 wx:
   pay:
-    notify-url: https://nfttest.raex.vip/notify/order/weixin
-    refund-notify-url: https://nfttest.raex.vip/wx/refundNotify
-    return-url: https://nfttest.raex.vip/9th/orders
+    notify-url: https://oasis.raex.vip/notify/order/weixin
+    refund-notify-url: https://oasis.raex.vip/wx/refundNotify
+    return-url: https://oasis.raex.vip/9th/orders
 alipay:
-  notify-url: https://nfttest.raex.vip/notify/order/alipay
-  return-url: https://nfttest.raex.vip/9th/home
+  notify-url: https://oasis.raex.vip/notify/order/alipay
+  return-url: https://oasis.raex.vip/9th/home
 adapay:
-  notify-url: https://nfttest.raex.vip/notify/adapay
+  notify-url: https://oasis.raex.vip/notify/adapay
 rocketmq:
   name-server: 172.29.50.102:9876
   producer:
     group: my-producer
 sandpay:
-  notify-url: https://nfttest.raex.vip/sandpay/notify
+  notify-url: https://oasis.raex.vip/sandpay/notify
 hmpay:
-  notify-url: https://nfttest.raex.vip/hmpay/notify
+  notify-url: https://oasis.raex.vip/hmpay/notify
 payease:
-  notify-url: https://nfttest.raex.vip/payease/notify
+  notify-url: https://oasis.raex.vip/payease/notify

Dosya farkı çok büyük olduğundan ihmal edildi
+ 0 - 0
src/main/resources/genjson/AuctionOrder.json


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

@@ -708,6 +708,75 @@ const router = new Router({
                         title: 'captcha'
                     }
                 },
+                {
+                    path: '/auctionOrderEdit',
+                    name: 'AuctionOrderEdit',
+                    component: () => import(/* webpackChunkName: "auctionOrderEdit" */ '@/views/AuctionOrderEdit.vue'),
+                    meta: {
+                        title: '拍卖订单编辑'
+                    }
+                },
+                {
+                    path: '/auctionOrderList',
+                    name: 'AuctionOrderList',
+                    component: () => import(/* webpackChunkName: "auctionOrderList" */ '@/views/AuctionOrderList.vue'),
+                    meta: {
+                        title: '拍卖订单'
+                    }
+                },
+                {
+                    path: '/auctionOrderUsedList',
+                    name: 'AuctionOrderUsedList',
+                    component: () => import(/* webpackChunkName: "auctionOrderList" */ '@/views/AuctionOrderUsedList.vue'),
+                    meta: {
+                        title: '拍卖订单'
+                    }
+                },
+                {
+                    path: '/auctionActivityEdit',
+                    name: 'AuctionActivityEdit',
+                    component: () =>
+                        import(/* webpackChunkName: "auctionActivityEdit" */ '@/views/AuctionActivityEdit.vue'),
+                    meta: {
+                        title: '拍卖编辑'
+                    }
+                },
+                {
+                    path: '/auctionActivityList',
+                    name: 'AuctionActivityList',
+                    component: () =>
+                        import(/* webpackChunkName: "auctionActivityList" */ '@/views/AuctionActivityList.vue'),
+                    meta: {
+                        title: '拍卖'
+                    }
+                },
+                {
+                    path: '/auctionUsedList',
+                    name: 'AuctionUsedList',
+                    component: () =>
+                        import(/* webpackChunkName: "auctionUsedList" */ '@/views/AuctionUsedList.vue'),
+                    meta: {
+                        title: '拍卖'
+                    }
+                },
+                {
+                    path: '/auctionRecordEdit',
+                    name: 'AuctionRecordEdit',
+                    component: () =>
+                        import(/* webpackChunkName: "auctionRecordEdit" */ '@/views/AuctionRecordEdit.vue'),
+                    meta: {
+                        title: '拍卖纪录编辑'
+                    }
+                },
+                {
+                    path: '/auctionRecordList',
+                    name: 'AuctionRecordList',
+                    component: () =>
+                        import(/* webpackChunkName: "auctionRecordList" */ '@/views/AuctionRecordList.vue'),
+                    meta: {
+                        title: '拍卖纪录'
+                    }
+                },
                 {
                     path: '/tagEdit',
                     name: 'TagEdit',

+ 3 - 0
src/main/vue/src/views/AppVersionEdit.vue

@@ -31,6 +31,9 @@
                     <el-form-item prop="review" label="review">
                         <el-switch v-model="formData.review"></el-switch>
                     </el-form-item>
+                    <el-form-item prop="channel" label="channel">
+                        <el-input v-model="formData.channel"></el-input>
+                    </el-form-item>
                     <el-form-item prop="downloadUrl" label="downloadUrl">
                         <el-input v-model="formData.downloadUrl"></el-input>
                     </el-form-item>

Bu fark içinde çok fazla dosya değişikliği olduğu için bazı dosyalar gösterilmiyor