Browse Source

兑换码兑换车票

zoujiajian 1 năm trước cách đây
mục cha
commit
f20242d61f
19 tập tin đã thay đổi với 1220 bổ sung0 xóa
  1. 7 0
      wholesale/pom.xml
  2. 13 0
      wholesale/src/main/java/com/yhlxj/dao/mapper/AccountMapper.java
  3. 19 0
      wholesale/src/main/java/com/yhlxj/dao/mapper/GroupsMapper.java
  4. 14 0
      wholesale/src/main/java/com/yhlxj/dao/mapper/GroupsRelationMapper.java
  5. 137 0
      wholesale/src/main/java/com/yhlxj/dao/model/entity/Account.java
  6. 164 0
      wholesale/src/main/java/com/yhlxj/dao/model/entity/GroupsRelation.java
  7. 198 0
      wholesale/src/main/java/com/yhlxj/dao/model/entity/GroupsTrips.java
  8. 21 0
      wholesale/src/main/java/com/yhlxj/dao/model/request/ExchangeCodeTicket.java
  9. 197 0
      wholesale/src/main/java/com/yhlxj/dao/model/view/AccountView.java
  10. 47 0
      wholesale/src/main/java/com/yhlxj/dao/model/view/WebWholesaleOrderDonCodeDetailView.java
  11. 13 0
      wholesale/src/main/java/com/yhlxj/service/code/ExchangeCodeService.java
  12. 80 0
      wholesale/src/main/java/com/yhlxj/service/code/impl/ExchangeCodeServiceImpl.java
  13. 19 0
      wholesale/src/main/java/com/yhlxj/service/groups/GroupsFuncService.java
  14. 144 0
      wholesale/src/main/java/com/yhlxj/service/groups/impl/GroupsFuncServiceImpl.java
  15. 12 0
      wholesale/src/main/java/com/yhlxj/service/relation/GroupRelationFrontService.java
  16. 93 0
      wholesale/src/main/java/com/yhlxj/service/relation/impl/GroupRelationFrontServiceImpl.java
  17. 15 0
      wholesale/src/main/java/com/yhlxj/web/controller/code/exchange/ExchangeCodeController.java
  18. 13 0
      wholesale/src/main/resources/mapper/GroupsMapper.xml
  19. 14 0
      wholesale/src/main/resources/mapper/GroupsRelationMapper.xml

+ 7 - 0
wholesale/pom.xml

@@ -178,6 +178,13 @@
             <artifactId>alipay-sdk-java</artifactId>
             <version>4.35.65.ALL</version>
         </dependency>
+
+        <!--guava-重试-->
+        <dependency>
+            <groupId>com.github.rholder</groupId>
+            <artifactId>guava-retrying</artifactId>
+            <version>2.0.0</version>
+        </dependency>
     </dependencies>
 
 

+ 13 - 0
wholesale/src/main/java/com/yhlxj/dao/mapper/AccountMapper.java

@@ -0,0 +1,13 @@
+package com.yhlxj.dao.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.yhlxj.dao.model.entity.Account;
+
+/**
+ * 项目名: yhlxj2
+ * 文件名: AccountMapper
+ * 创建者: JavaZou
+ * 创建时间:2025/6/5 18:08
+ */
+public interface AccountMapper extends BaseMapper<Account> {
+}

+ 19 - 0
wholesale/src/main/java/com/yhlxj/dao/mapper/GroupsMapper.java

@@ -0,0 +1,19 @@
+package com.yhlxj.dao.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.yhlxj.dao.model.entity.GroupsTrips;
+import org.apache.ibatis.annotations.Update;
+
+/**
+ * 项目名: yhlxj2
+ * 文件名: GroupsMapper
+ * 创建者: JavaZou
+ * 创建时间:2025/6/5 17:59
+ */
+public interface GroupsMapper extends BaseMapper<GroupsTrips> {
+
+	GroupsTrips selectCollegeStudentUserGptTicket(Long skuId);
+
+	@Update("update groups_trips set available_num = available_num - 1 where id = #{groupId} and available_num > 0")
+	int decrAvailableNum(Long groupId);
+}

+ 14 - 0
wholesale/src/main/java/com/yhlxj/dao/mapper/GroupsRelationMapper.java

@@ -0,0 +1,14 @@
+package com.yhlxj.dao.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.yhlxj.dao.model.entity.GroupsRelation;
+
+/**
+ * 项目名: yhlxj2
+ * 文件名: GroupsRelationMapper
+ * 创建者: JavaZou
+ * 创建时间:2025/6/5 17:58
+ */
+public interface GroupsRelationMapper extends BaseMapper<GroupsRelation> {
+	GroupsRelation selectRandomOneRelationByGroupsId(Long groupsId);
+}

+ 137 - 0
wholesale/src/main/java/com/yhlxj/dao/model/entity/Account.java

