浏览代码

Merge branch 'abroad_073' into abroad_pre

# Conflicts:
#	netflix-web/src/main/java/com/cyksj/web/controller/manage/CmsOrderController.java
#	netflix-web/src/main/java/com/cyksj/web/controller/manage/account/CmsAccountController.java
#	netflix-web/src/main/java/com/cyksj/web/controller/manage/goods/CmsGoodsDonController.java
#	netflix-web/src/main/java/com/cyksj/web/controller/manage/group/CmsGroupRelationController.java
zoujiajian 2 年之前
父节点
当前提交
0ba418078b
共有 35 个文件被更改,包括 1597 次插入182 次删除
  1. 5 0
      netflix-common/src/main/java/com/cyksj/common/constant/Constant.java
  2. 16 0
      netflix-common/src/main/java/com/cyksj/common/util/StringUtil.java
  3. 64 0
      netflix-common/src/main/java/com/cyksj/common/util/TicketCodeCommonUtil.java
  4. 4 0
      netflix-dao/src/main/java/com/cyksj/mapper/GoodsDonSkuMapper.java
  5. 13 0
      netflix-dao/src/main/java/com/cyksj/mapper/GroupsRelationIndependentRenewMapper.java
  6. 13 0
      netflix-dao/src/main/java/com/cyksj/mapper/GroupsRelationLoginCodeRecordMapper.java
  7. 13 0
      netflix-dao/src/main/java/com/cyksj/mapper/TicketPwdViewRecordMapper.java
  8. 44 0
      netflix-dao/src/main/java/com/cyksj/model/dto/CuiQiuEmailDetailDto.java
  9. 38 0
      netflix-dao/src/main/java/com/cyksj/model/dto/CuiQiuEmailDto.java
  10. 31 0
      netflix-dao/src/main/java/com/cyksj/model/dto/CuiQiuEmailResultDto.java
  11. 90 6
      netflix-dao/src/main/java/com/cyksj/model/entity/GoodsDonSku.java
  12. 24 0
      netflix-dao/src/main/java/com/cyksj/model/entity/GroupsRelationIndependentRenew.java
  13. 24 0
      netflix-dao/src/main/java/com/cyksj/model/entity/GroupsRelationLoginCodeRecord.java
  14. 26 0
      netflix-dao/src/main/java/com/cyksj/model/entity/TicketPwdViewRecord.java
  15. 63 0
      netflix-dao/src/main/java/com/cyksj/model/views/AccountSpecificView.java
  16. 78 0
      netflix-dao/src/main/java/com/cyksj/model/views/GroupsRelationIndependentView.java
  17. 49 0
      netflix-dao/src/main/java/com/cyksj/model/views/OrderDonRenewView.java
  18. 51 0
      netflix-dao/src/main/java/com/cyksj/model/views/TicketPwdViewRecordView.java
  19. 16 0
      netflix-dao/src/main/resources/mapper/GoodsDonSkuMapper.xml
  20. 1 0
      netflix-service/src/main/java/com/cyksj/redis/RedisService.java
  21. 15 0
      netflix-service/src/main/java/com/cyksj/service/mail/CuiQiuMailService.java
  22. 166 0
      netflix-service/src/main/java/com/cyksj/service/mail/impl/CuiQiuMailServiceImpl.java
  23. 15 0
      netflix-service/src/main/java/com/cyksj/service/mange/RefreshCacheService.java
  24. 26 0
      netflix-service/src/main/java/com/cyksj/service/mange/impl/RefreshCacheServiceImpl.java
  25. 6 1
      netflix-service/src/main/java/com/cyksj/service/relation/GroupRelationFrontService.java
  26. 27 0
      netflix-service/src/main/java/com/cyksj/service/relation/GroupsRelationNetflixService.java
  27. 131 3
      netflix-service/src/main/java/com/cyksj/service/relation/impl/GroupRelationFrontServiceImpl.java
  28. 168 0
      netflix-service/src/main/java/com/cyksj/service/relation/impl/GroupsRelationNetflixServiceImpl.java
  29. 20 9
      netflix-web/src/main/java/com/cyksj/web/controller/group/GroupRelationController.java
  30. 1 0
      netflix-web/src/main/java/com/cyksj/web/controller/manage/CmsOrderController.java
  31. 37 4
      netflix-web/src/main/java/com/cyksj/web/controller/manage/account/CmsAccountController.java
  32. 139 137
      netflix-web/src/main/java/com/cyksj/web/controller/manage/goods/CmsGoodsDonController.java
  33. 100 21
      netflix-web/src/main/java/com/cyksj/web/controller/manage/goods/CmsGoodsDonSkuController.java
  34. 83 0
      netflix-web/src/main/java/com/cyksj/web/controller/manage/group/CmsGroupRelationController.java
  35. 0 1
      netflix-web/src/main/java/com/cyksj/web/controller/manage/shop/ShopConfigController.java

+ 5 - 0
netflix-common/src/main/java/com/cyksj/common/constant/Constant.java

@@ -146,4 +146,9 @@ public interface Constant {
 	 * 新科手机号
 	 */
 	String XK_PHONE = "17681947535";
+
+	/**
+	 * 电影域名
+	 */
+	String ZHAOJU_MOVIES = "https://zhaoju666.com";
 }

+ 16 - 0
netflix-common/src/main/java/com/cyksj/common/util/StringUtil.java

@@ -11,6 +11,8 @@ import java.io.StringWriter;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Random;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 
 /**
  * @author  chan 字符串操作辅助类
@@ -491,4 +493,18 @@ public final class StringUtil {
 
 		return "unknown";
 	}
+
+	/**
+	 * 获取账号登录验证码
+	 */
+	public static String getVerifyCodePattern(String code, Integer length) {
+		if (StrUtil.isNotEmpty(code)) {
+			Pattern pattern = Pattern.compile(String.format("\\d{%s,}", length));
+			Matcher matcher = pattern.matcher(code);
+			while (matcher.find()) {
+				return matcher.group();
+			}
+		}
+		return StrUtil.EMPTY;
+	}
 }

+ 64 - 0
netflix-common/src/main/java/com/cyksj/common/util/TicketCodeCommonUtil.java

@@ -0,0 +1,64 @@
+package com.cyksj.common.util;
+
+import cn.hutool.core.util.StrUtil;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * 项目名: yhlxj2
+ * 文件名: TicketCodeCommonUtil
+ * 创建者: JavaZou
+ * 创建时间:2024/5/24 15:31
+ */
+
+public class TicketCodeCommonUtil {
+	/**
+	 * 车票邮箱验证码
+	 */
+	public static String getTicketCodeStr(String body, Long goodsId) {
+		if (StrUtil.isEmpty(body)) {
+			return body;
+		}
+		String str = null;
+		if (goodsId == 33l) {
+			str = "color:#505050; font-family:adobe-clean, Helvetica Neue, Helvetica, Verdana, Arial, sans-serif;";
+		}
+		if (goodsId == 3l) {
+			str = "letter-spacing:4px; line-height:38px; mso-line-height-rule: exactly";
+		}
+		if (StrUtil.isEmpty(str)) {
+			return str;
+		}
+		int index = body.indexOf(str);
+		if (index == -1) {
+			if (goodsId == 33l) {
+				str = "X-Report-Abuse: abuse@adobe.com";
+			}
+			if (goodsId == 3l) {
+				str = "Noto Sans Display', Helvetica, Arial, sans-serif; font-weight: 600;text-align: center;";
+			}
+			index = body.indexOf(str);
+		}
+		String code = StrUtil.subWithLength(body, index, 512);
+		if (StrUtil.isNotBlank(code)) {
+			code = code.replace(str, "");
+		}
+		return code;
+	}
+
+	public static String extractUrl(String body, String prefixUrl) {
+		String urlPattern = "(https?://\\S+)";
+		Pattern pattern = Pattern.compile(urlPattern);
+		Matcher matcher = pattern.matcher(body);
+
+		// 查找匹配的URL
+		while (matcher.find()) {
+			String url = matcher.group();
+			if (url.contains(prefixUrl)) {
+				return url.replaceAll("\"", "");
+			}
+		}
+		return null;
+	}
+}

+ 4 - 0
netflix-dao/src/main/java/com/cyksj/mapper/GoodsDonSkuMapper.java

@@ -13,4 +13,8 @@ import java.util.List;
 public interface GoodsDonSkuMapper  extends BaseMapper<GoodsDonSku> {
 
 	List<Long> selectAIMonthSkuIds(@Param("list") List<Long> goodsIds);
+
+	List<Long> getSpecificSkuIdsByGoodsIds(@Param("list") List<Long> aiGoodsIds, @Param("months") Integer months);
+
+	List<Long> getSpecificSkuIdsByGoodsId(@Param("goodsId") Long goodsId, @Param("num") Integer num, @Param("months") Integer months);
 }

+ 13 - 0
netflix-dao/src/main/java/com/cyksj/mapper/GroupsRelationIndependentRenewMapper.java

@@ -0,0 +1,13 @@
+package com.cyksj.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.cyksj.model.entity.GroupsRelationIndependentRenew;
+
+/**
+ * 项目名: yhlxj
+ * 文件名: GroupsRelationIndependentRenewMapper
+ * 创建者: JavaZou
+ * 创建时间:2023/11/27 15:27
+ */
+public interface GroupsRelationIndependentRenewMapper extends BaseMapper<GroupsRelationIndependentRenew> {
+}

+ 13 - 0
netflix-dao/src/main/java/com/cyksj/mapper/GroupsRelationLoginCodeRecordMapper.java

@@ -0,0 +1,13 @@
+package com.cyksj.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.cyksj.model.entity.GroupsRelationLoginCodeRecord;
+
+/**
+ * 项目名: yhlxj
+ * 文件名: GroupsRelationLoginCodeRecordMapper
+ * 创建者: JavaZou
+ * 创建时间:2023/12/4 11:07
+ */
+public interface GroupsRelationLoginCodeRecordMapper extends BaseMapper<GroupsRelationLoginCodeRecord> {
+}

+ 13 - 0
netflix-dao/src/main/java/com/cyksj/mapper/TicketPwdViewRecordMapper.java

@@ -0,0 +1,13 @@
+package com.cyksj.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.cyksj.model.entity.TicketPwdViewRecord;
+
+/*
+ *项目名: netflix
+ *文件名: TicketPwdViewRecordMapper
+ *创建者: JavaZou
+ *创建时间:2023/5/17 16:15
+ */
+public interface TicketPwdViewRecordMapper extends BaseMapper<TicketPwdViewRecord> {
+}

+ 44 - 0
netflix-dao/src/main/java/com/cyksj/model/dto/CuiQiuEmailDetailDto.java

@@ -0,0 +1,44 @@
+package com.cyksj.model.dto;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.List;
+
+/**
+ * 项目名: yhlxj2
+ * 文件名: CuiQiuEmailDetailDto
+ * 创建者: JavaZou
+ * 创建时间:2024/4/25 16:52
+ */
+@Getter
+@Setter
+public class CuiQiuEmailDetailDto {
+	private Integer code;
+
+	private String msg;
+
+	private ResultData data;
+
+	@Getter
+	@Setter
+	public static class ResultData{
+		private Content content;
+	}
+
+	@Getter
+	@Setter
+	public static class Content {
+		private Integer id;
+
+		private String time;
+
+		private String subject;
+
+		private List<CuiQiuEmailDto.CuiQiuUser> from;
+
+		private List<CuiQiuEmailDto.CuiQiuUser> to;
+
+		private String body;
+	}
+}

+ 38 - 0
netflix-dao/src/main/java/com/cyksj/model/dto/CuiQiuEmailDto.java