@@ -0,0 +1,137 @@
+package com.yhlxj.dao.model.entity;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.yhlxj.dao.model.BaseEntity;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.math.BigDecimal;
+import java.util.Date;
+
+/**
+ * @author chan
+ * @date 2022/9/27 6:17 PM
+ */
+@Getter
+@Setter
+public class Account extends BaseEntity {
+
+    private String title;
+
+    private String account;
+
+    private String password;
+
+    private Boolean isMonth;
+
+    private Long goodsId;
+
+    private String bankCard;
+
+    @TableField(exist = false)
+    private Long skuId;
+
+    private Date startTime;
+
+    private Date expiryTime;
+
+    private BigDecimal amount;
+
+    /**
+     * 国区id
+     */
+    private String cnAccount;
+
+    /**
+     * 美区id
+     */
+    private String usAccount;
+
+    /**
+     * 客服id
+     */
+    private Long customerServiceId;
+
+    /**
+     * chatGpt apiKey
+     */
+    private String apiKey;
+
+    /**
+     * chatGpt 邮箱密码
+     */
+    private String gptEmailPwd;
+
+    /**
+     * 辅助邮箱
+     */
+    private String email;
+
+    private String remark;
+
+    /**
+     * midJourney 登录安全码
+     */
+    private String verifyCodes;
+
+    /**
+     * 密保
+     */
+    private String secret;
+
+    /**
+     * gpt API 密钥
+     */
+    private String apiSecret;
+
+    /**
+     * 账号是否被弃用
+     */
+    private Boolean isAbandon;
+
+    /**
+     * gpt accesToken
+     */
+    private String gptRefreshToken;
+
+    /**
+     * 备用账号类型sku_ids
+     */
+    private String preSkuIds;
+
+    /**
+     * 类型 1通用 2备用 3临时账号
+     */
+    private Integer type;
+
+    /**
+     * 账号是否禁用
+     */
+    private Boolean isDisable;
+
+    /**
+     * cookie nf
+     */
+    private String cookie;
+
+    /**
+     * 关联邮箱 收取邮件
+     */
+    private String relateEmail;
+
+    /**
+     * 同户验证链接
+     */
+    private String verifyLink;
+
+    /**
+     * 是否外部采购
+     */
+    private Boolean outsidePurchase;
+
+    /**
+     * 激活码
+     */
+    private String actCode;
+
+}

+ 164 - 0
wholesale/src/main/java/com/yhlxj/dao/model/entity/GroupsRelation.java

@@ -0,0 +1,164 @@
+package com.yhlxj.dao.model.entity;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.ejlchina.searcher.bean.DbIgnore;
+import com.yhlxj.dao.model.BaseEntity;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.Date;
+
+/**
+ * @author chan
+ * @date 2022/9/26 6:31 PM
+ */
+@Getter
+@Setter
+public class GroupsRelation extends BaseEntity {
+
+    private Long groupsId;
+
+    private Long userId;
+
+    private Date startTime;
+
+    private Date expiryTime;
+
+    private Integer num;
+
+    /**
+     * locking 锁定中
+     * overdue 过期
+     * validity 有效
+     * none 无人
+     */
+    private Status status;
+
+    /**
+     * 账号
+     */
+    private String account;
+
+    /**
+     * 密码
+     */
+    private String password;
+
+    private Date submitTime;
+
+    private Date sendTime;
+
+    private String operator;
+
+    private RechargeStatus rechargeStatus;
+
+    /**
+     * 邀请制家庭组链接
+     */
+    private String inviteLink;
+
+    /**
+     * 联系方式
+     */
+    private String contact;
+
+    /**
+     * 续费意愿处理状态
+     */
+    private Boolean renewStatus;
+
+    /**
+     * 处理状态
+     */
+    private Boolean isHandle;
+
+    /**
+     * 客服
+     */
+    private String customerService;
+
+    /**
+     * midJourney 登录安全码
+     */
+    private String verifyCode;
+
+    private Long yhsId;
+
+    /**
+     * 店铺类型
+     * 0无 1.普通店铺 2.镜像店铺
+     */
+    private Integer cmt;
+
+    /**
+     * 获取权益时的订单id
+     */
+    @TableField(exist = false)
+    @DbIgnore
+    private Long orderId;
+
+    /**
+     * 更换车票时,新车票id
+     */
+    @TableField(exist = false)
+    @DbIgnore
+    private Long newRelationId;
+
+
+    /**
+     * 车队目前可用停车数
+     */
+    @TableField(exist = false)
+    @DbIgnore
+    private Integer groupsAvailParkingNum;
+
+    /**
+     * 车队最多可用车位数
+     */
+    @TableField(exist = false)
+    @DbIgnore
+    private Integer maxNum;
+
+    /**
+     * 车票获取类型 默认1购买,2.体验,3.镜像裂变,4.个人网站批发
+     */
+    private Integer aqType;
+
+    /**
+     * 奈飞pinCode
+     */
+    private String pinCode;
+
+    /**
+     * 是否是VIP
+     */
+    private Boolean isVip;
+
+
+    @AllArgsConstructor
+    @Getter
+    public enum Status{
+        locking("锁定中"),
+        overdue("过期"),
+        validity("有效"),
+        none("无人"),
+        outside("额外")
+        ;
+
+        private String desc;
+
+    }
+
+    @AllArgsConstructor
+    @Getter
+    public enum RechargeStatus{
+        waiting("待充值"),
+        complete("已完成"),
+        error("账号错误"),
+        ;
+
+        private String desc;
+
+    }
+}

+ 198 - 0
wholesale/src/main/java/com/yhlxj/dao/model/entity/GroupsTrips.java

@@ -0,0 +1,198 @@
+package com.yhlxj.dao.model.entity;
+
+import com.baomidou.mybatisplus.annotation.FieldFill;
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.ejlchina.searcher.bean.DbField;
+import com.ejlchina.searcher.bean.DbIgnore;
+import com.ejlchina.searcher.bean.SearchBean;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.Date;
+
+/**
+ * @author chan
+ * @date 2022/9/26 6:31 PM
+ */
+@Getter
+@Setter
+@SearchBean(tables = "groups_trips gt left join goods_don_sku sku on gt.sku_id = sku.id " +
+        "left join goods_don g on g.id = sku.goods_id " +
+        "left join account a on a.id = gt.account_id ")
+public class GroupsTrips {
+
+    @TableId(value = "id",type = IdType.AUTO)
+    @DbField("gt.id")
+    private Long id;
+
+    @DbField("gt.id")
+    @TableField(exist = false)
+    private Long groupId;
+
+    /**
+     * 商品skuId
+     */
+    @DbField("gt.sku_id")
+    private Long skuId;
+
+    /**
+     * 账号id
+     */
+    @DbField("gt.account_id")
+    private Long accountId;
+
+
+    /**
+     * 账号
+     */
+    @DbField("a.account")
+    @TableField(exist = false)
+    private String account;
+
+    /**
+     * 密码
+     */
+    @DbField("a.password")
+    @TableField(exist = false)
+    private String password;
+
+    /**
+     * 商品id
+     */
+    @DbField("g.id")
+    @TableField(exist = false)
+    private Long goodsId;
+
+    /**
+     * 标题
+     */
+    @DbField("g.title")
+    @TableField(exist = false)
+    private String title;
+
+    /**
+     * 是否是第三方平台
+     */
+    @DbField("g.is_third_goods")
+    @TableField(exist = false)
+    private Boolean isThirdGoods;
+
+    /**
+     * 商品规格
+     */
+    @DbField("sku.spec_val")
+    @TableField(exist = false)
+    private String specVal;
+
+    /**
+     * 商品规格
+     */
+    @DbField("sku.is_mirror")
+    @TableField(exist = false)
+    private Boolean isMirror;
+
+    /**
+     * 录入人
+     */
+    @DbField("gt.writer")
+    private Long writer;
+
+    /**
+     * 车位数量
+     */
+    @DbField("gt.num")
+    private Integer num;
+
+    /**
+     * 可用车位数
+     */
+    @DbField("gt.available_num")
+    private Integer availableNum;
+
+    /**
+     * 状态
+     */
+    @DbField("gt.status")
+    private Status status;
+
+    /**
+     * 备注
+     */
+    @DbField("gt.remark")
+    private String remark;
+
+    /**
+     * 开时间
+     */
+    @DbField("gt.start_time")
+    private Date startTime;
+
+    @DbIgnore
+    @TableField(exist = false)
+    private String verifyCodes;
+
+    @DbField("gt.renewal_time")
+    private Date renewalTime;
+
+    @DbField("a.expiry_time")
+    @TableField(exist = false)
+    private Date expiryTime;
+
+    @DbField("a.is_disable")
+    @TableField(exist = false)
+    private Boolean isDisable;
+
+    @DbField("a.act_code")
+    @TableField(exist = false)
+    private String actCode;
+
+    /**
+     * 车队上是否有人
+     */
+    @DbIgnore
+    @TableField(exist = false)
+    private Boolean isExists;
+
+    /**
+     * 可上车队时间
+     */
+    @DbField("gt.parking_time")
+    private Date parkingTime;
+
+    /**
+     * 目前可停车数目
+     */
+    @DbField("gt.available_parking_num")
+    private Integer availableParkingNum;
+
+    /**
+     * 创建时间
+     */
+
+    @DbField("gt.created_time")
+    @TableField(fill = FieldFill.INSERT)
+    private Date createdTime;
+
+    /**
+     * 修改时间
+     */
+    @DbField("gt.update_time")
+    @TableField(fill = FieldFill.INSERT_UPDATE)
+    private Date updateTime;
+
+
+    @AllArgsConstructor
+    @Getter
+    public enum Status{
+        waiting("等待发车"),
+        validity("已发车"),
+        down("下架"),
+        close("关闭");
+
+        private String desc;
+
+    }
+}

+ 21 - 0
wholesale/src/main/java/com/yhlxj/dao/model/request/ExchangeCodeTicket.java

@@ -0,0 +1,21 @@
+package com.yhlxj.dao.model.request;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/*
+ *项目名: netflix
+ *文件名: ExchangeCodeTicket
+ *创建者: JavaZou
+ *创建时间:2022/11/8 13:43
+ */
+@Getter
+@Setter
+public class ExchangeCodeTicket {
+	/**
+	 * 兑换码
+	 */
+	private String code;
+
+	private Long userId;
+}