@@ -0,0 +1,38 @@
+package com.cyksj.model.dto;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.List;
+
+/**
+ * 项目名: yhlxj2
+ * 文件名: CuiQiuEmailDto
+ * 创建者: JavaZou
+ * 创建时间:2024/4/25 16:35
+ */
+
+@Getter
+@Setter
+public class CuiQiuEmailDto {
+
+	private Long id;
+
+	private String time;
+
+	private Long timestamp;
+
+	private String subject;
+
+	private List<CuiQiuUser> from;
+
+	private List<CuiQiuUser> to;
+
+	@Getter
+	@Setter
+	public static class CuiQiuUser{
+		private String name;
+
+		private String address;
+	}
+}

+ 31 - 0
netflix-dao/src/main/java/com/cyksj/model/dto/CuiQiuEmailResultDto.java

@@ -0,0 +1,31 @@
+package com.cyksj.model.dto;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.List;
+
+/**
+ * 项目名: yhlxj2
+ * 文件名: CuiQiuEmailResultDto
+ * 创建者: JavaZou
+ * 创建时间:2024/4/25 16:42
+ */
+@Getter
+@Setter
+public class CuiQiuEmailResultDto {
+	private Integer code;
+
+	private String msg;
+
+	private ResultData data;
+
+	@Getter
+	@Setter
+	public static class ResultData {
+		private Integer total;
+
+		private List<CuiQiuEmailDto> list;
+	}
+
+}

+ 90 - 6
netflix-dao/src/main/java/com/cyksj/model/entity/GoodsDonSku.java

@@ -3,10 +3,10 @@ package com.cyksj.model.entity;
 import com.baomidou.mybatisplus.annotation.FieldStrategy;
 import com.baomidou.mybatisplus.annotation.TableField;
 import com.cyksj.model.views.GoodsDiscountPlusPurchaseRelationFrontView;
-import com.ejlchina.searcher.bean.DbField;
 import com.ejlchina.searcher.bean.DbIgnore;
 import com.ejlchina.searcher.bean.SearchBean;
 import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
 import lombok.Getter;
 import lombok.Setter;
 
@@ -19,7 +19,8 @@ import java.util.List;
  */
 @Getter
 @Setter