+ 197 - 0
wholesale/src/main/java/com/yhlxj/dao/model/view/AccountView.java

@@ -0,0 +1,197 @@
+package com.yhlxj.dao.model.view;
+
+import com.ejlchina.searcher.bean.DbField;
+import com.ejlchina.searcher.bean.DbIgnore;
+import com.ejlchina.searcher.bean.SearchBean;
+import com.yhlxj.dao.model.entity.GroupsTrips;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.math.BigDecimal;
+import java.util.Date;
+
+/**
+ * @author chan
+ * @date 2022/10/12 12:02 PM
+ */
+@Getter
+@Setter
+@SearchBean(tables = "account a left join goods_don g on a.goods_id = g.id " +
+        "left join groups_trips gt on gt.account_id = a.id " +
+        "left join goods_don_sku gdk on gdk.id = gt.sku_id",
+        where = ":extra_sql:")
+public class AccountView {
+
+    @DbField("a.id")
+    private Long id;
+
+    @DbField("g.id")
+    private Long goodsId;
+
+    @DbField("g.title")
+    private String title;
+
+    @DbField("g.second_type")
+    private Integer goodsSecondType;
+
+    /**
+     * 是否是第三方平台
+     */
+    @DbField("g.is_third_goods")
+    private Boolean isThirdGoods;
+
+    @DbField("a.bank_card")
+    private String bankCard;
+
+    @DbField("a.account")
+    private String account;
+
+    @DbField("a.gpt_email_pwd")
+    private String emailPassword;
+
+    @DbField("a.password")
+    private String password;
+
+    @DbField("a.is_month")
+    private Boolean isMonth;
+
+    @DbField("a.api_key")
+    private String apiKey;
+
+    @DbField("a.gpt_email_pwd")
+    private String gptEmailPwd;
+
+    @DbField("a.verify_codes")
+    private String verifyCodes;
+
+    @DbField("a.api_secret")
+    private String apiSecret;
+
+    @DbField("a.start_time")
+    private Date startTime;
+
+    @DbField("a.expiry_time")
+    private Date expiryTime;
+
+    @DbField("a.amount")
+    private BigDecimal amount;
+
+    /**
+     * 国区id
+     */
+    @DbField("a.cn_account")
+    private String cnAccount;
+
+    /**
+     * 美区id
+     */
+    @DbField("a.us_account")
+    private String usAccount;
+
+    @DbField("a.customer_service_id")
+    private Long customerServiceId;
+
+    @DbField("a.secret")
+    private String secret;
+
+    @DbIgnore
+    private String customerServiceName;
+
+    @DbIgnore
+    private Integer invited;
+
+    @DbIgnore
+    private Integer unInvited;
+
+    @DbIgnore
+    private Integer total;
+
+    @DbField("gt.id")
+    private Long groupsId;
+
+    @DbField("gt.status")
+    private GroupsTrips.Status gtStatus;
+
+    /**
+     * 账号备注
+     */
+    @DbField("a.remark")
+    private String remark;
+
+    @DbField("a.email")
+    private String email;
+
+    @DbField("gdk.id")
+    private Long skuId;
+
+    @DbField("gdk.is_mirror")
+    private Boolean isMirror;
+
+    @DbField("a.gpt_refresh_token")
+    private String gptRefreshToken;
+
+    /**
+     * 规格
+     */
+    @DbField("gdk.spec_val")
+    private String specVal;
+
+    @DbField("a.created_time")
+    private Date createdTime;
+
+    //@DbField("select count(ur.id) from user_ticket_cleared_record ur where ur.account_id = a.id and deleted is true and source = 'self' :yesTime:")
+    @DbIgnore
+    private Integer expiryCount;
+
+    //@DbField("if((select count(distinct relation_id) from user_ticket_cleared_record ur where ur.account_id = a.id and deleted is true and source = 'self' :yesTime:)>=5,true,false)")
+    @DbIgnore
+    private Boolean expiredAll;
+
+    /**
+     * 今日有过期人员
+     */
+    @DbIgnore
+    private Boolean hadExpiredToDay;
+
+    @DbIgnore
+    private Integer updatePwdNum;
+
+    @DbIgnore
+    private Date lastUpdatePwdDate;
+
+    @DbField("a.pre_sku_ids")
+    private String preSkuIds;
+
+    @DbField("a.type")
+    private Integer accountType;
+
+    @DbIgnore
+    private Boolean isMjMirror;
+
+    @DbField("a.is_disable")
+    private Boolean isDisable;
+
+    @DbField("a.cookie")
+    private String cookie;
+
+    @DbField("a.relate_email")
+    private String relateEmail;
+
+    @DbField("a.type")
+    private Integer type;
+
+    @DbField("a.verify_link")
+    private String verifyLink;
+
+    /**
+     * 是否外部采购
+     */
+    @DbField("a.outside_purchase")
+    private Boolean outsidePurchase;
+
+    /**
+     * 激活码
+     */
+    @DbField("a.act_code")
+    private String actCode;
+}

+ 47 - 0
wholesale/src/main/java/com/yhlxj/dao/model/view/WebWholesaleOrderDonCodeDetailView.java

@@ -0,0 +1,47 @@
+package com.yhlxj.dao.model.view;
+
+import com.ejlchina.searcher.bean.DbField;
+import com.ejlchina.searcher.bean.SearchBean;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.yhlxj.dao.model.entity.WebWholesaleOrderDon;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.Date;
+
+/**
+ * 项目名: yhlxj2
+ * 文件名: WebWholesaleOrderDonCodeDetailView
+ * 创建者: JavaZou
+ * 创建时间:2025/6/5 17:51
+ */
+@Getter
+@Setter
+@SearchBean(tables = "web_whole_sale_order_don wod inner join web_whole_sale_order_don_code_relate odr on wod.id = odr.oder_id")
+public class WebWholesaleOrderDonCodeDetailView {
+
+	@DbField("wod.id")
+	private Long orderId;
+
+	@DbField("odr.dh_user_id")
+	private Long dhUserId;
+
+	@DbField("u.nickname")
+	private String nickname;
+
+	/**
+	 * 支付状态
+	 */
+	@DbField("wod.status")
+	@JsonIgnore
+	private WebWholesaleOrderDon.Status status;
+
+	/**
+	 * 支付标题
+	 */
+	@DbField("wod.pay_title")
+	private String payTitle;
+
+	@DbField("odr.update_time")
+	private Date updateTime;
+}

+ 13 - 0
wholesale/src/main/java/com/yhlxj/service/code/ExchangeCodeService.java

@@ -0,0 +1,13 @@
+package com.yhlxj.service.code;
+
+import com.yhlxj.dao.model.request.ExchangeCodeTicket;
+
+/**
+ * 项目名: yhlxj2
+ * 文件名: ExchangeCodeService
+ * 创建者: JavaZou
+ * 创建时间:2025/6/5 17:47
+ */
+public interface ExchangeCodeService {
+	void exchangeCode(ExchangeCodeTicket exchangeCodeTicket) throws Exception;
+}

+ 80 - 0
wholesale/src/main/java/com/yhlxj/service/code/impl/ExchangeCodeServiceImpl.java

@@ -0,0 +1,80 @@
+package com.yhlxj.service.code.impl;
+
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.cyksj.common.exception.BusinessRuntimeException;
+import com.cyksj.common.util.Jsons;
+import com.yhlxj.dao.mapper.ExchangeCodeMapper;
+import com.yhlxj.dao.mapper.WebWholeSaleOrderDonMapper;
+import com.yhlxj.dao.mapper.WebWholesaleOrderDonCodeRelateMapper;
+import com.yhlxj.dao.model.entity.ExchangeCode;
+import com.yhlxj.dao.model.entity.WebWholesaleOrderDon;
+import com.yhlxj.dao.model.entity.WebWholesaleOrderDonCodeRelate;
+import com.yhlxj.dao.model.request.ExchangeCodeTicket;
+import com.yhlxj.service.code.ExchangeCodeService;
+import com.yhlxj.service.relation.GroupRelationFrontService;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.List;
+
+/**
+ * 项目名: yhlxj2
+ * 文件名: ExchangeCodeServiceImpl
+ * 创建者: JavaZou
+ * 创建时间:2025/6/5 17:48
+ */
+@Service
+@RequiredArgsConstructor
+@Slf4j
+public class ExchangeCodeServiceImpl implements ExchangeCodeService {
+	private final WebWholesaleOrderDonCodeRelateMapper webWholesaleOrderDonCodeRelateMapper;
+
+	private final WebWholeSaleOrderDonMapper orderDonMapper;
+
+	private final ExchangeCodeMapper exchangeCodeMapper;
+
+	private final GroupRelationFrontService groupRelationFrontService;
+
+	@Override
+	@Transactional(rollbackFor = Throwable.class)
+	public void exchangeCode(ExchangeCodeTicket exchangeCodeTicket) throws Exception {
+		Long userId = exchangeCodeTicket.getUserId();
+		String code = exchangeCodeTicket.getCode();
+		WebWholesaleOrderDonCodeRelate webWholesaleOrderDonCodeRelate = webWholesaleOrderDonCodeRelateMapper.selectOne(Wrappers.lambdaQuery(WebWholesaleOrderDonCodeRelate.class)
+				.eq(WebWholesaleOrderDonCodeRelate::getCode, code)
+				.last("limit 1"));
+		if (webWholesaleOrderDonCodeRelate == null) {
+			throw BusinessRuntimeException.getInstance("兑换码不存在");
+		}
+		if (webWholesaleOrderDonCodeRelate.getDhUserId() != 0) {
+			throw BusinessRuntimeException.getInstance("兑换码已使用");
+		}
+		Long orderId = webWholesaleOrderDonCodeRelate.getOrderId();
+		WebWholesaleOrderDon webWholesaleOrderDon = orderDonMapper.selectById(orderId);
+		if (webWholesaleOrderDon == null || webWholesaleOrderDon.getStatus() != WebWholesaleOrderDon.Status.complete) {
+			throw BusinessRuntimeException.getInstance("兑换码不存在");
+		}
+		int update = webWholesaleOrderDonCodeRelateMapper.update(null, Wrappers.lambdaUpdate(WebWholesaleOrderDonCodeRelate.class)
+				.set(WebWholesaleOrderDonCodeRelate::getDhUserId, userId)
+				.eq(WebWholesaleOrderDonCodeRelate::getId, webWholesaleOrderDonCodeRelate.getId())
+				.eq(WebWholesaleOrderDonCodeRelate::getDhUserId, 0));
+		if (update == 0) {
+			throw BusinessRuntimeException.getInstance("兑换码已使用");
+		}
+		ExchangeCode exchangeCode = exchangeCodeMapper.selectOne(Wrappers.lambdaQuery(ExchangeCode.class)
+				.eq(ExchangeCode::getCode, code)
+				.eq(ExchangeCode::getUseStatus, false)
+				.last("limit 1"));
+		if (exchangeCode != null) {
+			exchangeCode.setUserId(userId);
+			exchangeCode.setUseStatus(Boolean.TRUE);
+			exchangeCodeMapper.updateById(exchangeCode);
+		}
+		//兑换规格
+		String skuIds = webWholesaleOrderDon.getSkuIds();
+		List<Long> skuIdList = Jsons.parseList(skuIds, Long.class);
+		skuIdList.forEach(skuId -> groupRelationFrontService.getWebWholesaleCodeTicket(userId, skuId));
+	}
+}