-@SearchBean(tables = "goods_don_sku")
+@SearchBean(tables = "goods_don_sku",
+        where = ":condition:")
 @JsonInclude(JsonInclude.Include.NON_NULL)
 public class GoodsDonSku extends BaseEntity {
 
@@ -53,6 +54,26 @@ public class GoodsDonSku extends BaseEntity {
      */
     private String notifyText;
 
+    /**
+     * H5标签
+     */
+    private String mobileTags;
+
+    /**
+     * 规格背景图
+     */
+    private String img;
+
+    /**
+     * 规格框提示
+     */
+    private String smallMsg;
+
+    /**
+     * 双重验证码次数
+     */
+    private Integer codeNum;
+
     /**
      * 商品预览图
      */
@@ -116,9 +137,9 @@ public class GoodsDonSku extends BaseEntity {
     @TableField(updateStrategy = FieldStrategy.IGNORED)
     private Integer days;
 
-    @DbField("case when spec_val like '%月%' and spec_val not like '%年%' then 0 when spec_val like '%季%' then 1 when spec_val like '%半年%' then 2 when spec_val like '%年%' then 3 else 66 end")
-    @TableField(exist = false)
-    private Integer orderBy;
+//    @DbField("case when spec_val like '%月%' and spec_val not like '%年%' then 0 when spec_val like '%季%' then 1 when spec_val like '%半年%' then 2 when spec_val like '%年%' then 3 else 66 end")
+//    @TableField(exist = false)
+//    private Integer orderBy;
 
     /**
      * 加购规格
@@ -132,10 +153,73 @@ public class GoodsDonSku extends BaseEntity {
      */
     private Boolean isDp;
 
+    /**
+     * 是否是镜像服务
+     */
+    private Boolean isMirror;
+
+    /**
+     * 是否是车队形式
+     */
+    private Boolean isCar;
+
+    /**
+     * 限制次数
+     */
+    private Integer gptLimitNum;
+
+    /**
+     * 限制时间
+     */
+    private Long gptLimitTime;
+
+    /**
+     * mj fast次数
+     */
+    private Integer mjFastNum;
+
+    /**
+     * mj relax次数
+     */
+    @TableField(updateStrategy = FieldStrategy.IGNORED)
+    private Integer mjRelaxNum;
+
+    /**
+     * 特定价格
+     */
+    private BigDecimal specificPrice;
+
+    /**
+     * 特定平台购买用户人群
+     */
+    private String specificGoodsIds;
+
     /**
      * 优惠加购商品规格展示
      */
     @DbIgnore
     @TableField(exist = false)
-    private List<GoodsDiscountPlusPurchaseRelationFrontView> dpSkuViews;
+    private List<GoodsDiscountPlusPurchaseRelationFrontView> dpSkuList;
+
+    /**
+     * 前端展示
+     */
+    @DbIgnore
+    @TableField(exist = false)
+    @JsonProperty("gname")
+    private String gName;
+
+    /**
+     * 前端展示
+     */
+    @DbIgnore
+    @TableField(exist = false)
+    @JsonProperty("sname")
+    private String sName;
+
+    /**
+     * 排序
+     */
+    @TableField(updateStrategy = FieldStrategy.IGNORED)
+    private Integer sorted;
 }

+ 24 - 0
netflix-dao/src/main/java/com/cyksj/model/entity/GroupsRelationIndependentRenew.java

@@ -0,0 +1,24 @@
+package com.cyksj.model.entity;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * 项目名: yhlxj
+ * 文件名: GroupsRelationIndependentRenew
+ * 创建者: JavaZou
+ * 创建时间:2023/11/27 15:26
+ */
+@Getter
+@Setter
+public class GroupsRelationIndependentRenew extends BaseEntity{
+	private Long userId;
+
+	private Long relationId;
+
+	private Boolean isRenew;
+
+	private String operator;
+
+	private Long orderId;
+}

+ 24 - 0
netflix-dao/src/main/java/com/cyksj/model/entity/GroupsRelationLoginCodeRecord.java

@@ -0,0 +1,24 @@
+package com.cyksj.model.entity;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * 项目名: yhlxj
+ * 文件名: GroupsRelationLoginCodeRecord
+ * 创建者: JavaZou
+ * 创建时间:2023/12/4 11:06
+ */
+@Getter
+@Setter
+public class GroupsRelationLoginCodeRecord extends BaseEntity{
+	private Long userId;
+
+	private Long skuId;
+
+	private Long relationId;
+
+	private Long goodsId;
+
+	private String account;
+}

+ 26 - 0
netflix-dao/src/main/java/com/cyksj/model/entity/TicketPwdViewRecord.java

@@ -0,0 +1,26 @@
+package com.cyksj.model.entity;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/*
+ *项目名: netflix
+ *文件名: TicketPwdViewRecord
+ *创建者: JavaZou
+ *创建时间:2023/5/17 16:07
+ */
+@Getter
+@Setter
+public class TicketPwdViewRecord extends BaseEntity{
+	private Long userId;
+
+	private Long relationId;
+
+	private String account;
+
+	private String password;
+
+	private Long skuId;
+
+	private String operateLocation;
+}

+ 63 - 0
netflix-dao/src/main/java/com/cyksj/model/views/AccountSpecificView.java

@@ -0,0 +1,63 @@
+package com.cyksj.model.views;
+
+import com.ejlchina.searcher.bean.DbField;
+import com.ejlchina.searcher.bean.SearchBean;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.Date;
+
+/*
+ *项目名: yhlxj
+ *文件名: AccountSpecificView
+ *创建者: JavaZou
+ *创建时间:2023/9/21 15:03
+ */
+@Getter
+@Setter
+@SearchBean(tables = "account a inner join groups_trips gt on gt.account_id = a.id :condition:" +
+		" left join goods_don g on g.id = a.goods_id" +
+		" left join goods_don_sku sku on sku.id = gt.sku_id")
+public class AccountSpecificView {
+	@DbField("a.id")
+	private Long id;
+
+	@DbField("a.account")
+	private String account;
+
+	@DbField("a.password")
+	private String password;
+
+	@DbField("a.start_time")
+	private Date startTime;
+
+	@DbField("a.expiry_time")
+	private Date expiryTime;
+
+	@DbField("a.goods_id")
+	private Long goodsId;
+
+	@DbField("gt.sku_id")
+	private Long skuId;
+
+	@DbField("g.title")
+	private String title;
+
+	@DbField("sku.spec_val")
+	private String specVal;
+
+	@DbField("gt.num")
+	private Integer num;
+
+	@DbField("gt.available_num")
+	private Integer availableNum;
+
+	@DbField("a.remark")
+	private String remark;
+
+	@DbField("a.created_time")
+	private Date createdTime;
+
+	@DbField("a.update_time")
+	private Date updateTime;
+}

+ 78 - 0
netflix-dao/src/main/java/com/cyksj/model/views/GroupsRelationIndependentView.java

@@ -0,0 +1,78 @@
+package com.cyksj.model.views;
+
+import com.ejlchina.searcher.bean.DbField;
+import com.ejlchina.searcher.bean.SearchBean;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.Date;
+
+/**
+ * 项目名: yhlxj
+ * 文件名: GroupsRelationIndependentView
+ * 创建者: JavaZou
+ * 创建时间:2023/11/27 15:10
+ */
+
+@Getter
+@Setter
+@SearchBean(tables = "order_don o inner join groups_relation gr on gr.id = o.relation_id and gr.user_id = o.user_id" +
+		" left join groups_relation_independent_renew gnr on gnr.order_id = o.id" +
+		" inner join user u on u.id = gr.user_id" +
+		" left join goods_don_sku sku on sku.id = o.sku_id" +
+		" left join goods_don g on g.id = o.goods_id" +
+		" left join groups_trips gt on gt.id = gr.groups_id" +
+		" left join account a on a.id = gt.account_id",
+		where = ":condition:")
+public class GroupsRelationIndependentView {
+	@DbField("gr.id")
+	private Long relationId;
+
+	@DbField("gr.groups_id")
+	private Long groupsId;
+
+	@DbField("o.id")
+	private Long orderId;
+
+	@DbField("a.account")
+	private String account;
+
+	@DbField("a.password")
+	private String password;
+
+	@DbField("gr.user_id")
+	private Long userId;
+
+	@DbField("u.nickname")
+	private String nickname;
+
+	@DbField("gr.start_time")
+	private Date startTime;
+
+	@DbField("gr.expiry_time")
+	private Date expiryTime;
+
+	@DbField("a.expiry_time")
+	private Date accountExpiryTime;
+
+	@DbField("ifnull(gnr.is_renew,false)")
+	private Boolean isRenew;
+
+	@DbField("ifnull(o.pay_time,o.created_time)")
+	private Date submitTime;
+
+	@DbField("g.id")
+	private Long goodsId;
+
+	@DbField("sku.id")
+	private Long skuId;
+
+	@DbField("g.title")
+	private String title;
+
+	@DbField("sku.spec_val")
+	private String specVal;
+
+	@DbField("if(gnr.is_renew,gnr.update_time,null)")
+	private Date updateTime;
+}

+ 49 - 0
netflix-dao/src/main/java/com/cyksj/model/views/OrderDonRenewView.java

@@ -0,0 +1,49 @@
+package com.cyksj.model.views;
+
+import com.cyksj.model.entity.OrderDon;
+import com.ejlchina.searcher.bean.DbField;
+import com.ejlchina.searcher.bean.SearchBean;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.math.BigDecimal;
+import java.util.Date;
+
+/**
+ * 项目名: yhlxj
+ * 文件名: OrderDonRenewView
+ * 创建者: JavaZou
+ * 创建时间:2023/11/27 15:34
+ */
+@Getter
+@Setter
+@SearchBean(tables = "order_don o left join goods_don g on g.id = o.goods_id" +
+		" left join goods_don_sku sku on sku.id = o.sku_id")
+public class OrderDonRenewView {
+	@DbField("o.id")
+	private Long orderId;
+
+	@DbField("o.user_id")
+	private Long userId;
+
+	@DbField("g.title")
+	private String title;
+
+	@DbField("sku.spec_val")
+	private String specVal;
+
+	@DbField("o.money")
+	private BigDecimal money;
+
+	@DbField("o.relation_id")
+	private Long relationId;
+
+	@DbField("o.order_type")
+	private Integer orderType;
+
+	@DbField("o.status")
+	private OrderDon.Status status;
+
+	@DbField("o.created_time")
+	private Date createdTime;
+}

+ 51 - 0
netflix-dao/src/main/java/com/cyksj/model/views/TicketPwdViewRecordView.java

@@ -0,0 +1,51 @@
+package com.cyksj.model.views;
+
+import com.ejlchina.searcher.bean.DbField;
+import com.ejlchina.searcher.bean.SearchBean;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.Date;
+
+/**
+ * 项目名: yhlxj
+ * 文件名: TicketPwdViewRecordView
+ * 创建者: JavaZou
+ * 创建时间:2024/1/23 13:54
+ */
+@Getter
+@Setter
+@SearchBean(tables = "(select * from ticket_pwd_view_record where account is not null) tpr left join goods_don_sku sku on sku.id = tpr.sku_id" +
+		" left join goods_don g on g.id = sku.goods_id" +
+		" left join user u on u.id = tpr.user_id")
+public class TicketPwdViewRecordView {
+	@DbField("tpr.id")
+	private Long id;
+
+	@DbField("u.id")
+	private Long userId;
+
+	@DbField("u.nickname")
+	private String nickname;
+
+	@DbField("tpr.account")
+	private String account;
+
+	@DbField("tpr.password")
+	private String password;
+
+	@DbField("g.id")
+	private Long goodsId;
+
+	@DbField("g.title")
+	private String title;
+
+	@DbField("sku.id")
+	private Long skuId;
+
+	@DbField("sku.spec_val")
+	private String specVal;
+
+	@DbField("tpr.created_time")
+	private Date createdTime;
+}

+ 16 - 0
netflix-dao/src/main/resources/mapper/GoodsDonSkuMapper.xml

@@ -9,4 +9,20 @@
         </foreach>
         and `months` = 1
     </select>
+
+    <select id="getSpecificSkuIdsByGoodsIds" resultType="java.lang.Long">
+        select id from goods_don_sku where goods_id in
+        <foreach collection="list" item="item" open="(" separator="," close=")">
+            #{item}
+        </foreach>
+        and `months` = #{months}
+    </select>
+
+    <select id="getSpecificSkuIdsByGoodsId" resultType="java.lang.Long">
+        select id
+        from goods_don_sku
+        where goods_id = #{goodsId}
+          and num = #{num}
+          and `months` = #{months}
+    </select>
 </mapper>

+ 1 - 0
netflix-service/src/main/java/com/cyksj/redis/RedisService.java

@@ -632,6 +632,7 @@ public class RedisService {
         USER_BIND_ACCOUNT_INFO_KEY("user_bind_account_info_key:", "用户绑定其他账号key", 10l),
         TASK_RECEIVED_KEY("task_received_key:%s:%s", "领取任务奖励key", 10l),
         EXCHANGE_RATE_KEY("exchange_rate_key","当日汇率",60 * 60 * 4L),
+        NETFLIX_SET_LIMIT_TIME("netflix_set_limit_time", "奈飞设置限制", 30l),
         ;
 
         private String name;

+ 15 - 0
netflix-service/src/main/java/com/cyksj/service/mail/CuiQiuMailService.java

@@ -0,0 +1,15 @@
+package com.cyksj.service.mail;
+
+/**
+ * 项目名: yhlxj2
+ * 文件名: CuiQiuMailService
+ * 创建者: JavaZou
+ * 创建时间:2024/4/25 15:55
+ */
+public interface CuiQiuMailService {
+
+	/**
+	 * 获取最新邮箱 返回验证码
+	 */
+	String getVerifyCode(String email, Long goodsId, Integer type, Boolean sync) throws Exception;
+}

+ 166 - 0
netflix-service/src/main/java/com/cyksj/service/mail/impl/CuiQiuMailServiceImpl.java

@@ -0,0 +1,166 @@
+package com.cyksj.service.mail.impl;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.date.DateTime;
+import cn.hutool.core.date.DateUtil;
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.http.HttpRequest;
+import cn.hutool.http.HttpResponse;
+import cn.hutool.http.HttpUtil;
+import com.cyksj.common.exception.BusinessRuntimeException;
+import com.cyksj.common.util.Jsons;
+import com.cyksj.common.util.StringUtil;
+import com.cyksj.common.util.TicketCodeCommonUtil;
+import com.cyksj.model.dto.CuiQiuEmailDetailDto;
+import com.cyksj.model.dto.CuiQiuEmailDto;
+import com.cyksj.model.dto.CuiQiuEmailResultDto;
+import com.cyksj.service.mail.CuiQiuMailService;
+import com.cyksj.service.relation.GroupsRelationNetflixService;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+/**
+ * 项目名: yhlxj2
+ * 文件名: CuiQiuMailServiceImpl
+ * 创建者: JavaZou
+ * 创建时间:2024/4/25 15:57
+ */
+@Service
+@Slf4j
+@RequiredArgsConstructor
+public class CuiQiuMailServiceImpl implements CuiQiuMailService {
+	private final GroupsRelationNetflixService groupsRelationNetflix;
+
+	private final static String CUI_QIU_TOKEN = "4ff0341ebf1747cd89a2d1a5a296b68b";
+
+	//脆球域名id
+	private final static String DOMAIN_ID = "1696913058045050661";
+
+	//代收管理员邮件id
+	private final static String ADMIN_MAIL_ID = "1696913058063659217";
+
+	//PS 验证码官方
+	private final static String PS_ADOBE = "Adobe";
+
+	private final static String DISNEY = "Disney+";
+
+	private final static String NETFLIX = "Netflix";
+
+	@Override
+	public String getVerifyCode(String email, Long goodsId, Integer type, Boolean sync) throws Exception {
+		//获取近二十封邮件
+		String url = "https://domain-open-api.cuiqiu.com/v1/message/list";
+
+		Map<String, Object> params = new HashMap<>();
+
+		//获取近五分钟的代收邮件
+		//维度是天
+		DateTime now = DateTime.now();
+		params.put("token", CUI_QIU_TOKEN);
+		params.put("mail_id", ADMIN_MAIL_ID);
+		params.put("start_time", DateUtil.offsetDay(now, -1).toDateStr());
+		params.put("end_time", DateUtil.offsetDay(now, 1).toDateStr());
+		params.put("to", email);
+		params.put("limit", 20);
+
+		HttpRequest post = HttpUtil.createPost(url);
+		post.form(params);
+		HttpResponse execute = post.execute();
+		CuiQiuEmailResultDto resultDto = Jsons.parseObject(execute.body(), CuiQiuEmailResultDto.class);
+		if (resultDto.getData().getList() == null) {
+			return null;
+		}
+		List<CuiQiuEmailDto> list = resultDto.getData().getList();
+		//获取邮箱对应的邮件
+		list = list.stream().filter(emailInfo -> {
+			CuiQiuEmailDto.CuiQiuUser from = emailInfo.getFrom().get(0);
+			CuiQiuEmailDto.CuiQiuUser cuiQiuUser = emailInfo.getTo().get(0);
+			if (StrUtil.equalsIgnoreCase(cuiQiuUser.getAddress(), email)) {
+				//PS
+				if (goodsId == 33l && StrUtil.equals(from.getName(), PS_ADOBE)) {
+					return true;
+				}
+				//Disney
+				if (goodsId == 3l && StrUtil.equals(from.getName(), DISNEY)) {
+					return true;
+				}
+				if (goodsId == 1l && StrUtil.equals(from.getName(), NETFLIX)) {
+					return true;
+				}
+			}
+			return false;
+		}).collect(Collectors.toList());
+
+		if (CollUtil.isNotEmpty(list)) {
+			for (CuiQiuEmailDto cuiQiuEmailDto : list) {
+				Long messageId = cuiQiuEmailDto.getId();
+				try {
+					String code = getVerifyCodeByEmail(messageId, goodsId, type, sync);
+					if (StrUtil.isNotBlank(code)) {
+						return code;
+					}
+				} catch (Exception e) {
+				}
+			}
+		}
+		return null;
+	}
+
+	public String getVerifyCodeByEmail(Long messageId, Long goodsId, Integer type, Boolean sync) throws Exception {
+		String url = "https://domain-open-api.cuiqiu.com/v1/message/detail";
+		Map<String, Object> params = new HashMap<>();
+		params.put("token", CUI_QIU_TOKEN);
+		params.put("mail_id", ADMIN_MAIL_ID);
+		params.put("message_id", messageId);
+		HttpRequest post = HttpUtil.createPost(url);
+		post.form(params);
+		HttpResponse execute = post.execute();
+		String respBody = execute.body();
+		CuiQiuEmailDetailDto cuiQiuEmailDetailDto = Jsons.parseObject(respBody, CuiQiuEmailDetailDto.class);
+		CuiQiuEmailDetailDto.Content content = cuiQiuEmailDetailDto.getData().getContent();
+		String code = null;
+		String body = content.getBody();
+		if (goodsId == 1) {
+			if (type != null && type == 1) {
+				String pre = "NetflixSans-Regular, Helvetica, Roboto, Segoe UI, sans-serif; font-weight";
+				if (body.contains("輸入此代碼登入") || body.contains("输入此代码登录")) {
+					code = StrUtil.subAfter(body, pre, false);
+				}
+				if (StrUtil.isEmpty(code)) {
+					throw BusinessRuntimeException.getInstance("查询失败,请检查是否发送了登陆码..");
+				}
+			} else {
+				String urlPref = "https://www.netflix.com/account/update-primary-location";
+				String nfVerifyUrl = TicketCodeCommonUtil.extractUrl(body, urlPref);
+				if (StrUtil.isEmpty(nfVerifyUrl)) {
+					urlPref = "https://www.netflix.com/account/travel/verify";
+					nfVerifyUrl = TicketCodeCommonUtil.extractUrl(body, urlPref);
+					if (StrUtil.isEmpty(nfVerifyUrl)) {
+						throw BusinessRuntimeException.getInstance("获取认证链接失败,请重新获取");
+					}
+				}
+				//非点击装置同步更新按钮 直接返回链接
+				if (!sync) return nfVerifyUrl;
+				//失败返回验证链接
+				if (!groupsRelationNetflix.confirmUpdate(nfVerifyUrl)) {
+					return nfVerifyUrl;
+				}
+				return StrUtil.EMPTY;
+			}
+		}
+		if (StrUtil.isEmpty(code)) {
+			code = TicketCodeCommonUtil.getTicketCodeStr(body, goodsId);
+		}
+		int length = 4;
+		if (goodsId == 33l) {
+			length = 6;
+		}
+		return StringUtil.getVerifyCodePattern(code, length);
+	}
+}

+ 15 - 0
netflix-service/src/main/java/com/cyksj/service/mange/RefreshCacheService.java

@@ -0,0 +1,15 @@
+package com.cyksj.service.mange;
+
+/**
+ * 项目名: yhlxj2
+ * 文件名: RefreshCacheService
+ * 创建者: JavaZou
+ * 创建时间:2024/2/22 16:28
+ */
+public interface RefreshCacheService {
+
+	/**
+	 * 清除官网首页商品缓存
+	 */
+	void refreshYhHomePageCache();
+}

+ 26 - 0
netflix-service/src/main/java/com/cyksj/service/mange/impl/RefreshCacheServiceImpl.java

@@ -0,0 +1,26 @@
+package com.cyksj.service.mange.impl;
+
+import com.cyksj.redis.RedisService;
+import com.cyksj.service.mange.RefreshCacheService;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+
+import java.util.Set;
+
+/**
+ * 项目名: yhlxj2
+ * 文件名: RefreshCacheServiceImpl
+ * 创建者: JavaZou
+ * 创建时间:2024/2/22 16:28
+ */
+@Service
+@RequiredArgsConstructor
+public class RefreshCacheServiceImpl implements RefreshCacheService {
+	private final RedisService redisService;
+
+	@Override
+	public void refreshYhHomePageCache() {
+		Set<String> keys = redisService.keys(RedisService.key.YH_HOME_PAGHE_CACHE.getName() + "*");
+		redisService.del(keys.toArray(String[]::new));
+	}
+}

+ 6 - 1
netflix-service/src/main/java/com/cyksj/service/relation/GroupRelationFrontService.java

@@ -1,6 +1,5 @@
 package com.cyksj.service.relation;
 
-import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.cyksj.model.entity.GroupsRelation;
 import com.cyksj.model.views.RenewalView;
@@ -22,4 +21,10 @@ public interface GroupRelationFrontService {
 	GroupsRelation getSimilarExpiredGroupRelation(Long skuId, Integer days, Integer months, List<Long> errorsRelationIds);
 
 	Page<UserRecommendGoodsFrontView> getRecommendGoodsViews(Boolean isPayNf, List<Long> filter_goods_id, Integer start, Integer limit);
+
+	/**
+	 * 获取车票账号登录 验证码
+	 */
+	String getAiVerifyCode(Long userId, Long relationId, Integer type, Boolean sync) throws Exception;
+
 }

+ 27 - 0
netflix-service/src/main/java/com/cyksj/service/relation/GroupsRelationNetflixService.java

@@ -0,0 +1,27 @@
+package com.cyksj.service.relation;
+
+import cn.hutool.json.JSONObject;
+
+import java.util.Date;
+
+/**
+ * 项目名: yhlxj2
+ * 文件名: GroupsRelationNetflixService
+ * 创建者: JavaZou
+ * 创建时间:2024/6/17 15:44
+ */
+public interface GroupsRelationNetflixService {
+
+	JSONObject setNetflixSeatNum(Integer seatNum, String seatName, String account, String password, Date expiryTime, String code);
+
+	JSONObject setNetflixPin(Long relationId, long userId, String code);
+
+	Integer getPinStatus(String taskId) throws Exception;
+
+	Boolean confirmUpdate(String nfUrl);
+
+	/**
+	 * 定时设置奈飞座位号
+	 */
+	void timingSetNetflix(Integer num, String nickname, String account, String password, Date expiryTime);
+}

+ 131 - 3
netflix-service/src/main/java/com/cyksj/service/relation/impl/GroupRelationFrontServiceImpl.java

@@ -3,21 +3,29 @@ package com.cyksj.service.relation.impl;
 import cn.hutool.core.date.BetweenFormater;
 import cn.hutool.core.date.DateTime;
 import cn.hutool.core.date.DateUtil;
+import cn.hutool.core.lang.Validator;
 import cn.hutool.core.util.StrUtil;
+import cn.hutool.http.HttpRequest;
+import cn.hutool.http.HttpStatus;
+import cn.hutool.http.HttpUtil;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.cyksj.common.exception.BusinessRuntimeException;
+import com.cyksj.common.util.StringUtil;
+import com.cyksj.common.util.TicketCodeCommonUtil;
 import com.cyksj.enums.GatewayApiCode;
+import com.cyksj.mapper.GroupsRelationLoginCodeRecordMapper;
 import com.cyksj.mapper.GroupsRelationMapper;
 import com.cyksj.mapper.UserMapper;
-import com.cyksj.model.entity.CouponUser;
-import com.cyksj.model.entity.GroupsRelation;
-import com.cyksj.model.entity.User;
+import com.cyksj.mapper.sys.SysEmailMapper;
+import com.cyksj.model.entity.*;
 import com.cyksj.model.views.*;
 import com.cyksj.redis.RedisService;
 import com.cyksj.service.chatgpt.ChatGptAuthService;
+import com.cyksj.service.mail.CuiQiuMailService;
 import com.cyksj.service.mange.coupon.CouponCommonService;
 import com.cyksj.service.relation.GroupRelationFrontService;
+import com.cyksj.service.relation.GroupsRelationNetflixService;
 import com.cyksj.service.user.UserBindRelationService;
 import com.ejlchina.searcher.BeanSearcher;
 import com.ejlchina.searcher.param.Operator;
@@ -27,7 +35,9 @@ import lombok.extern.slf4j.Slf4j;
 import org.springframework.stereotype.Service;
 
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 import java.util.stream.Collectors;
 
 /*
@@ -54,6 +64,17 @@ public class GroupRelationFrontServiceImpl implements GroupRelationFrontService
 
 	private final RedisService redisService;
 
+	private final SysEmailMapper sysEmailMapper;
+
+	private final CuiQiuMailService cuiQiuMailService;
+
+	private final GroupsRelationLoginCodeRecordMapper groupsRelationLoginCodeRecordMapper;
+
+	private final GroupsRelationNetflixService groupsRelationNetflixService;
+
+	//脆球邮箱后缀
+	private final static String CUI_QIU_EMAIL_SUFFIX = "@kindvd.com";
+
 	@Override
 	public List<RenewalView> getMyTicket(long userId, Boolean isLoginPopularize) {
 		User u = userMapper.selectById(userId);
@@ -186,4 +207,111 @@ public class GroupRelationFrontServiceImpl implements GroupRelationFrontService
 	public Page<UserRecommendGoodsFrontView> getRecommendGoodsViews(Boolean isPayNf, List<Long> filter_goods_id, Integer start, Integer limit) {
 		return groupsRelationMapper.getRecommendGoodsViews(new Page<>(start, limit),filter_goods_id, isPayNf);
 	}
+
+	@Override
+	public String getAiVerifyCode(Long userId, Long relationId, Integer type, Boolean sync) throws Exception {
+		List<Long> relationUserIdList = userBindRelationService.getRelationUserIdList(userId, null);
+		RenewalView renewalView = beanSearcher.searchFirst(RenewalView.class, MapUtils.builder().field(RenewalView::getUserId, relationUserIdList).op(Operator.InList)
+				.field(RenewalView::getRelationId, relationId).build());
+		if (renewalView == null) {
+			throw BusinessRuntimeException.getInstance("您的车票不存在...");
+		}
+		if (StrUtil.isEmpty(renewalView.getAccount())) {
+			throw BusinessRuntimeException.getInstance("车票未配置账号");
+		}
+		String account = renewalView.getAccount();
+		String password = renewalView.getPassword();
+		if (StrUtil.hasEmpty(account, password)) {
+			throw BusinessRuntimeException.getInstance("您的车票账号密码异常,请联系客服...");
+		}
+		if (renewalView.getAccount().contains(CUI_QIU_EMAIL_SUFFIX)) {
+			return cuiQiuMailService.getVerifyCode(renewalView.getAccount(), renewalView.getGoodsId(), type, sync);
+		}
+		//获取邮箱密码
+		SysEmail sysEmail = sysEmailMapper.selectOne(Wrappers.lambdaQuery(SysEmail.class)
+				.eq(SysEmail::getEmail, account)
+				.last("limit 1"));
+		if (sysEmail == null) {
+			log.info("获取账号:{}验证码异常,未配置对应系统邮箱", account);
+			throw BusinessRuntimeException.getInstance("获取账号验证码异常,请联系客服...");
+		}
+		String url = "http://yinhelx.com/api/controller.php";
+		Map<String, Object> params = new HashMap<>();
+
+		params.put("imap_key", "imap_56568niua@@");
+		params.put("fun", "imap_read");
+		params.put("imap_ip", "yinhelx.com");
+		params.put("port", "143");
+		params.put("username", account);
+		params.put("password", sysEmail.getPassword());
+		params.put("mbox_id", "0");
+		params.put("delete", "0");
+
+		HttpRequest post = HttpUtil.createPost(url);
+		post.form(params);
+		cn.hutool.http.HttpResponse execute = post.execute();
+		if (execute.getStatus() != HttpStatus.HTTP_OK) {
+			throw BusinessRuntimeException.getInstance("获取验证码异常,请联系客服...");
+		}
+		String code = getDifferentGoodsCode(renewalView.getGoodsId(), execute.body(), type, sync);
+		GroupsRelationLoginCodeRecord record = new GroupsRelationLoginCodeRecord();
+		record.setUserId(userId);
+		record.setRelationId(relationId);
+		record.setAccount(renewalView.getAccount());
+		record.setGoodsId(renewalView.getGoodsId());
+		record.setSkuId(renewalView.getSkuId());
+		groupsRelationLoginCodeRecordMapper.insert(record);
+		return code;
+	}
+
+
+	public String getDifferentGoodsCode(Long goodsId, String body, Integer type, Boolean sync) {
+		String code = null;
+		//奈飞
+		if (goodsId == 1) {
+			if (type != null && type == 1) {
+				if (body.contains("輸入此代碼登入") || body.contains("输入此代码登录")) {
+					code = StrUtil.subBetween(body, "輸入此代碼登入", "請在裝置上輸入上");
+					if (StrUtil.isEmpty(code)) {
+						code = StrUtil.subAfter(body, "输入此代码登录", true);
+					}
+				}
+				if (StrUtil.isEmpty(code)) {
+					throw BusinessRuntimeException.getInstance("查询失败,请检查是否发送了登陆码..");
+				}
+			} else {
+				String urlPref = "https://www.netflix.com/account/update-primary-location";
+				code = StrUtil.subBetween(body, "[" + urlPref, "]");
+				if (StrUtil.isEmpty(code)) {
+					urlPref = "https://www.netflix.com/account/travel/verify";
+					code = StrUtil.subBetween(body, "[" + urlPref, "]");
+					if (StrUtil.isEmpty(code)) {
+						throw BusinessRuntimeException.getInstance("获取认证链接失败,请重新获取");
+					}
+				}
+				String url = urlPref + code;
+				//非点击装置同步更新按钮 直接返回链接
+				if (!sync) return url;
+				//失败返回验证链接
+				if (!groupsRelationNetflixService.confirmUpdate(url)) {
+					return url;
+				}
+				return StrUtil.EMPTY;
+			}
+		}
+		//除奈飞
+		if (StrUtil.isEmpty(code)) {
+			code = TicketCodeCommonUtil.getTicketCodeStr(body, goodsId);
+		}
+		int length = 4;
+		if (goodsId == 33l) {
+			length = 6;
+		}
+		code = StringUtil.getVerifyCodePattern(code, length);
+		if (!Validator.isNumber(code)) {
+			log.error("获取账号验证码失败:{}", StrUtil.subSufByLength(code, 512));
+			throw BusinessRuntimeException.getInstance("获取验证码失败,请重新获取..");
+		}
+		return code.trim();
+	}
 }

+ 168 - 0
netflix-service/src/main/java/com/cyksj/service/relation/impl/GroupsRelationNetflixServiceImpl.java

@@ -0,0 +1,168 @@
+package com.cyksj.service.relation.impl;
+
+import cn.hutool.core.date.DateTime;
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.http.HttpUtil;
+import cn.hutool.json.JSONObject;
+import com.cyksj.common.constant.Constant;
+import com.cyksj.common.exception.BusinessRuntimeException;
+import com.cyksj.common.util.IoKit;
+import com.cyksj.common.util.J11HttpC;
+import com.cyksj.common.util.Jsons;
+import com.cyksj.common.util.StringUtil;
+import com.cyksj.mapper.AccountMapper;
+import com.cyksj.mapper.GroupsMapper;
+import com.cyksj.mapper.GroupsRelationMapper;
+import com.cyksj.mapper.UserMapper;
+import com.cyksj.model.entity.Account;
+import com.cyksj.model.entity.GroupsRelation;
+import com.cyksj.model.entity.GroupsTrips;
+import com.cyksj.model.entity.User;
+import com.cyksj.redis.RedisService;
+import com.cyksj.service.relation.GroupsRelationNetflixService;
+import com.cyksj.service.user.UserBindRelationService;
+import com.cyksj.task.JobManager;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+
+import java.net.http.HttpRequest;
+import java.net.http.HttpResponse;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 项目名: yhlxj2
+ * 文件名: GroupsRelationNetflixServiceImpl
+ * 创建者: JavaZou
+ * 创建时间:2024/6/17 15:45
+ */
+@Service
+@RequiredArgsConstructor
+@Slf4j
+public class GroupsRelationNetflixServiceImpl implements GroupsRelationNetflixService {
+	private final UserMapper userMapper;
+
+	private final GroupsRelationMapper relationMapper;
+
+	private final GroupsMapper groupsMapper;
+
+	private final AccountMapper accountMapper;
+
+	private final UserBindRelationService userBindRelationService;
+
+	private final RedisService redisService;
+
+	private final JobManager jobManager;
+
+	@Override
+	public JSONObject setNetflixSeatNum(Integer seatNum, String seatName, String account, String password, Date expiryTime, String code) {
+		JSONObject params = new JSONObject();
+		params.putOpt("username", account);
+		params.putOpt("password", password);
+		params.putOpt("seat_name", seatName);
+		params.putOpt("seat_num", seatNum);
+		params.putOpt("seat_time", expiryTime);
+		if (StrUtil.isNotBlank(code)) {
+			params.putOpt("pin_code", code);
+		}
+		//设置座位
+		String url = Constant.ZHAOJU_MOVIES + "/netflix_set/netflix_seat";
+		log.info("设置账号:{} 奈飞用户:{}座位信息", account, seatName);
+		try {
+			HttpResponse<String> res =
+					J11HttpC.custom()
+							.ofPost()
+							.url(url)
+							.headers(J11HttpC.ReqType.raw_json)
+							.body(HttpRequest.BodyPublishers.ofString(Jsons.toJson(params), IoKit.Charsets.UTF_8.getCharset()))
+							.send(HttpResponse.BodyHandlers.ofString());
+			String body = res.body();
+			JSONObject jsonObject = Jsons.parseObject(body, JSONObject.class);
+			JSONObject data = Jsons.parseObject(jsonObject.get("data"), JSONObject.class);
+			Integer status = data.getInt("status");
+			if (status == 2) {
+				log.error("设置用户:{}奈飞座位号失败", seatName);
+			}
+			return data;
+		} catch (Exception e) {
+			log.error("设置用户:{}奈飞座位号错误,msg:{}", seatName, StringUtil.getErrorText(e));
+		}
+		JSONObject jsonObject = new JSONObject();
+		jsonObject.putOpt("status", 2);
+		return jsonObject;
+	}
+
+	@Override
+	public JSONObject setNetflixPin(Long relationId, long userId, String code) {
+		List<Long> userIdList = userBindRelationService.getRelationUserIdList(userId, null);
+		GroupsRelation relation = relationMapper.selectById(relationId);
+		if (!userIdList.contains(relation.getUserId())) {
+			throw BusinessRuntimeException.getInstance("您车票已失效");
+		}
+		GroupsTrips groupsTrips = groupsMapper.selectById(relation.getGroupsId());
+		Account account = accountMapper.selectById(groupsTrips.getAccountId());
+		if (account.getGoodsId() != 1) {
+			throw BusinessRuntimeException.getInstance("系统错误");
+		}
+		User user = userMapper.selectById(relation.getUserId());
+		return setNetflixSeatNum(relation.getNum(), user.getNickname(), account.getAccount(), account.getPassword(), relation.getExpiryTime(), code);
+	}
+
+	@Override
+	public Integer getPinStatus(String taskId) throws Exception {
+		JSONObject params = new JSONObject();
+		params.putOpt("transId", taskId);
+		//查询任务状态
+		String url = Constant.ZHAOJU_MOVIES + "/netflix_set/netflix_task_status";
+		HttpResponse<String> res =
+				J11HttpC.custom()
+						.ofPost()
+						.url(url)
+						.headers(J11HttpC.ReqType.raw_json)
+						.body(HttpRequest.BodyPublishers.ofString(Jsons.toJson(params), IoKit.Charsets.UTF_8.getCharset()))
+						.send(HttpResponse.BodyHandlers.ofString());
+		String body = res.body();
+		JSONObject jsonObject = Jsons.parseObject(body, JSONObject.class);
+		JSONObject data = Jsons.parseObject(jsonObject.get("data"), JSONObject.class);
+		Integer status = data.getInt("status");
+		return status;
+	}
+
+	@Override
+	public Boolean confirmUpdate(String nfUrl) {
+		JSONObject params = new JSONObject();
+		params.putOpt("url", nfUrl);
+		//确认更新点击
+		String url = Constant.ZHAOJU_MOVIES + "/netflix_set/netflix_primary_action";
+		try {
+			cn.hutool.http.HttpResponse execute = HttpUtil
+					.createPost(url)
+					.body(params.toString(), "application/json")
+					.setConnectionTimeout(30000)
+					.setReadTimeout(30000)
+					.execute();
+			JSONObject resp = Jsons.parseObject(execute.body(), JSONObject.class);
+			return resp.getBool("success");
+		} catch (Exception e) {
+		}
+		return false;
+	}
+
+	/**
+	 * 定时设置座位号
+	 * 30s执行一次
+	 */
+	@Override
+	public void timingSetNetflix(Integer num, String nickname, String account, String password, Date expiryTime) {
+		String key = RedisService.key.NETFLIX_SET_LIMIT_TIME.getName();
+		if (!redisService.setNx(key, 1L, 30L)) {
+			jobManager.addJob(30001, () -> {
+				timingSetNetflix(num, nickname, account, password, expiryTime);
+			});
+		} else {
+			setNetflixSeatNum(num, nickname, account, password, expiryTime, null);
+			log.info("当前时间:{}开始调用设置奈飞座位信息接口", DateTime.now());
+		}
+	}
+}

+ 20 - 9
netflix-web/src/main/java/com/cyksj/web/controller/group/GroupRelationController.java

@@ -18,7 +18,6 @@ import com.cyksj.common.snowflake.Sequence;
 import com.cyksj.common.task.GlobalThreadPoolTaskExecutor;
 import com.cyksj.common.util.GoogleGenerator;
 import com.cyksj.common.util.Jsons;
-import com.cyksj.common.util.StringUtil;
 import com.cyksj.dto.Result;
 import com.cyksj.enums.GatewayResponse;
 import com.cyksj.mapper.*;
@@ -102,6 +101,8 @@ public class GroupRelationController {
 
     private final ChatGptAuthService chatGptAuthService;
 
+    private final TicketPwdViewRecordMapper ticketPwdViewRecordMapper;
+
     private final static Sequence SEQUENCE = new Sequence(0);
 
     @RequestMapping("/get/renewal")
@@ -187,17 +188,19 @@ public class GroupRelationController {
                 .field(GroupsRelationView::getId, relationId).build());
         if (groupsRelationView == null) {
             log.info("userId:{}查看relationId:{}车票不存在", userId, relationId);
-            throw BusinessRuntimeException.getInstance(I18nMessageUtil.getI18nMsg("sys_error"));
+            throw BusinessRuntimeException.getInstance("该车票已不存在");
         }
-        if (groupsRelationView.getAccountId() == null) throw BusinessRuntimeException.getInstance(I18nMessageUtil.getI18nMsg("account_not_set"));
-        if (groupRelationFrontService == null) throw BusinessRuntimeException.getInstance(I18nMessageUtil.getI18nMsg("sys_error"));
-        ChatGptPwdViewRecord viewRecord = new ChatGptPwdViewRecord();
+        if (groupsRelationView.getAccountId() == null) throw BusinessRuntimeException.getInstance("该车队未配置账号");
+        if (groupRelationFrontService == null) throw BusinessRuntimeException.getInstance("车票已不存在");
+        TicketPwdViewRecord viewRecord = new TicketPwdViewRecord();
         viewRecord.setUserId(userId);
         viewRecord.setRelationId(relationId);
         viewRecord.setSkuId(groupsRelationView.getSkuId());
-        viewRecord.setOperateLocation(StringUtil.getRealAddressByIP(ServletUtil.getClientIP(request)));
-        chatGptPwdViewRecordMapper.insert(viewRecord);
-        if (StrUtil.isEmpty(groupsRelationView.getApiSecret())) {
+        viewRecord.setOperateLocation(ServletUtil.getClientIP(request));
+        viewRecord.setAccount(groupsRelationView.getTripsAccount());
+        viewRecord.setPassword(groupsRelationView.getTripsPassword());
+        ticketPwdViewRecordMapper.insert(viewRecord);
+        if (groupsRelationView.getGoodsId() == 18 && StrUtil.isEmpty(groupsRelationView.getApiSecret())) {
             THREAD_POOL.execute(() -> {
                 //车队所有人查看密码
                 Integer num = groupsRelationView.getGtNum();
@@ -223,7 +226,6 @@ public class GroupRelationController {
         }
         return GatewayResponse.SUCCESS.newBuilder().toResult(groupsRelationView.getTripsPassword());
     }
-
     /**
      * 获取AI类 ChatGPT产品谷歌验证码
      */
@@ -518,4 +520,13 @@ public class GroupRelationController {
         });
         return GatewayResponse.SUCCESS.newBuilder().toResult(page);
     }
+
+    /**
+     * 读取车票账号登录验证码
+     */
+    @GetMapping("/get/verifyCode/{relationId}")
+    public Result<String> getAiVerifyCode(@PathVariable Long relationId, Integer type, @RequestParam(defaultValue = "0") Boolean sync) throws Exception {
+        long userId = StpUserUtil.getLoginIdAsLong();
+        return GatewayResponse.SUCCESS.newBuilder().toResult(groupRelationFrontService.getAiVerifyCode(userId, relationId, type, sync));
+    }
 }

+ 1 - 0
netflix-web/src/main/java/com/cyksj/web/controller/manage/CmsOrderController.java

@@ -1,5 +1,6 @@
 package com.cyksj.web.controller.manage;
 
+import com.cyksj.web.util.StpAbroadUtil;
 import cn.dev33.satoken.annotation.SaCheckPermission;
 import com.cyksj.web.util.StpAbroadUtil;
 import cn.hutool.core.date.DateTime;

+ 37 - 4
netflix-web/src/main/java/com/cyksj/web/controller/manage/account/CmsAccountController.java

@@ -1,5 +1,6 @@
 package com.cyksj.web.controller.manage.account;
 
+import com.cyksj.common.constant.Constant;
 import com.cyksj.web.util.StpAbroadUtil;
 import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.date.DateTime;
@@ -56,10 +57,7 @@ import org.springframework.web.multipart.MultipartFile;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import java.io.IOException;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Optional;
-import java.util.Set;
+import java.util.*;
 import java.util.stream.Collectors;
 
 /**
@@ -104,6 +102,8 @@ public class CmsAccountController {
 
 	private final SysEmailMapper sysEmailMapper;
 
+	private final GoodsDonSkuMapper goodsDonSkuMapper;
+
 	@GetMapping("/get")
 	public Result<SearchResult<AccountView>> get(Long userId, String showId, String nickName, String submitAccount, String expiryStartTime, String expiryEndTime, Boolean expiredAll, Boolean existsExpired, Boolean existsExpiredToday, Integer noChangeMonths) {
 		MapBuilder mapBuilder = MapUtils.flatBuilder(request.getParameterMap());
@@ -871,6 +871,39 @@ public class CmsAccountController {
 		return GatewayResponse.SUCCESS.newBuilder().toResult(search);
 	}
 
+	/**
+	 * 用户车看车票账号密码 记录列表
+	 */
+	@GetMapping("/get/ticket/pwd/view")
+	public Result<SearchResult<TicketPwdViewRecordView>> getTicketPwdView() {
+		SearchResult<TicketPwdViewRecordView> search = beanSearcher.search(TicketPwdViewRecordView.class, MapUtils.flatBuilder(request.getParameterMap())
+				.orderBy(TicketPwdViewRecordView::getId).desc()
+				.build());
+		return GatewayResponse.SUCCESS.newBuilder().toResult(search);
+	}
+
+	/**
+	 * MidJourney、ChatGPT年付 ChatGpt独立月付未续费列表
+	 */
+	@GetMapping("/get/specific/account")
+	public Result<SearchResult<AccountSpecificView>> getSpecificAccount() {
+		//获取MidJourney、ChatGPT年付 ChatGpt独立月付 规格id
+		Long chatGptPlusGid = Constant.AI_goodsIds.get(0);
+		//年付
+		List<Long> yearSkuIds = goodsDonSkuMapper.getSpecificSkuIdsByGoodsIds(Constant.AI_goodsIds, 12);
+		//ChatGpt Plus 独立月付
+		List<Long> monthSkuIds = goodsDonSkuMapper.getSpecificSkuIdsByGoodsId(chatGptPlusGid, 1, 1);
+		Collection<Long> skuIds = CollUtil.addAll(yearSkuIds, monthSkuIds);
+		if (skuIds.isEmpty()) {
+			return GatewayResponse.SUCCESS.newBuilder().toResult();
+		}
+		SearchResult<AccountSpecificView> search = beanSearcher.search(AccountSpecificView.class, MapUtils.flatBuilder(request.getParameterMap())
+				.put("condition", String.format("and (select count(*) from groups_relation gr where gr.groups_id = gt.id and gr.user_id != 0 and gr.status in ('validity','outside')) > 0"))
+				.field(AccountSpecificView::getExpiryTime, DateTime.now()).op(Operator.LessThan)
+				.field(AccountSpecificView::getSkuId, skuIds).op(Operator.InList).build());
+		return GatewayResponse.SUCCESS.newBuilder().toResult(search);
+	}
+
 	/**
 	 * 批量导入系统邮箱
 	 */

+ 139 - 137
netflix-web/src/main/java/com/cyksj/web/controller/manage/goods/CmsGoodsDonController.java

@@ -9,15 +9,16 @@ import com.cyksj.common.util.Jsons;
 import com.cyksj.dto.Result;
 import com.cyksj.enums.BusinessType;
 import com.cyksj.enums.GatewayResponse;
-import com.cyksj.model.entity.GoodsDiscountPlusPurchaseRelation;
 import com.cyksj.model.entity.GoodsDon;
 import com.cyksj.model.entity.GoodsDonSku;
 import com.cyksj.model.manage.request.ReqGoodsSpuInsert;
 import com.cyksj.model.manage.views.GoodsDonViewer;
-import com.cyksj.redis.RedisService;
 import com.cyksj.service.mange.CmsGoodsDonService;
+import com.cyksj.service.mange.RefreshCacheService;
 import com.ejlchina.searcher.BeanSearcher;
 import com.ejlchina.searcher.SearchResult;
+import com.ejlchina.searcher.param.Operator;
+import com.ejlchina.searcher.util.MapBuilder;
 import com.ejlchina.searcher.util.MapUtils;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
@@ -40,13 +41,13 @@ import java.util.Set;
 @RequestMapping("/manage/goods")
 public class CmsGoodsDonController {
 
-    private final HttpServletRequest request;
+	private final HttpServletRequest request;
 
-    private final BeanSearcher beanSearcher;
+	private final BeanSearcher beanSearcher;
 
-    private final CmsGoodsDonService goodsDonService;
+	private final CmsGoodsDonService goodsDonService;
 
-    private final RedisService redisService;
+	private final RefreshCacheService refreshCacheService;
 
     @GetMapping("/get")
     public Result<SearchResult<GoodsDon>> get(){
@@ -56,135 +57,136 @@ public class CmsGoodsDonController {
         return GatewayResponse.SUCCESS.newBuilder().toResult(search);
     }
 
-    /**
-     * 商品详情
-     */
-    @GetMapping("/get/{id}")
-    public Result<GoodsDonViewer> getById(@PathVariable Long id) throws Exception {
-        GoodsDonViewer goodsDonViewer = beanSearcher.searchFirst(GoodsDonViewer.class, MapUtils.builder().field(GoodsDonViewer::getId, id).build());
-        if (StrUtil.isNotBlank(goodsDonViewer.getRecommendGoods())) {
-            goodsDonViewer.setRecommendGoodsList(Jsons.parseList(goodsDonViewer.getRecommendGoods(), Long.class));
-        }
-        List<GoodsDonSku> goodsDonSkus = beanSearcher.searchAll(GoodsDonSku.class, MapUtils.builder().field(GoodsDonSku::getGoodsId, id).build());
-        if (goodsDonViewer.getType() == 1) {
-            goodsDonSkus.forEach(sku -> {
-                if (sku.getIsDp()) {
-                    sku.setDpSku(beanSearcher.searchAll(GoodsDiscountPlusPurchaseRelation.class, MapUtils.builder()
-                            .field(GoodsDiscountPlusPurchaseRelation::getSkuId, sku.getId())
-                            .build()));
-                }
-            });
-        }
-        goodsDonViewer.setSkus(goodsDonSkus);
-        return GatewayResponse.SUCCESS.newBuilder().toResult(goodsDonViewer);
-    }
-
-    /**
-     * 商品规格详情
-     */
-    @GetMapping("/get/sku/{id}")
-    public Result<List<GoodsDonSku>> getSkuById(@PathVariable Long id, HttpServletRequest request) {
-        List<GoodsDonSku> goodsDonSkus = beanSearcher.searchAll(GoodsDonSku.class, MapUtils.flatBuilder(request.getParameterMap()).field(GoodsDonSku::getGoodsId, id).build());
-        return GatewayResponse.SUCCESS.newBuilder().toResult(goodsDonSkus);
-    }
-
-    /**
-     * 新增 商品spu
-     */
-    @PostMapping(value = "/post")
-    @Log(module = "平台管理/新增平台", businessType = BusinessType.POST, isSaveRequestData = true)
-    public Result<Long> spuInsert(@Validated @RequestBody ReqGoodsSpuInsert spu) throws Exception {
-        // 新增商品
-        GoodsDon goods = new GoodsDon();
-        BeanUtil.copyProperties(spu, goods);
-        if (StrUtil.isNotEmpty(goods.getRecommendTitle())) {
-            if (CollUtil.isEmpty(spu.getRecommendGoodsList())) {
-                throw BusinessRuntimeException.getInstance("请选择推荐的对应平台");
-            }
-        }
-        goodsDonService.save(goods);
-        Set<String> keys = redisService.keys(RedisService.key.YH_HOME_PAGHE_CACHE.getName() + "*");
-        redisService.del(keys.toArray(String[]::new));
-        return GatewayResponse.SUCCESS.newBuilder().toResult(goods.getId());
-    }
-
-    /**
-     * 修改 商品spu
-     */
-    @PutMapping(value = "/update")
-    @Log(module = "平台管理/编辑平台", businessType = BusinessType.PUT, isSaveRequestData = true)
-    public Result<String> spuUpdate(@Validated @RequestBody ReqGoodsSpuInsert spu) throws Exception{
-        GoodsDon goods = new GoodsDon();
-        BeanUtil.copyProperties(spu,goods);
-        if (spu.getSpecialType() == null) {
-            goods.setSpecialType(null);
-        }
-        if (StrUtil.isNotEmpty(goods.getRecommendTitle())) {
-            if (CollUtil.isEmpty(spu.getRecommendGoodsList())) {
-                throw BusinessRuntimeException.getInstance("请选择推荐的对应平台");
-            }
-        }
-        if (CollUtil.isNotEmpty(spu.getRecommendGoodsList())) {
-            Set<Long> re_goodsIds = new HashSet<>(spu.getRecommendGoodsList());
-            //去除自己
-            re_goodsIds.remove(spu.getId());
-            goods.setRecommendGoods(Jsons.toJson(re_goodsIds));
-        }
-        if (StrUtil.isEmpty(goods.getRecommendTitle())) {
-            goods.setRecommendTitle(null);
-        }
-        if (StrUtil.isEmpty(goods.getVideo())) {
-            goods.setVideo(null);
-        }
-        if (CollUtil.isNotEmpty(spu.getRecommendGoodsList())) {
-            Set<Long> re_goodsIds = new HashSet<>(spu.getRecommendGoodsList());
-            //去除自己
-            re_goodsIds.remove(spu.getId());
-            goods.setRecommendGoods(Jsons.toJson(re_goodsIds));
-        }
-        goodsDonService.updateById(goods);
-        Set<String> keys = redisService.keys(RedisService.key.YH_HOME_PAGHE_CACHE.getName() + "*");
-        redisService.del(keys.toArray(String[]::new));
-        return GatewayResponse.SUCCESS.newBuilder().toResult();
-    }
-
-
-    @PutMapping("/put/status/{id}")
-    @Log(module = "平台管理/平台上下架", businessType = BusinessType.PUT, isSaveRequestData = true, isSaveResponseData = true)
-    public Result<Boolean> updateStatus(@PathVariable Long id) {
-        GoodsDon goods = goodsDonService.getById(id);
-        if (goods == null) {
-            throw BusinessRuntimeException.getInstance("平台不存在");
-        }
-        goods.setStatus(!goods.getStatus());
-        goodsDonService.updateById(goods);
-        Set<String> keys = redisService.keys(RedisService.key.YH_HOME_PAGHE_CACHE.getName() + "*");
-        redisService.del(keys.toArray(String[]::new));
-        return GatewayResponse.SUCCESS.newBuilder().toResult(goods.getStatus());
-    }
-
-    @DeleteMapping("/delete/{id}")
-    @Log(module = "平台管理/删除平台", businessType = BusinessType.DELETE, isSaveRequestData = true, isSaveResponseData = true)
-    public Result<Long> deleteById(@PathVariable Long id) {
-        GoodsDon goods = goodsDonService.getById(id);
-        if (goods == null) {
-            throw BusinessRuntimeException.getInstance("平台不存在");
-        }
-        goods.setDeleted(false);
-        goodsDonService.updateById(goods);
-        Set<String> keys = redisService.keys(RedisService.key.YH_HOME_PAGHE_CACHE.getName() + "*");
-        redisService.del(keys.toArray(String[]::new));
-        return GatewayResponse.SUCCESS.newBuilder().toResult(id);
-    }
-
-    /**
-     * 获取所有平台列表
-     */
-    @GetMapping("/get/all")
-    public Result<List<GoodsDon>> getAllGoodsList() {
-        List<GoodsDon> goodsDons = beanSearcher.searchAll(GoodsDon.class, MapUtils.flatBuilder(request.getParameterMap())
-                .field(GoodsDon::getDeleted,true)
-                .onlySelect(GoodsDon::getId, GoodsDon::getCategory, GoodsDon::getType, GoodsDon::getTitle).build());
-        return GatewayResponse.SUCCESS.newBuilder().toResult(goodsDons);
-    }
+	/**
+	 * 商品详情
+	 */
+	@GetMapping("/get/{id}")
+	public Result<GoodsDonViewer> getById(@PathVariable Long id) throws Exception {
+		GoodsDonViewer goodsDonViewer = beanSearcher.searchFirst(GoodsDonViewer.class, MapUtils.builder().field(GoodsDonViewer::getId, id).build());
+		if (StrUtil.isNotBlank(goodsDonViewer.getRecommendGoods())) {
+			goodsDonViewer.setRecommendGoodsList(Jsons.parseList(goodsDonViewer.getRecommendGoods(), Long.class));
+		}
+		return GatewayResponse.SUCCESS.newBuilder().toResult(goodsDonViewer);
+	}
+
+	/**
+	 * 商品规格详情
+	 */
+	@GetMapping("/get/sku/{id}")
+	public Result<List<GoodsDonSku>> getSkuById(@PathVariable Long id, HttpServletRequest request) {
+		List<GoodsDonSku> goodsDonSkus = beanSearcher.searchAll(GoodsDonSku.class, MapUtils.flatBuilder(request.getParameterMap()).field(GoodsDonSku::getGoodsId, id)
+				.orderBy(GoodsDonSku::getSorted).asc()
+				.build());
+		return GatewayResponse.SUCCESS.newBuilder().toResult(goodsDonSkus);
+	}
+
+	/**
+	 * 新增 商品spu
+	 */
+	@PostMapping(value = "/post")
+	@Log(module = "平台管理/新增平台", businessType = BusinessType.POST, isSaveRequestData = true)
+	public Result<Long> spuInsert(@Validated @RequestBody ReqGoodsSpuInsert spu) throws Exception {
+		// 新增商品
+		GoodsDon goods = new GoodsDon();
+		if (spu.getSecondType() == null) {
+			spu.setSecondType(2);
+		}
+		BeanUtil.copyProperties(spu, goods);
+		if (StrUtil.isNotEmpty(goods.getRecommendTitle())) {
+			if (CollUtil.isEmpty(spu.getRecommendGoodsList())) {
+				throw BusinessRuntimeException.getInstance("请选择推荐的对应平台");
+			}
+		}
+		goodsDonService.save(goods);
+		refreshCacheService.refreshYhHomePageCache();
+		return GatewayResponse.SUCCESS.newBuilder().toResult(goods.getId());
+	}
+
+	/**
+	 * 修改 商品spu
+	 */
+	@PutMapping(value = "/update")
+	@Log(module = "平台管理/编辑平台", businessType = BusinessType.PUT, isSaveRequestData = true)
+	public Result<String> spuUpdate(@Validated @RequestBody ReqGoodsSpuInsert spu) throws Exception{
+		GoodsDon goods = new GoodsDon();
+		BeanUtil.copyProperties(spu,goods);
+		if (spu.getSpecialType() == null) {
+			goods.setSpecialType(null);
+		}
+		if (StrUtil.isNotEmpty(goods.getRecommendTitle())) {
+			if (CollUtil.isEmpty(spu.getRecommendGoodsList())) {
+				throw BusinessRuntimeException.getInstance("请选择推荐的对应平台");
+			}
+		}
+		if (CollUtil.isNotEmpty(spu.getRecommendGoodsList())) {
+			Set<Long> re_goodsIds = new HashSet<>(spu.getRecommendGoodsList());
+			//去除自己
+			re_goodsIds.remove(spu.getId());
+			goods.setRecommendGoods(Jsons.toJson(re_goodsIds));
+		}
+		if (StrUtil.isEmpty(goods.getRecommendTitle())) {
+			goods.setRecommendTitle(null);
+		}
+		if (StrUtil.isEmpty(goods.getVideo())) {
+			goods.setVideo(null);
+		}
+		if (CollUtil.isNotEmpty(spu.getRecommendGoodsList())) {
+			Set<Long> re_goodsIds = new HashSet<>(spu.getRecommendGoodsList());
+			//去除自己
+			re_goodsIds.remove(spu.getId());
+			goods.setRecommendGoods(Jsons.toJson(re_goodsIds));
+		}
+		goodsDonService.updateById(goods);
+		refreshCacheService.refreshYhHomePageCache();
+		return GatewayResponse.SUCCESS.newBuilder().toResult();
+	}
+
+
+	@PutMapping("/put/status/{id}")
+	@Log(module = "平台管理/平台上下架", businessType = BusinessType.PUT, isSaveRequestData = true, isSaveResponseData = true)
+	public Result<Boolean> updateStatus(@PathVariable Long id) {
+		GoodsDon goods = goodsDonService.getById(id);
+		if (goods == null) {
+			throw BusinessRuntimeException.getInstance("平台不存在");
+		}
+		goods.setStatus(!goods.getStatus());
+		goodsDonService.updateById(goods);
+		refreshCacheService.refreshYhHomePageCache();
+		return GatewayResponse.SUCCESS.newBuilder().toResult(goods.getStatus());
+	}
+
+	@DeleteMapping("/delete/{id}")
+	@Log(module = "平台管理/删除平台", businessType = BusinessType.DELETE, isSaveRequestData = true, isSaveResponseData = true)
+	public Result<Long> deleteById(@PathVariable Long id) {
+		GoodsDon goods = goodsDonService.getById(id);
+		if (goods == null) {
+			throw BusinessRuntimeException.getInstance("平台不存在");
+		}
+		goods.setDeleted(false);
+		goodsDonService.updateById(goods);
+		refreshCacheService.refreshYhHomePageCache();
+		return GatewayResponse.SUCCESS.newBuilder().toResult(id);
+	}
+
+	/**
+	 * 获取所有平台列表
+	 */
+	@GetMapping("/get/all")
+	public Result<List<GoodsDon>> getAllGoodsList(Boolean isNoBuyout) {
+		MapBuilder mapBuilder = MapUtils.flatBuilder(request.getParameterMap());
+		//过滤买断制 平台
+		String conditionSql;
+		if (isNoBuyout != null && isNoBuyout) {
+			mapBuilder.field(GoodsDon::getSpecialType).op(Operator.IsNull);
+			conditionSql = "(select count(*) from goods_don_sku sku where sku.goods_id = g.id and sku.months = 300) = 0";
+		} else {
+			conditionSql = "(special_type is null or special_type != 'giftCard')";
+		}
+		conditionSql += "  and exists (select id from goods_don_sku sku where sku.goods_id = g.id limit 1)";
+		List<GoodsDon> goodsDons = beanSearcher.searchAll(GoodsDon.class, mapBuilder
+				.put("condition", conditionSql)
+				.field(GoodsDon::getDeleted, true)
+				.onlySelect(GoodsDon::getId, GoodsDon::getCategory, GoodsDon::getType, GoodsDon::getTitle, GoodsDon::getSecondType).build());
+		return GatewayResponse.SUCCESS.newBuilder().toResult(goodsDons);
+	}
 }

+ 100 - 21
netflix-web/src/main/java/com/cyksj/web/controller/manage/goods/CmsGoodsDonSkuController.java

@@ -1,22 +1,26 @@
 package com.cyksj.web.controller.manage.goods;
 
+import cn.hutool.core.util.StrUtil;
 import com.baomidou.mybatisplus.core.toolkit.Assert;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.cyksj.common.annotation.Log;
 import com.cyksj.common.exception.BusinessRuntimeException;
+import com.cyksj.common.util.Jsons;
 import com.cyksj.dto.Result;
 import com.cyksj.enums.BusinessType;
 import com.cyksj.enums.GatewayResponse;
+import com.cyksj.model.entity.GoodsDiscountPlusPurchaseRelation;
 import com.cyksj.model.entity.GoodsDon;
 import com.cyksj.model.entity.GoodsDonSku;
-import com.cyksj.model.entity.GoodsDonSpec;
 import com.cyksj.model.manage.request.ReqGoodsSkuInsert;
 import com.cyksj.model.request.CombinationSkuReq;
-import com.cyksj.model.views.GoodsDonSkuView;
-import com.cyksj.redis.RedisService;
 import com.cyksj.service.mange.CmsGoodsDonService;
 import com.cyksj.service.mange.CmsGoodsDonSkuService;
 import com.cyksj.service.mange.CmsGoodsDonSpecService;
+import com.cyksj.service.mange.RefreshCacheService;
 import com.ejlchina.searcher.BeanSearcher;
+import com.ejlchina.searcher.SearchResult;
+import com.ejlchina.searcher.util.MapBuilder;
 import com.ejlchina.searcher.util.MapUtils;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
@@ -25,6 +29,7 @@ import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
 
 import javax.servlet.http.HttpServletRequest;
+import java.math.BigDecimal;
 import java.util.List;
 import java.util.Set;
 
@@ -49,7 +54,7 @@ public class CmsGoodsDonSkuController {
 
     private final HttpServletRequest request;
 
-    private final RedisService redisService;
+    private final RefreshCacheService refreshCacheService;
 
 
     /**
@@ -59,7 +64,7 @@ public class CmsGoodsDonSkuController {
     @Log(module = "平台管理/新增商品sku&spec", businessType = BusinessType.POST, isSaveRequestData = true)
     public Result<String> skuInsert(@Validated @RequestBody ReqGoodsSkuInsert insert) throws Exception{
         goodsDonSpecService.insertOrUpdateSkuSpec(insert, false);
-
+        refreshCacheService.refreshYhHomePageCache();
         return GatewayResponse.SUCCESS.newBuilder().toResult();
     }
 
@@ -68,13 +73,8 @@ public class CmsGoodsDonSkuController {
      */
     @PutMapping("/update/spec")
     public Result<String> updateGoodsSpec(@Validated @RequestBody ReqGoodsSkuInsert insert) throws Exception {
-        Long id = insert.getId();
-        Assert.notNull(id, "规格属性id不存在");
-        GoodsDonSpec spec = goodsDonSpecService.getById(id);
-        if (spec == null || !spec.getGoodsId().equals(insert.getGoodsId())) {
-            throw BusinessRuntimeException.getInstance("规格不存在");
-        }
         goodsDonSpecService.insertOrUpdateSkuSpec(insert, true);
+        refreshCacheService.refreshYhHomePageCache();
         return GatewayResponse.SUCCESS.newBuilder().toResult();
     }
 
@@ -93,9 +93,8 @@ public class CmsGoodsDonSkuController {
         goodsDonSpecService.skuAppend(insert, goods);
         //给平台更新额外属性
         goodsDonService.updateGoodsSkuPrice(goods.getId(), goods);
-        Set<String> keys = redisService.keys(RedisService.key.YH_HOME_PAGHE_CACHE.getName() + "*");
-        redisService.del(keys.toArray(String[]::new));
-       return GatewayResponse.SUCCESS.newBuilder().toResult();
+        refreshCacheService.refreshYhHomePageCache();
+        return GatewayResponse.SUCCESS.newBuilder().toResult();
     }
 
     /**
@@ -104,7 +103,10 @@ public class CmsGoodsDonSkuController {
     @Transactional(rollbackFor = Throwable.class)
     @PutMapping(value = "/update")
     @Log(module = "平台管理/编辑规格", businessType = BusinessType.PUT, isSaveRequestData = true)
-    public Result<String> skuUpdate(@RequestBody GoodsDonSku sku){
+    public Result<String> skuUpdate(@RequestBody GoodsDonSku sku) throws Exception {
+        Long skuId = sku.getId();
+        GoodsDonSku dbSku = goodsDonSkuService.getById(skuId);
+        Assert.notNull(dbSku, "规格不存在");
         Long goodsId = sku.getGoodsId();
         GoodsDon goods = goodsDonService.getById(goodsId);
         if (goods.getType() == 1) {
@@ -119,13 +121,42 @@ public class CmsGoodsDonSkuController {
         if (sku.getDays() == null) {
             sku.setDays(null);
         }
+        if (sku.getMjRelaxNum() == null) {
+            sku.setMjRelaxNum(null);
+        }
+        String specificGoodsIds = sku.getSpecificGoodsIds();
+        if (StrUtil.isEmpty(specificGoodsIds)) {
+            sku.setSpecificPrice(BigDecimal.ZERO);
+        } else {
+            Set<Long> specificGids = Jsons.parseSet(specificGoodsIds, Long.class);
+            if (specificGids.isEmpty()) {
+                sku.setSpecificPrice(BigDecimal.ZERO);
+            } else {
+                Integer count = goodsDonService.count(Wrappers.lambdaQuery(GoodsDon.class)
+                        .in(GoodsDon::getId, specificGids)
+                        .eq(GoodsDon::getStatus, true)
+                        .eq(GoodsDon::getDeleted, true));
+                if (count != specificGids.size()) {
+                    throw BusinessRuntimeException.getInstance("存在被删除或已下架的平台");
+                }
+                BigDecimal specificPrice = sku.getSpecificPrice();
+                if (specificPrice == null || specificPrice.compareTo(BigDecimal.ZERO) <= 0) {
+                    throw BusinessRuntimeException.getInstance("请输入正确的特定价格");
+                }
+            }
+        }
         //优惠加购
         goodsDonSkuService.handleDiscountPurchaseGoods(sku, sku.getDpSku());
+
+        String benefitsList = sku.getBenefitsList();
+        if (StrUtil.isNotBlank(benefitsList)) {
+            Set<GoodsDonSku> benefitsSkuIds = Jsons.parseSet(benefitsList, GoodsDonSku.class);
+            sku.setBenefitsList(Jsons.toJson(benefitsSkuIds));
+        }
         goodsDonSkuService.saveOrUpdate(sku);
         //给平台更新额外属性
         goodsDonService.updateGoodsSkuPrice(sku.getGoodsId(), null);
-        Set<String> keys = redisService.keys(RedisService.key.YH_HOME_PAGHE_CACHE.getName() + "*");
-        redisService.del(keys.toArray(String[]::new));
+        refreshCacheService.refreshYhHomePageCache();
         return GatewayResponse.SUCCESS.newBuilder().toResult();
     }
 
@@ -142,8 +173,7 @@ public class CmsGoodsDonSkuController {
         goodsDonSkuService.handleDiscountPurchaseGoods(sku, null);
         goodsDonSkuService.removeById(skuId);
         goodsDonService.updateGoodsSkuPrice(sku.getGoodsId(), null);
-        Set<String> keys = redisService.keys(RedisService.key.YH_HOME_PAGHE_CACHE.getName() + "*");
-        redisService.del(keys.toArray(String[]::new));
+        refreshCacheService.refreshYhHomePageCache();
         return GatewayResponse.SUCCESS.newBuilder().toResult();
     }
 
@@ -161,8 +191,57 @@ public class CmsGoodsDonSkuController {
      * 获取平台规格列表
      */
     @GetMapping("/get/list")
-    public Result<List<GoodsDonSkuView>> getGoodsSkuList() {
-        List<GoodsDonSkuView> skuViewList = beanSearcher.searchAll(GoodsDonSkuView.class, MapUtils.flatBuilder(request.getParameterMap()).build());
+    public Result<SearchResult<GoodsDonSku>> getGoodsSkuList(@RequestParam(defaultValue = "0") Boolean filterPack) {
+        MapBuilder builder = MapUtils.flatBuilder(request.getParameterMap());
+        if (filterPack) {
+            String condition = " spec_json not like '%套餐%'";
+            builder.put("condition", condition);
+        }
+        SearchResult<GoodsDonSku> skuViewList = beanSearcher.search(GoodsDonSku.class, builder.build());
+        skuViewList.getDataList().forEach(sku->{
+            if (sku.getIsDp()) {
+                sku.setDpSku(beanSearcher.searchAll(GoodsDiscountPlusPurchaseRelation.class, MapUtils.builder()
+                        .field(GoodsDiscountPlusPurchaseRelation::getSkuId, sku.getId())
+                        .build()));
+            }
+        });
         return GatewayResponse.SUCCESS.newBuilder().toResult(skuViewList);
     }
+
+    /**
+     * 批量上架
+     */
+    @PutMapping("/batch/update/status/{goodsId}")
+    public Result<String> batchUpdateStatus(@PathVariable Long goodsId, @RequestBody List<Long> skuIds) {
+        GoodsDon goodsDon = goodsDonService.getById(goodsId);
+        if (goodsDon == null || !goodsDon.getDeleted()) {
+            throw BusinessRuntimeException.getInstance("商品不存在");
+        }
+        boolean update = goodsDonSkuService.update(null, Wrappers.lambdaUpdate(GoodsDonSku.class)
+                .set(GoodsDonSku::getStatus, true)
+                .eq(GoodsDonSku::getGoodsId, goodsId)
+                .in(GoodsDonSku::getId, skuIds)
+                .eq(GoodsDonSku::getStatus, false));
+        if (update) {
+            goodsDonService.updateGoodsSkuPrice(goodsId, null);
+            refreshCacheService.refreshYhHomePageCache();
+        }
+        return GatewayResponse.SUCCESS.newBuilder().toResult();
+    }
+
+
+    /**
+     * 规格排序
+     */
+    @PutMapping("/sorted")
+    public Result<String> sorted(@RequestBody GoodsDonSku sku) {
+        Long id = sku.getId();
+        Integer sorted = sku.getSorted();
+        Assert.notNull(id, "请选择指定的规格");
+        goodsDonSkuService.update(null, Wrappers.lambdaUpdate(GoodsDonSku.class)
+                .eq(GoodsDonSku::getId, id)
+                .set(GoodsDonSku::getSorted, sorted));
+        refreshCacheService.refreshYhHomePageCache();
+        return GatewayResponse.SUCCESS.newBuilder().toResult();
+    }
 }

+ 83 - 0
netflix-web/src/main/java/com/cyksj/web/controller/manage/group/CmsGroupRelationController.java

@@ -1,9 +1,12 @@
 package com.cyksj.web.controller.manage.group;
 
+import cn.hutool.core.collection.CollUtil;
 import com.cyksj.web.util.StpAbroadUtil;
 import cn.hutool.core.date.DateTime;
 import cn.hutool.core.date.DateUtil;
 import cn.hutool.core.lang.Assert;
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.core.util.StrUtil;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.cyksj.common.annotation.NoSubmit;
 import com.cyksj.common.constant.Constant;
@@ -11,13 +14,18 @@ import com.cyksj.common.exception.BusinessRuntimeException;
 import com.cyksj.dto.Result;
 import com.cyksj.enums.GatewayResponse;
 import com.cyksj.mapper.GoodsDonSkuMapper;
+import com.cyksj.mapper.GroupsRelationIndependentRenewMapper;
 import com.cyksj.mapper.GroupsRelationMapper;
 import com.cyksj.mapper.OrderDonMapper;
 import com.cyksj.mapper.manage.cms.CmsUserMapper;
 import com.cyksj.model.entity.*;
+import com.cyksj.model.manage.views.AccountView;
 import com.cyksj.model.manage.views.GroupsRelationBackView;
+import com.cyksj.model.views.GroupsRelationIndependentView;
 import com.cyksj.model.views.GroupsRelationRechargeView;
+import com.cyksj.model.views.OrderDonRenewView;
 import com.cyksj.service.scheduler.SchedulerService;
+import com.cyksj.web.util.StpAbroadUtil;
 import com.ejlchina.searcher.BeanSearcher;
 import com.ejlchina.searcher.SearchResult;
 import com.ejlchina.searcher.param.Operator;
@@ -29,6 +37,8 @@ import org.springframework.web.bind.annotation.*;
 
 import javax.servlet.http.HttpServletRequest;
 import java.util.List;
+import java.util.Optional;
+import java.util.stream.Collectors;
 
 /**
  * @author chan
@@ -54,6 +64,8 @@ public class CmsGroupRelationController {
 
     private final GoodsDonSkuMapper goodsDonSkuMapper;
 
+    private final GroupsRelationIndependentRenewMapper groupsRelationIndependentRenewMapper;
+
     @GetMapping("/get")
     public Result<List<GroupsRelationBackView>> get(){
         List<GroupsRelationBackView> search = beanSearcher.searchAll(GroupsRelationBackView.class, MapUtils.flatBuilder(request.getParameterMap())
@@ -150,4 +162,75 @@ public class CmsGroupRelationController {
         }
         return GatewayResponse.SUCCESS.newBuilder().toResult(false);
     }
+
+    /**
+     * Chat GPT独立规格续费 列表
+     */
+    @GetMapping("/get/chatGPT/independent/renew")
+    public Result<SearchResult<GroupsRelationIndependentView>> getIndependentRenew(String account) {
+        String condition = " o.sku_id in (select id from goods_don_sku sku where sku.goods_id in (18,26) and sku.num = 1)" +
+                " and o.status not in ('close','noPayment','refund') and o.order_type = 2";
+        if (StrUtil.isNotEmpty(account)) {
+            List<AccountView> dbAccounts = beanSearcher.searchAll(AccountView.class, MapUtils.builder().field(AccountView::getAccount, account).op(Operator.Contain).build());
+            if (CollUtil.isNotEmpty(dbAccounts)) {
+                String collect = dbAccounts.stream().map(e -> String.valueOf(e.getGroupsId())).collect(Collectors.joining(","));
+                condition += String.format(" and groups_id in (%s)", collect);
+            }
+        }
+        SearchResult<GroupsRelationIndependentView> search = beanSearcher.search(GroupsRelationIndependentView.class, MapUtils.flatBuilder(request.getParameterMap())
+                .put("condition", condition)
+                .build());
+        return GatewayResponse.SUCCESS.newBuilder().toResult(search);
+    }
+
+    /**
+     * 编辑车票独立续费状态
+     */
+    @PutMapping("/update/independent/renew/status")
+    public Result<String> updateRenewStatus(@RequestBody GroupsRelationIndependentView view) {
+        long adminId = StpUtil.getLoginIdAsLong();
+        Long relationId = view.getRelationId();
+        Long userId = view.getUserId();
+        Boolean isRenew = view.getIsRenew();
+        if (ObjectUtil.hasEmpty(relationId, userId, isRenew)) {
+            throw BusinessRuntimeException.getInstance("参数错误");
+        }
+        GroupsRelationIndependentRenew groupsRelationIndependentRenew = Optional.ofNullable(groupsRelationIndependentRenewMapper.selectOne(Wrappers.lambdaQuery(GroupsRelationIndependentRenew.class)
+                .eq(GroupsRelationIndependentRenew::getOrderId, view.getOrderId())
+                .eq(GroupsRelationIndependentRenew::getUserId, userId)
+                .eq(GroupsRelationIndependentRenew::getRelationId, relationId).last("limit 1"))).orElse(new GroupsRelationIndependentRenew());
+        CmsUser cmsUser = cmsUserMapper.selectById(adminId);
+        if (cmsUser != null) {
+            groupsRelationIndependentRenew.setOperator(cmsUser.getNickname());
+        }
+        groupsRelationIndependentRenew.setOrderId(view.getOrderId());
+
+        if (groupsRelationIndependentRenew.getId() == null) {
+            groupsRelationIndependentRenew.setRelationId(relationId);
+            groupsRelationIndependentRenew.setUserId(userId);
+            groupsRelationIndependentRenew.setIsRenew(isRenew);
+            groupsRelationIndependentRenewMapper.insert(groupsRelationIndependentRenew);
+        } else {
+            groupsRelationIndependentRenew.setIsRenew(isRenew);
+            groupsRelationIndependentRenewMapper.updateById(groupsRelationIndependentRenew);
+        }
+        return GatewayResponse.SUCCESS.newBuilder().toResult();
+    }
+
+    /**
+     * 独立账号续费记录
+     */
+    @GetMapping("/get/independent/renew/record")
+    public Result<SearchResult<OrderDonRenewView>> getIndependentRenewRecord(Long userId, Long relationId) {
+        if (ObjectUtil.hasEmpty(relationId, userId)) {
+            throw BusinessRuntimeException.getInstance("参数错误");
+        }
+        SearchResult<OrderDonRenewView> search = beanSearcher.search(OrderDonRenewView.class, MapUtils.flatBuilder(request.getParameterMap())
+                .field(OrderDonRenewView::getUserId, userId)
+                .field(OrderDonRenewView::getRelationId, relationId)
+                .field(OrderDonRenewView::getOrderType, 2)
+                .field(OrderDonRenewView::getStatus, Constant.noOrderAllStatus).op(Operator.NotIn)
+                .build());
+        return GatewayResponse.SUCCESS.newBuilder().toResult(search);
+    }
 }

+ 0 - 1
netflix-web/src/main/java/com/cyksj/web/controller/manage/shop/ShopConfigController.java

@@ -1,6 +1,5 @@
 package com.cyksj.web.controller.manage.shop;
 
-import cn.dev33.satoken.annotation.SaCheckPermission;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.cyksj.dto.Result;
 import com.cyksj.enums.GatewayResponse;