+ 19 - 0
wholesale/src/main/java/com/yhlxj/service/groups/GroupsFuncService.java

@@ -0,0 +1,19 @@
+package com.yhlxj.service.groups;
+
+
+import com.yhlxj.dao.model.entity.GoodsDonSku;
+import com.yhlxj.dao.model.entity.GroupsRelation;
+
+/*
+ *项目名: netflix
+ *文件名: GroupsFuncService
+ *创建者: JavaZou
+ *创建时间:2023/6/8 16:34
+ */
+public interface GroupsFuncService {
+
+	/**
+	 * 新增空车队
+	 */
+	GroupsRelation createNewGroupsTrips(GoodsDonSku sku);
+}

+ 144 - 0
wholesale/src/main/java/com/yhlxj/service/groups/impl/GroupsFuncServiceImpl.java

@@ -0,0 +1,144 @@
+package com.yhlxj.service.groups.impl;
+
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.cyksj.common.constant.Constant;
+import com.ejlchina.searcher.BeanSearcher;
+import com.ejlchina.searcher.util.MapUtils;
+import com.yhlxj.dao.mapper.AccountMapper;
+import com.yhlxj.dao.mapper.GroupsMapper;
+import com.yhlxj.dao.mapper.GroupsRelationMapper;
+import com.yhlxj.dao.model.entity.Account;
+import com.yhlxj.dao.model.entity.GoodsDonSku;
+import com.yhlxj.dao.model.entity.GroupsRelation;
+import com.yhlxj.dao.model.entity.GroupsTrips;
+import com.yhlxj.dao.model.view.AccountView;
+import com.yhlxj.service.groups.GroupsFuncService;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.dao.DuplicateKeyException;
+import org.springframework.stereotype.Service;
+
+/**
+ * 项目名: GroupsFuncServiceImpl
+ * 文件名: A
+ * 创建者: JavaZou
+ * 创建时间:2025/6/5 18:06
+ */
+@Service
+@RequiredArgsConstructor
+@Slf4j
+public class GroupsFuncServiceImpl implements GroupsFuncService {
+	private final BeanSearcher beanSearcher;
+
+	private final GroupsMapper groupsMapper;
+
+	private final GroupsRelationMapper groupsRelationMapper;
+
+	private final AccountMapper accountMapper;
+	@Override
+	public GroupsRelation createNewGroupsTrips(GoodsDonSku sku) {
+		//新增车次
+		GroupsTrips groups = new GroupsTrips();
+		groups.setSkuId(sku.getId());
+		groups.setNum(sku.getNum());
+		groups.setAvailableNum(sku.getNum());
+		if (sku.getGoodsId() == 23) {
+			AccountView accountView = beanSearcher.searchFirst(AccountView.class, MapUtils.builder().field(AccountView::getGoodsId, 23).onlySelect(AccountView::getId).build());
+			if (accountView != null) {
+				groups.setAccountId(accountView.getId());
+				groups.setStatus(GroupsTrips.Status.validity);
+				groups.setRemark("已设置唯一账号");
+			} else {
+				groups.setStatus(GroupsTrips.Status.waiting);
+				groups.setRemark("等待设置账号");
+			}
+		} else {
+			groups.setStatus(GroupsTrips.Status.waiting);
+			groups.setRemark("等待设置账号");
+		}
+		//限制每天新车队前3天 停车数量
+		//10人镜像月付GPT
+		Integer availableParkingNum = 0;
+		if (sku.getId() == 161l || sku.getId() == 422l) {
+			availableParkingNum = 20;
+		}
+		//4人镜像月付GPT
+		if (sku.getId() == 178l || sku.getId() == 423l) {
+			availableParkingNum = 6;
+		}
+		//如果是镜像车队
+		setMirrorUnifyAccount(sku, groups);
+		groups.setAvailableParkingNum(availableParkingNum);
+
+		groupsMapper.insert(groups);
+		GroupsRelation relation = new GroupsRelation();
+		relation.setGroupsId(groups.getId());
+		relation.setNum(1);
+		relation.setStatus(GroupsRelation.Status.none);
+		relation.setGroupsId(groups.getId());
+		groupsRelationMapper.insert(relation);
+
+		for (int i = 2; i <= groups.getNum(); i++) {
+			GroupsRelation groupsRelation = new GroupsRelation();
+			groupsRelation.setGroupsId(groups.getId());
+			groupsRelation.setNum(i);
+			groupsRelation.setStatus(GroupsRelation.Status.none);
+			groupsRelationMapper.insert(groupsRelation);
+		}
+		return relation;
+	}
+
+	/**
+	 * 设置镜像统一账号
+	 */
+	public void setMirrorUnifyAccount(GoodsDonSku sku, GroupsTrips groups) {
+		//如果是GPT、MJ镜像车队
+		//设置唯一账号
+		Long goodsId = sku.getGoodsId();
+		Boolean isMirror = sku.getIsMirror();
+		Boolean isCar = sku.getIsCar();
+		String account = null;
+		if ((goodsId == 88 && isMirror) || (goodsId == 87 && isMirror) || (goodsId == 18 && isCar) || (goodsId == 26 && isMirror) || (goodsId == 75 && isCar)) {
+			if (goodsId == 18) {
+				account = Constant.GPT_CAR_ONLY_ACCOUNT;
+			}
+			if (goodsId == 26) {
+				account = Constant.MJ_MIRROR_ONLY_ACCOUNT;
+			}
+			if (goodsId == 75) {
+				account = Constant.CLAUDE_MIRROR_ONLY_ACCOUNT;
+			}
+			if (goodsId == 87) {
+				account = Constant.LUMA_MIRROR_ONLY_ACCOUNT;
+			}
+			if (goodsId == 88) {
+				account = Constant.GROK_MIRROR_ONLY_ACCOUNT;
+			}
+			AccountView accountView = beanSearcher.searchFirst(AccountView.class, MapUtils.builder()
+					.field(AccountView::getGoodsId, goodsId)
+					.field(AccountView::getAccount, account).
+					onlySelect(AccountView::getId).build());
+			Long accountId;
+			if (accountView == null) {
+				try {
+					Account insert = new Account();
+					insert.setAccount(account);
+					insert.setPassword(account);
+					insert.setGoodsId(goodsId);
+					accountMapper.insert(insert);
+					accountId = insert.getId();
+				} catch (DuplicateKeyException e) {
+					accountId = accountMapper.selectOne(Wrappers.lambdaQuery(Account.class)
+							.eq(Account::getGoodsId, goodsId)
+							.eq(Account::getAccount, account)
+							.last("limit 1")).getId();
+				}
+			} else {
+				accountId = accountView.getId();
+			}
+			groups.setAccountId(accountId);
+			groups.setStatus(GroupsTrips.Status.validity);
+			groups.setRemark("已设置镜像车队唯一账号");
+		}
+	}
+}

+ 12 - 0
wholesale/src/main/java/com/yhlxj/service/relation/GroupRelationFrontService.java

@@ -0,0 +1,12 @@
+package com.yhlxj.service.relation;
+
+/*
+ *项目名: netflix
+ *文件名: GroupRelationFrontService
+ *创建者: JavaZou
+ *创建时间:2022/12/29 15:42
+ */
+public interface GroupRelationFrontService {
+
+	Long getWebWholesaleCodeTicket(Long userId, Long skuId);
+}

+ 93 - 0
wholesale/src/main/java/com/yhlxj/service/relation/impl/GroupRelationFrontServiceImpl.java

@@ -0,0 +1,93 @@
+package com.yhlxj.service.relation.impl;
+
+import cn.hutool.core.date.DateTime;
+import cn.hutool.core.date.DateUtil;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.cyksj.common.util.StringUtil;
+import com.github.rholder.retry.*;
+import com.yhlxj.dao.mapper.GoodsDonSkuMapper;
+import com.yhlxj.dao.mapper.GroupsMapper;
+import com.yhlxj.dao.mapper.GroupsRelationMapper;
+import com.yhlxj.dao.model.entity.GoodsDonSku;
+import com.yhlxj.dao.model.entity.GroupsRelation;
+import com.yhlxj.dao.model.entity.GroupsTrips;
+import com.yhlxj.service.groups.GroupsFuncService;
+import com.yhlxj.service.relation.GroupRelationFrontService;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * 项目名: yhlxj2
+ * 文件名: GroupRelationFrontServiceImpl
+ * 创建者: JavaZou
+ * 创建时间:2025/6/5 17:55
+ */
+@Service
+@RequiredArgsConstructor
+@Slf4j
+public class GroupRelationFrontServiceImpl implements GroupRelationFrontService {
+	private final GroupsMapper groupsMapper;
+
+	private final GroupsRelationMapper groupsRelationMapper;
+
+	private final GoodsDonSkuMapper goodsDonSkuMapper;
+
+	private final GroupsFuncService groupsFuncService;
+
+	@Override
+	public Long getWebWholesaleCodeTicket(Long userId, Long skuId) {
+		Retryer<Long> build = RetryerBuilder.<Long>newBuilder()
+				.retryIfException()
+				//运行时异常重试
+				.retryIfRuntimeException()
+				//false重试
+				.retryIfResult(res -> res == null)
+				//1s 间隔
+				.withWaitStrategy(WaitStrategies.fixedWait(1, TimeUnit.SECONDS))
+				//停止策略 : 尝试请求1次
+				.withStopStrategy(StopStrategies.stopAfterAttempt(1)).build();
+		try {
+			return build.call(() -> {
+				GroupsTrips groups = groupsMapper.selectCollegeStudentUserGptTicket(skuId);
+				GroupsRelation relation = null;
+				if (groups != null) {
+					relation = groupsRelationMapper.selectRandomOneRelationByGroupsId(groups.getId());
+				}
+				GoodsDonSku sku = goodsDonSkuMapper.selectById(skuId);
+				//生成空车队
+				if (relation == null) {
+					relation = groupsFuncService.createNewGroupsTrips(sku);
+				}
+				DateTime startTime = DateTime.now();
+				DateTime expiryTime;
+				if (sku.getDays() != null) {
+					expiryTime = DateUtil.offsetDay(startTime, sku.getDays());
+				} else {
+					expiryTime = DateUtil.offsetMonth(startTime, sku.getMonths());
+				}
+				int update = groupsRelationMapper.update(null, Wrappers.lambdaUpdate(GroupsRelation.class)
+						.set(GroupsRelation::getUserId, userId)
+						.set(GroupsRelation::getStartTime, startTime)
+						.set(GroupsRelation::getExpiryTime, expiryTime)
+						.set(GroupsRelation::getStatus, GroupsRelation.Status.validity)
+						//个人网站批发类型
+						.set(GroupsRelation::getAqType, 4)
+						.eq(GroupsRelation::getId, relation.getId())
+						.eq(GroupsRelation::getUserId, 0));
+				if (update > 0) {
+					groupsMapper.decrAvailableNum(groups.getId());
+					return relation.getId();
+				}
+				log.error("发送用户:{} 批发镜像车票失败,进行重试", userId);
+				return null;
+			});
+		} catch (ExecutionException | RetryException e) {
+			log.error("发送批发镜像失败:{}", StringUtil.getErrorText(e));
+			return null;
+		}
+	}
+}

+ 15 - 0
wholesale/src/main/java/com/yhlxj/web/controller/code/exchange/ExchangeCodeController.java

@@ -1,7 +1,14 @@
 package com.yhlxj.web.controller.manage.code.exchange;
 
+import com.yhlxj.dao.model.dto.Result;
+import com.yhlxj.dao.model.enums.GatewayResponse;
+import com.yhlxj.dao.model.request.ExchangeCodeTicket;
+import com.yhlxj.service.code.ExchangeCodeService;
+import com.yhlxj.web.util.StpUserUtil;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 
@@ -17,8 +24,16 @@ import org.springframework.web.bind.annotation.RestController;
 @RestController
 @RequestMapping("/applets/wholesale/code")
 public class ExchangeCodeController {
+	private final ExchangeCodeService exchangeCodeService;
 
 	/**
 	 * 兑换车票
 	 */
+	@PostMapping("/exchange")
+	public Result<String> exchangeCode(@RequestBody ExchangeCodeTicket exchangeCodeTicket) {
+		long userId = StpUserUtil.getLoginIdAsLong();
+		exchangeCodeTicket.setUserId(userId);
+		exchangeCodeService.exchangeCode(exchangeCodeTicket);
+		return GatewayResponse.SUCCESS.newBuilder().toResult();
+	}
 }

+ 13 - 0
wholesale/src/main/resources/mapper/GroupsMapper.xml

@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.yhlxj.dao.mapper.GroupsMapper">
+
+    <select id="selectCollegeStudentUserGptTicket" resultType="com.yhlxj.dao.model.entity.GroupsTrips">
+        select gt.id
+        from `groups_trips` gt
+        where gt.sku_id = #{skuId}
+          and gt.status = 'validity'
+          and gt.available_num > 0
+        order by rand() limit 1
+    </select>
+</mapper>

+ 14 - 0
wholesale/src/main/resources/mapper/GroupsRelationMapper.xml

@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.yhlxj.dao.mapper.GroupsRelationMapper">
+
+
+    <select id="selectRandomOneRelationByGroupsId" resultType="com.yhlxj.dao.model.entity.GroupsRelation">
+        select *
+        from groups_relation
+        where groups_id = #{groupsId}
+          and user_id = 0
+          and status = 'none'
+        order by rand() limit 1
+    </select>
+</mapper>