Bläddra i källkod

Merge branch 'mj' into dev

zwhui 2 år sedan
förälder
incheckning
bd39737e25
61 ändrade filer med 2204 tillägg och 66 borttagningar
  1. 5 0
      netflix-common/src/main/java/com/cyksj/common/constant/Constant.java
  2. 13 0
      netflix-dao/src/main/java/com/cyksj/mapper/ChatgptUserCarUsedRecordMapper.java
  3. 3 0
      netflix-dao/src/main/java/com/cyksj/mapper/GroupsRelationMapper.java
  4. 11 0
      netflix-dao/src/main/java/com/cyksj/mapper/MidjourneyAccountMapper.java
  5. 11 0
      netflix-dao/src/main/java/com/cyksj/mapper/MidjourneyUserConversationMapper.java
  6. 11 0
      netflix-dao/src/main/java/com/cyksj/mapper/MidjourneyUserMapper.java
  7. 11 0
      netflix-dao/src/main/java/com/cyksj/mapper/UpgradeOrderDonMapper.java
  8. 11 0
      netflix-dao/src/main/java/com/cyksj/mapper/UpgradePackageMapper.java
  9. 3 0
      netflix-dao/src/main/java/com/cyksj/mapper/corp/CorpUserAuthMapper.java
  10. 21 0
      netflix-dao/src/main/java/com/cyksj/model/dto/BlendDimensions.java
  11. 18 0
      netflix-dao/src/main/java/com/cyksj/model/dto/SubmitActionDTO.java
  12. 23 0
      netflix-dao/src/main/java/com/cyksj/model/dto/SubmitBlendDTO.java
  13. 16 0
      netflix-dao/src/main/java/com/cyksj/model/dto/SubmitDescribeDTO.java
  14. 24 0
      netflix-dao/src/main/java/com/cyksj/model/dto/SubmitImagineDTO.java
  15. 27 0
      netflix-dao/src/main/java/com/cyksj/model/dto/SubmitModalDTO.java
  16. 16 0
      netflix-dao/src/main/java/com/cyksj/model/dto/SubmitShortenDTO.java
  17. 40 0
      netflix-dao/src/main/java/com/cyksj/model/entity/ChatgptUserCarUsedRecord.java
  18. 5 0
      netflix-dao/src/main/java/com/cyksj/model/entity/CorpCustomerAcquisitionLinkPopularize.java
  19. 10 0
      netflix-dao/src/main/java/com/cyksj/model/entity/GoodsDonSku.java
  20. 54 0
      netflix-dao/src/main/java/com/cyksj/model/entity/MidjourneyAccount.java
  21. 60 0
      netflix-dao/src/main/java/com/cyksj/model/entity/MidjourneyUser.java
  22. 90 0
      netflix-dao/src/main/java/com/cyksj/model/entity/MidjourneyUserConversation.java
  23. 121 0
      netflix-dao/src/main/java/com/cyksj/model/entity/UpgradeOrderDon.java
  24. 53 0
      netflix-dao/src/main/java/com/cyksj/model/entity/UpgradePackage.java
  25. 6 0
      netflix-dao/src/main/java/com/cyksj/model/manage/views/UserView.java
  26. 5 0
      netflix-dao/src/main/java/com/cyksj/model/request/OrderPayRequest.java
  27. 6 0
      netflix-dao/src/main/java/com/cyksj/model/request/corp/CorpXmlMessage.java
  28. 6 0
      netflix-dao/src/main/java/com/cyksj/model/views/CorpCustomerAcquisitionLinkPopularizeView.java
  29. 76 0
      netflix-dao/src/main/java/com/cyksj/model/views/MidjourneyAccountView.java
  30. 71 0
      netflix-dao/src/main/java/com/cyksj/model/views/UpgradePackageView.java
  31. 13 0
      netflix-dao/src/main/resources/mapper/GroupRelationMapper.xml
  32. 1 1
      netflix-service/src/main/java/com/cyksj/service/chatgpt/ChatGptAccountService.java
  33. 44 7
      netflix-service/src/main/java/com/cyksj/service/chatgpt/impl/ChatGptAccountServiceImpl.java
  34. 81 3
      netflix-service/src/main/java/com/cyksj/service/corp/impl/CorpEventActionServiceImpl.java
  35. 9 0
      netflix-service/src/main/java/com/cyksj/service/corp/impl/CorpServiceImpl.java
  36. 1 2
      netflix-service/src/main/java/com/cyksj/service/corp/impl/WxCorpOpsImpl.java
  37. 2 0
      netflix-service/src/main/java/com/cyksj/service/corp/msg/CorpEventActionService.java
  38. 6 1
      netflix-service/src/main/java/com/cyksj/service/exchange/impl/ExchangeCodeServiceImpl.java
  39. 6 1
      netflix-service/src/main/java/com/cyksj/service/mange/group/CmsGroupServiceImpl.java
  40. 19 4
      netflix-service/src/main/java/com/cyksj/service/mange/impl/CmsOrderDonServiceImpl.java
  41. 11 0
      netflix-service/src/main/java/com/cyksj/service/mange/upgrade/UpgradePackageService.java
  42. 19 0
      netflix-service/src/main/java/com/cyksj/service/mange/upgrade/impl/UpgradePackageServiceImpl.java
  43. 27 0
      netflix-service/src/main/java/com/cyksj/service/midjourney/MidjourneyAccountService.java
  44. 29 0
      netflix-service/src/main/java/com/cyksj/service/midjourney/MidjourneyService.java
  45. 267 0
      netflix-service/src/main/java/com/cyksj/service/midjourney/impl/MidJourneyAccountServiceImpl.java
  46. 265 0
      netflix-service/src/main/java/com/cyksj/service/midjourney/impl/MidjourneyServiceImpl.java
  47. 4 0
      netflix-service/src/main/java/com/cyksj/service/order/OrderDonService.java
  48. 73 1
      netflix-service/src/main/java/com/cyksj/service/order/impl/OrderDonServiceImpl.java
  49. 4 1
      netflix-service/src/main/java/com/cyksj/service/relation/GroupRelationFrontService.java
  50. 20 13
      netflix-service/src/main/java/com/cyksj/service/relation/impl/GroupRelationFrontServiceImpl.java
  51. 10 3
      netflix-web/src/main/java/com/cyksj/web/controller/group/GroupRelationController.java
  52. 15 4
      netflix-web/src/main/java/com/cyksj/web/controller/manage/CmsUserController.java
  53. 16 14
      netflix-web/src/main/java/com/cyksj/web/controller/manage/corp/WxCorpController.java
  54. 106 0
      netflix-web/src/main/java/com/cyksj/web/controller/manage/mj/MidJourneyController.java
  55. 121 0
      netflix-web/src/main/java/com/cyksj/web/controller/manage/upgrade/UpgradePackageController.java
  56. 161 0
      netflix-web/src/main/java/com/cyksj/web/controller/mirror/MidjourneyController.java
  57. 19 6
      netflix-web/src/main/java/com/cyksj/web/controller/mirror/MirrorController.java
  58. 19 0
      netflix-web/src/main/java/com/cyksj/web/controller/payment/OrderController.java
  59. 0 0
      netflix-web/src/main/resources/application-dev.yml
  60. 0 0
      netflix-web/src/main/resources/application-prd.yml
  61. 9 5
      netflix-web/src/main/resources/application-pre.yml

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

@@ -301,4 +301,9 @@ public interface Constant {
 	 * 设备客服活码用户分销专用
 	 */
 	Long EP_AC_CODE_ID = 7l;
+
+	/**
+	 * 有效获客
+	 */
+	String CUSTOMER_EFFECTIVE = "customer_effective";
 }

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

@@ -0,0 +1,13 @@
+package com.cyksj.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.cyksj.model.entity.ChatgptUserCarUsedRecord;
+
+/**
+ * 项目名: yhlxj2
+ * 文件名: ChatgptUserCarUsedRecordMapper
+ * 创建者: JavaZou
+ * 创建时间:2024/4/19 17:55
+ */
+public interface ChatgptUserCarUsedRecordMapper extends BaseMapper<ChatgptUserCarUsedRecord> {
+}

+ 3 - 0
netflix-dao/src/main/java/com/cyksj/mapper/GroupsRelationMapper.java

@@ -8,6 +8,7 @@ import com.cyksj.model.entity.PhoneCode;
 import com.cyksj.model.manage.views.GroupsRelationBackView;
 import com.cyksj.model.manage.views.GroupsRelationView;
 import com.cyksj.model.views.GroupsRelationUserView;
+import com.cyksj.model.views.RenewalView;
 import com.cyksj.model.views.UserRecommendGoodsFrontView;
 import org.apache.ibatis.annotations.Param;
 import org.apache.ibatis.annotations.Update;
@@ -67,4 +68,6 @@ public interface GroupsRelationMapper extends BaseMapper<GroupsRelation> {
 	GroupsRelationBackView getGroupRelationAccountView(Long relationId);
 
 	PhoneCode getAreaPhoneByUserId(Long userId);
+
+	List<RenewalView> getUserHasPayGoods(@Param("list") List<Long> userIds, @Param("now") DateTime now);
 }

+ 11 - 0
netflix-dao/src/main/java/com/cyksj/mapper/MidjourneyAccountMapper.java

@@ -0,0 +1,11 @@
+package com.cyksj.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.cyksj.model.entity.MidjourneyAccount;
+
+/**
+ * @author zwhui
+ * @date 2024/4/12 15:51
+ */
+public interface MidjourneyAccountMapper extends BaseMapper<MidjourneyAccount> {
+}

+ 11 - 0
netflix-dao/src/main/java/com/cyksj/mapper/MidjourneyUserConversationMapper.java

@@ -0,0 +1,11 @@
+package com.cyksj.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.cyksj.model.entity.MidjourneyUserConversation;
+
+/**
+ * @author zwhui
+ * @date 2024/4/23 16:03
+ */
+public interface MidjourneyUserConversationMapper extends BaseMapper<MidjourneyUserConversation> {
+}

+ 11 - 0
netflix-dao/src/main/java/com/cyksj/mapper/MidjourneyUserMapper.java

@@ -0,0 +1,11 @@
+package com.cyksj.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.cyksj.model.entity.MidjourneyUser;
+
+/**
+ * @author zwhui
+ * @date 2024/4/16 17:46
+ */
+public interface MidjourneyUserMapper extends BaseMapper<MidjourneyUser> {
+}

+ 11 - 0
netflix-dao/src/main/java/com/cyksj/mapper/UpgradeOrderDonMapper.java

@@ -0,0 +1,11 @@
+package com.cyksj.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.cyksj.model.entity.UpgradeOrderDon;
+
+/**
+ * @author zwhui
+ * @date 2024/4/24 17:29
+ */
+public interface UpgradeOrderDonMapper extends BaseMapper<UpgradeOrderDon> {
+}

+ 11 - 0
netflix-dao/src/main/java/com/cyksj/mapper/UpgradePackageMapper.java

@@ -0,0 +1,11 @@
+package com.cyksj.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.cyksj.model.entity.UpgradePackage;
+
+/**
+ * @author zwhui
+ * @date 2024/4/24 15:03
+ */
+public interface UpgradePackageMapper extends BaseMapper<UpgradePackage> {
+}

+ 3 - 0
netflix-dao/src/main/java/com/cyksj/mapper/corp/CorpUserAuthMapper.java

@@ -2,10 +2,13 @@ package com.cyksj.mapper.corp;
 
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.cyksj.model.entity.CorpUserAuth;
+import org.apache.ibatis.annotations.Select;
 
 /**
  * @author chan
  * @date 2022/4/8 上午11:06
  */
 public interface CorpUserAuthMapper extends BaseMapper<CorpUserAuth> {
+	@Select("select unionid from corp_user where id = (select corp_user_id from corp_user_auth where external_userid = #{externalUserId} limit 1) limit 1")
+	String getUnionIdByExternalUserId(String externalUserId);
 }

+ 21 - 0
netflix-dao/src/main/java/com/cyksj/model/dto/BlendDimensions.java

@@ -0,0 +1,21 @@
+package com.cyksj.model.dto;
+
+
+import lombok.Getter;
+
+@Getter
+public enum BlendDimensions {
+
+	PORTRAIT("2:3"),
+
+	SQUARE("1:1"),
+
+	LANDSCAPE("3:2");
+
+	private final String value;
+
+	BlendDimensions(String value) {
+		this.value = value;
+	}
+
+}

+ 18 - 0
netflix-dao/src/main/java/com/cyksj/model/dto/SubmitActionDTO.java

@@ -0,0 +1,18 @@
+package com.cyksj.model.dto;
+
+import lombok.Data;
+
+/**
+ * @author zwhui
+ * @date 2024/4/24 10:56
+ */
+@Data
+public class SubmitActionDTO {
+
+    private Long taskId;
+
+    /**
+     * 动作标识,示例值(MJ::JOB::upsample::2::3dbbd469-36af-4a0f-8f02-df6c579e7011)
+     */
+    private String customId;
+}

+ 23 - 0
netflix-dao/src/main/java/com/cyksj/model/dto/SubmitBlendDTO.java

@@ -0,0 +1,23 @@
+package com.cyksj.model.dto;
+
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * @author zwhui
+ * @date 2024/4/23 13:49
+ */
+@Data
+public class SubmitBlendDTO {
+
+	/**
+	 * base64
+	 */
+	private List<String> base64Array;
+
+	/**
+	 * 比例: PORTRAIT(2:3); SQUARE(1:1); LANDSCAPE(3:2)
+	 */
+	private BlendDimensions dimensions = BlendDimensions.SQUARE;
+}

+ 16 - 0
netflix-dao/src/main/java/com/cyksj/model/dto/SubmitDescribeDTO.java

@@ -0,0 +1,16 @@
+package com.cyksj.model.dto;
+
+import lombok.Data;
+
+/**
+ * @author zwhui
+ * @date 2024/4/23 13:49
+ */
+@Data
+public class SubmitDescribeDTO {
+
+	/**
+	 * base64
+	 */
+	private String base64;
+}

+ 24 - 0
netflix-dao/src/main/java/com/cyksj/model/dto/SubmitImagineDTO.java

@@ -0,0 +1,24 @@
+package com.cyksj.model.dto;
+
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * @author zwhui
+ * @date 2024/4/23 13:49
+ */
+@Data
+public class SubmitImagineDTO {
+
+    /**
+     * 提示词
+     */
+    private String prompt;
+
+    /**
+     * 垫图base64数组
+     */
+    private List<String> base64Array;
+
+}

+ 27 - 0
netflix-dao/src/main/java/com/cyksj/model/dto/SubmitModalDTO.java

@@ -0,0 +1,27 @@
+package com.cyksj.model.dto;
+
+import lombok.Data;
+
+/**
+ * @author zwhui
+ * @date 2024/4/23 18:04
+ */
+@Data
+public class SubmitModalDTO {
+
+    /**
+     * 局部重绘base64
+     */
+    private String maskBase64;
+
+    /**
+     * 提示词
+     */
+    private String prompt;
+
+    /**
+     * 任务id
+     */
+    private Long taskId;
+
+}

+ 16 - 0
netflix-dao/src/main/java/com/cyksj/model/dto/SubmitShortenDTO.java

@@ -0,0 +1,16 @@
+package com.cyksj.model.dto;
+
+import lombok.Data;
+
+/**
+ * @author zwhui
+ * @date 2024/4/23 18:07
+ */
+@Data
+public class SubmitShortenDTO {
+
+    /**
+     * 提示词
+     */
+    private String prompt;
+}

+ 40 - 0
netflix-dao/src/main/java/com/cyksj/model/entity/ChatgptUserCarUsedRecord.java

@@ -0,0 +1,40 @@
+package com.cyksj.model.entity;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * 项目名: yhlxj2
+ * 文件名: ChatgptUserCarUsedRecord
+ * 创建者: JavaZou
+ * 创建时间:2024/4/19 17:54
+ */
+@TableName("chatgpt_user_car_used_record")
+@Getter
+@Setter
+public class ChatgptUserCarUsedRecord extends BaseEntity{
+
+	private String carId;
+
+	@TableField("userToken")
+	private String userToken;
+
+	/**
+	 * gpt3.5使用次数
+	 */
+	private Integer gpt;
+
+
+	/**
+	 * gpt4s使用次数
+	 */
+	private Integer gptFour;
+
+	/**
+	 * true用户次数限制
+	 */
+	private Boolean isUserLimit;
+
+}

+ 5 - 0
netflix-dao/src/main/java/com/cyksj/model/entity/CorpCustomerAcquisitionLinkPopularize.java

@@ -44,4 +44,9 @@ public class CorpCustomerAcquisitionLinkPopularize extends BaseEntity {
     @DbIgnore
     private String url;
 
+    /**
+     * 是否监听微信客户发起会话事件 才回传
+     */
+    private Boolean isChat;
+
 }

+ 10 - 0
netflix-dao/src/main/java/com/cyksj/model/entity/GoodsDonSku.java

@@ -178,6 +178,16 @@ public class GoodsDonSku extends BaseEntity {
      */
     private Long gptLimitTime;
 
+    /**
+     * mj fast次数
+     */
+    private Integer mjFastNum;
+
+    /**
+     * mj relax次数
+     */
+    private Integer mjRelaxNum;
+
     /**
      * 特定价格
      */

+ 54 - 0
netflix-dao/src/main/java/com/cyksj/model/entity/MidjourneyAccount.java

@@ -0,0 +1,54 @@
+package com.cyksj.model.entity;
+
+import com.ejlchina.searcher.bean.SearchBean;
+import lombok.Data;
+
+/**
+ * @author zwhui
+ * @date 2024/4/12 10:52
+ */
+@Data
+@SearchBean(tables = "midjourney_account")
+public class MidjourneyAccount extends BaseEntity{
+
+    /**
+     * 账号id
+     */
+    private Long accountId;
+
+    /**
+     * 状态 true有效 false无效
+     */
+    private Boolean status;
+
+    /**
+     * 服务器id
+     */
+    private Long guildId;
+
+    /**
+     * 频道id
+     */
+    private Long channelId;
+
+    /**
+     * user_token
+     */
+    private String userToken;
+
+    /**
+     * plus服务实例id
+     */
+    private Long instanceId;
+
+    /**
+     * fast剩余时间
+     */
+    private String fastRemainTime;
+
+    /**
+     * 备注
+     */
+    private String remark;
+
+}

+ 60 - 0
netflix-dao/src/main/java/com/cyksj/model/entity/MidjourneyUser.java

@@ -0,0 +1,60 @@
+package com.cyksj.model.entity;
+
+/**
+ * @author zwhui
+ * @date 2024/4/16 17:01
+ */
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.ejlchina.searcher.bean.SearchBean;
+import lombok.Data;
+
+import java.util.Date;
+
+@Data
+@SearchBean(tables = "midjourney_user")
+public class MidjourneyUser extends BaseEntity{
+
+    /**
+     * 名称
+     */
+    private String name;
+
+    /**
+     * 头像
+     */
+    private String img;
+
+    /**
+     * 用户凭证
+     */
+    @TableField("userToken")
+    private String userToken;
+
+    /**
+     * 过期时间
+     */
+    @TableField("expireTime")
+    private Date expireTime;
+
+    /**
+     * 车票id
+     */
+    @TableField("relationId")
+    private Long relationId;
+
+    /**
+     * mj fast次数
+     */
+    private Integer mjFastNum;
+
+    /**
+     * mj relax次数
+     */
+    private Integer mjRelaxNum;
+
+    /**
+     * 当前模式 1:fast 2:relax
+     */
+    private Integer mode;
+}

+ 90 - 0
netflix-dao/src/main/java/com/cyksj/model/entity/MidjourneyUserConversation.java

@@ -0,0 +1,90 @@
+package com.cyksj.model.entity;
+
+import com.ejlchina.searcher.bean.SearchBean;
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+
+/**
+ * @author zwhui
+ * @date 2024/4/23 11:10
+ */
+@Data
+@Accessors(chain = true)
+@SearchBean(tables = "midjourney_user_conversation")
+public class MidjourneyUserConversation extends BaseEntity implements Serializable {
+
+    private Long userId;
+
+    /**
+     * plus服务任务id
+     */
+    private Long taskId;
+
+    /**
+     * IMAGINE,UPSCALE,VARIATION,ZOOM,PAN,DESCRIBE,BLEND,SHORTEN
+     */
+    private String action;
+
+    /**
+     * 频道id
+     */
+    private Long channelId;
+
+    /**
+     * plus服务实例id
+     */
+    private Long instanceId;
+
+    /**
+     * 模式 1:fast 2:relax
+     */
+    private Integer mode;
+
+    /**
+     * 开始时间
+     */
+    private Long startTime;
+
+    /**
+     * 完成时间
+     */
+    private Long finishTime;
+
+    /**
+     * 提示词
+     */
+    private String prompt;
+
+    /**
+     * 描述
+     */
+    private String description;
+
+    /**
+     * 任务状态,可用值:IN_PROGRESS,FAILURE,SUCCESS,CANCEL
+     */
+    private String status;
+
+    /**
+     * 失败原因
+     */
+    private String failReason;
+
+    /**
+     * 进度
+     */
+    private String progress;
+
+    /**
+     * 图片地址
+     */
+    private String imageUrl;
+
+    /**
+     * 按钮
+     */
+    private String buttons;
+
+}

+ 121 - 0
netflix-dao/src/main/java/com/cyksj/model/entity/UpgradeOrderDon.java

@@ -0,0 +1,121 @@
+package com.cyksj.model.entity;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.Getter;
+
+import java.math.BigDecimal;
+import java.util.Arrays;
+import java.util.Date;
+
+/**
+ * @author zwhui
+ * @date 2024/4/24 17:08
+ */
+@Data
+public class UpgradeOrderDon extends BaseEntity {
+    /**
+     * 订单编号
+     */
+    private String orderNo;
+
+    /**
+     * 商品id
+     */
+    private Long goodsId;
+
+    /**
+     * 套餐id
+     */
+    private Long packageId;
+
+    /**
+     * 用户id
+     */
+    private Long userId;
+
+    /**
+     * 原订单号
+     */
+    private Long originalOrderId;
+
+    /**
+     * 金额
+     */
+    private BigDecimal money;
+
+
+    /**
+     * 余额支付
+     */
+    private BigDecimal balance;
+
+    /**
+     * 退款金额
+     */
+    private BigDecimal refundMoney;
+
+    /**
+     * 退款余额
+     */
+    private BigDecimal refundBalance;
+
+    /**
+     * 退款原因
+     */
+    private String refundDesc;
+
+    /**
+     * 支付时间
+     */
+    private Date payTime;
+
+    private Status status;
+
+    private Type type;
+
+    public enum Status {
+        /**
+         * 订单状态
+         */
+        close("已关闭"),
+        noPayment("待付款"),
+        hasPayment("已付款"),
+        transport("已发货"),
+        received("已签收"),
+        complete("已完成"),
+        refund("已退款"),
+        ;
+
+        private String desc;
+
+        Status(String desc) {
+            this.desc = desc;
+        }
+
+        public String getDesc() {
+            return desc;
+        }
+    }
+
+    @Getter
+    @AllArgsConstructor
+    public enum Type{
+        WeChat("wechat","微信"),
+        ALI_PAY("zfb","支付宝"),
+        EX_CODE("exchange_code","兑换码"),
+        LOTTERY("lottery","抽奖"),
+        EQUIPMENT("equipment", "实物设备分销"),
+        PAY_EQUIPMENT("pay_equipment", "自购设备"),
+        BALANCE("balance", "余额支付"),
+        PAYPAL("paypal","paypal支付"),
+        STRIPE("stripe","stripe支付")
+        ;
+        String type;
+        String desc;
+
+        public static UpgradeOrderDon.Type getType(String type) {
+            return Arrays.stream(UpgradeOrderDon.Type.values()).filter(tp -> tp.getType().equals(type)).findFirst().orElse(ALI_PAY);
+        }
+    }
+}

+ 53 - 0
netflix-dao/src/main/java/com/cyksj/model/entity/UpgradePackage.java

@@ -0,0 +1,53 @@
+package com.cyksj.model.entity;
+
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+/**
+ * @author zwhui
+ * @date 2024/4/24 14:54
+ */
+@Data
+public class UpgradePackage extends BaseEntity{
+
+    /**
+     * 套餐名称
+     */
+    private String name;
+
+    /**
+     * 商品id
+     */
+    private Long goodsId;
+
+    /**
+     * 商品规格id
+     */
+    private Long skuId;
+
+    /**
+     * 套餐价格
+     */
+    private BigDecimal price;
+
+    /**
+     * 数量
+     */
+    private Integer num;
+
+    /**
+     * 备注
+     */
+    private String remark;
+
+    /**
+     * true 上架 / false 下架
+     */
+    private Boolean status;
+
+    /**
+     * true 存在 / false 删除
+     */
+    private Boolean deleted;
+}

+ 6 - 0
netflix-dao/src/main/java/com/cyksj/model/manage/views/UserView.java

@@ -187,4 +187,10 @@ public class UserView {
 
     @DbField("u.is_google")
     private Boolean isGoogle;
+
+    /**
+     * 是否实名
+     */
+    @DbIgnore
+    private Boolean isCert;
 }

+ 5 - 0
netflix-dao/src/main/java/com/cyksj/model/request/OrderPayRequest.java

@@ -165,4 +165,9 @@ public class OrderPayRequest {
      * 百亿补贴规格id
      */
     private Long subsidyId;
+
+    /**
+     * 套餐id
+     */
+    private Long packageId;
 }

+ 6 - 0
netflix-dao/src/main/java/com/cyksj/model/request/corp/CorpXmlMessage.java

@@ -236,6 +236,12 @@ public class CorpXmlMessage implements Serializable {
 	@JacksonXmlProperty(localName = "ChatId")
 	private String chatId;
 
+	/**
+	 * 获客链接ID
+	 */
+	@JacksonXmlProperty(localName = "LinkId")
+	private String LinkId;
+
 
 	public static CorpXmlMessage fromXml(String xml) {
 		//修改微信变态的消息内容格式,方便解析

+ 6 - 0
netflix-dao/src/main/java/com/cyksj/model/views/CorpCustomerAcquisitionLinkPopularizeView.java

@@ -61,6 +61,12 @@ public class CorpCustomerAcquisitionLinkPopularizeView {
 	@DbField("cap.time")
 	private Long time;
 
+	/**
+	 * 是否监听微信客户发起会话事件 才回传
+	 */
+	@DbField("cap.is_chat")
+	private Boolean isChat;
+
 	@DbField("cap.created_time")
 	private Date createdTime;
 }

+ 76 - 0
netflix-dao/src/main/java/com/cyksj/model/views/MidjourneyAccountView.java

@@ -0,0 +1,76 @@
+package com.cyksj.model.views;
+
+import com.cyksj.model.entity.GroupsTrips;
+import com.ejlchina.searcher.bean.DbField;
+import com.ejlchina.searcher.bean.DbIgnore;
+import com.ejlchina.searcher.bean.SearchBean;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.math.BigDecimal;
+import java.util.Date;
+
+/**
+ * @author zwhui
+ * @date 2024/4/16 16:04
+ */
+@Getter
+@Setter
+@SearchBean(tables = "midjourney_account ma left join account a on ma.account_id = a.id",
+        where = ":extra_sql:")
+public class MidjourneyAccountView {
+    @DbField("ma.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;
+
+    /**
+     * 状态 true有效 false无效
+     */
+    @DbField("ma.status")
+    private Boolean status;
+
+    /**
+     * 服务器id
+     */
+    @DbField("ma.guild_id")
+    private Long guildId;
+
+    /**
+     * 频道id
+     */
+    @DbField("ma.channel_id")
+    private Long channelId;
+
+    /**
+     * user_token
+     */
+    @DbField("ma.user_token")
+    private String userToken;
+
+    /**
+     * fast剩余时间
+     */
+    @DbField("ma.fast_remain_time")
+    private String fastRemainTime;
+
+    /**
+     * 账号备注
+     */
+    @DbField("ma.remark")
+    private String remark;
+
+    @DbField("ma.created_time")
+    private Date createdTime;
+
+}

+ 71 - 0
netflix-dao/src/main/java/com/cyksj/model/views/UpgradePackageView.java

@@ -0,0 +1,71 @@
+package com.cyksj.model.views;
+
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.ejlchina.searcher.bean.DbField;
+import com.ejlchina.searcher.bean.SearchBean;
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+/**
+ * @author zwhui
+ * @date 2024/4/24 15:20
+ */
+@Data
+@SearchBean(tables = "upgrade_package up left join goods g on up.goods_id = g.id", where = "deleted = true")
+public class UpgradePackageView {
+
+    /**
+     * 套餐名称
+     */
+    @DbField("up.name")
+    private String name;
+
+    /**
+     * 商品id
+     */
+    @DbField("up.goods_id")
+    private Long goodsId;
+
+    /**
+     * 商品名称
+     */
+    @DbField("g.title")
+    private String goodsName;
+
+    /**
+     * 商品规格id
+     */
+    @DbField("up.sku_id")
+    private Long skuId;
+
+    /**
+     * 套餐价格
+     */
+    @DbField("up.price")
+    private BigDecimal price;
+
+    /**
+     * 数量
+     */
+    @DbField("up.num")
+    private Integer num;
+
+    /**
+     * 备注
+     */
+    @DbField("up.remark")
+    private String remark;
+
+    /**
+     * true 上架 / false 下架
+     */
+    @DbField("up.status")
+    private Boolean status;
+
+    /**
+     * true 存在 / false 删除
+     */
+    @DbField("up.deleted")
+    private Boolean deleted;
+}

+ 13 - 0
netflix-dao/src/main/resources/mapper/GroupRelationMapper.xml

@@ -321,4 +321,17 @@
               where id = #{userId} limit 1) s
                  left join phone_code pc on pc.phone = s.phone
     </select>
+
+    <select id="getUserHasPayGoods" resultType="com.cyksj.model.views.RenewalView">
+        select g.id as goods_id,g.title,g.logo from (select distinct groups_id from groups_relation where status in
+        ('validity', 'outside') and (expiry_time is null
+        or
+        expiry_time > #{now}) and user_id != 0 and user_id in <foreach
+            collection="list" item="item" open="(" separator="," close=")">
+        #{item}
+    </foreach> ) gr inner join groups_trips gt on gt.id = gr.groups_id
+        inner join goods_don_sku sku on sku.id = gt.sku_id inner join goods_don g on g.id = sku.goods_id
+        group by g.id,g.title,g.logo
+        order by goods_id
+    </select>
 </mapper>

+ 1 - 1
netflix-service/src/main/java/com/cyksj/service/chatgpt/ChatGptAccountService.java

@@ -57,7 +57,7 @@ public interface ChatGptAccountService {
 
     ChatgptUser getCarChatGptUserWithToken(String userToken);
 
-    Set<ChatgptCarInfoView> getCarInfoList(String userToken);
+    Set<ChatgptCarInfoView> getCarInfoList(String userToken, Integer limit, Boolean isPlus);
 
     ChatGptUserView getUserInfo(long userId, Long relationId);
 

+ 44 - 7
netflix-service/src/main/java/com/cyksj/service/chatgpt/impl/ChatGptAccountServiceImpl.java

@@ -92,6 +92,8 @@ public class ChatGptAccountServiceImpl implements ChatGptAccountService {
 
     private final ChatgptUserTokenPrepareMapper chatgptUserTokenPrepareMapper;
 
+    private final ChatgptUserCarUsedRecordMapper chatgptUserCarUsedRecordMapper;
+
     @Override
     public String addAccount(Account account) {
         if (isAccountExists(account)) {
@@ -211,6 +213,7 @@ public class ChatGptAccountServiceImpl implements ChatGptAccountService {
         GroupsRelation groupsRelation = getGroupsRelation(userId, relationId);
         GroupsTrips groupsTrips = getGroupsTrips(groupsRelation);
         GoodsDonSku goodsDonSku = skuMapper.selectById(groupsTrips.getSkuId());
+        log.info("用户:{},所在车次:{},座位id:{},在{}获取跳转GPT镜像的登录url", userId, groupsTrips.getId(), relationId, DateTime.now());
 
         if (goodsDonSku != null && goodsDonSku.getIsMirror()) {
             ChatgptUser chatgptUser = getChatgptUser(userId, relationId, groupsRelation, groupsTrips, goodsDonSku);
@@ -237,7 +240,9 @@ public class ChatGptAccountServiceImpl implements ChatGptAccountService {
         GoodsDonSku goodsDonSku = skuMapper.selectById(groupsTrips.getSkuId());
         if (goodsDonSku != null && goodsDonSku.getIsMirror() && goodsDonSku.getIsCar()) {
             ChatgptUser chatgptUser = getChatgptCarUser(userId, relationId, groupsRelation, goodsDonSku);
-            return CAR_GPT_DOMAIN + "/auth/logintoken?carid=" + carId + "&usertoken=" + chatgptUser.getUserToken();
+            String DOMAIN = "https://chat.galaxydvd.com";
+            log.info("domain:{},用户:{},所在车次:{},座位id:{},在{}获取跳转GPT镜像的登录url", DOMAIN, userId, groupsTrips.getId(), relationId, DateTime.now());
+            return DOMAIN + "/auth/logintoken?carid=" + carId + "&usertoken=" + chatgptUser.getUserToken();
         } else {
             throw BusinessRuntimeException.getInstance("服务器出了点问题");
         }
@@ -348,6 +353,7 @@ public class ChatGptAccountServiceImpl implements ChatGptAccountService {
             chatgptUser.setUserToken(UUID.randomUUID().toString());
             chatgptUserMapper.insert(chatgptUser);
         } catch (DuplicateKeyException e) {
+            log.error("重复插入镜像用户:{}token,errmsg:{}", user.getNickname(), StringUtil.getErrorText(e));
         }
         return chatgptUser;
     }
@@ -378,6 +384,7 @@ public class ChatGptAccountServiceImpl implements ChatGptAccountService {
             chatgptUserTokenPrepareMapper.updateById(prepare);
             log.info("用户激活userToken:{}成功", prepare.getUserToken());
         } catch (DuplicateKeyException e) {
+            log.error("重复插入镜像车队用户:{}token,errmsg:{}" + chatgptUser.getId(), StringUtil.getErrorText(e));
         }
         return chatgptUser;
     }
@@ -491,6 +498,11 @@ public class ChatGptAccountServiceImpl implements ChatGptAccountService {
                 conversationLimitResponse.setNextAvailableTime(nextAvailableTime);
             }
             conversationLimitResponse.setLimited(true);
+            //用户次数使用限制
+            ChatgptUserCarUsedRecord chatgptUserCarUsedRecord = new ChatgptUserCarUsedRecord();
+            chatgptUserCarUsedRecord.setUserToken(userToken);
+            chatgptUserCarUsedRecord.setIsUserLimit(true);
+            chatgptUserCarUsedRecordMapper.insert(chatgptUserCarUsedRecord);
             return conversationLimitResponse;
         } else {
             // 如果未超过限制,记录当前请求的时间戳
@@ -624,7 +636,7 @@ public class ChatGptAccountServiceImpl implements ChatGptAccountService {
      * 获取车队信息
      */
     @Override
-    public Set<ChatgptCarInfoView> getCarInfoList(String userToken) {
+    public Set<ChatgptCarInfoView> getCarInfoList(String userToken, Integer limit, Boolean isPlus) {
         SearchResult<ChatGptUserConversationRecordHistoryView> search = beanSearcher.search(ChatGptUserConversationRecordHistoryView.class, MapUtils.builder().field("userToken", userToken).limit(0, 2).build());
         Set<ChatgptCarInfoView> res = search.getDataList().stream()
                 .map((historyView) -> {
@@ -635,7 +647,7 @@ public class ChatGptAccountServiceImpl implements ChatGptAccountService {
                     return chatgptCarInfoView;
                 }).collect(Collectors.toCollection(LinkedHashSet::new));
 
-        Set<ChatgptCarInfoView> lowestScoreFleets = getLowestScoreFleets(10);
+        Set<ChatgptCarInfoView> lowestScoreFleets = getLowestScoreFleets(limit, isPlus);
 
         res.addAll(lowestScoreFleets);
 
@@ -685,7 +697,7 @@ public class ChatGptAccountServiceImpl implements ChatGptAccountService {
 
 
     // 获取得分最低的N个车队的方法
-    public Set<ChatgptCarInfoView> getLowestScoreFleets(int count) {
+    public Set<ChatgptCarInfoView> getLowestScoreFleets(int count, Boolean isPlus) {
         Set<ZSetOperations.TypedTuple<Object>> lowestScorecarIds;
         Long fleetsSize = redisService.zCard(RedisService.key.CHATGPT_CAR_SCORES.getName());
         // 构建ChatgptCarInfoView集合
@@ -698,7 +710,7 @@ public class ChatGptAccountServiceImpl implements ChatGptAccountService {
         }
         lowestScorecarIds = redisService.zRangeWithScores(RedisService.key.CHATGPT_CAR_SCORES.getName(), 0L, count - 1);
         Map<Object, Double> collect = lowestScorecarIds.stream().collect(Collectors.toMap(ZSetOperations.TypedTuple::getValue, ZSetOperations.TypedTuple::getScore));
-        List<ChatgptSession> chatgptSessions = chatgptSessionMapper.selectList(Wrappers.lambdaQuery(ChatgptSession.class).in(ChatgptSession::getCarId, collect.keySet()));
+        List<ChatgptSession> chatgptSessions = chatgptSessionMapper.selectList(Wrappers.lambdaQuery(ChatgptSession.class).in(ChatgptSession::getCarId, collect.keySet()).eq(isPlus !=null && isPlus, ChatgptSession::getIsPlus, true));
         return chatgptSessions.stream().map((chatgptSession)-> buildChatgptCarInfoView(chatgptSession.getCarId(),chatgptSession.getCarName(), chatgptSession.getIsPlus(), collect.get(chatgptSession.getCarId())))
                 .sorted(Comparator.comparing(ChatgptCarInfoView::getScore)).collect(Collectors.toCollection(LinkedHashSet::new));
     }
@@ -788,8 +800,10 @@ public class ChatGptAccountServiceImpl implements ChatGptAccountService {
                     .eq(ChatgptUserConversationRecord::getUserToken, userToken)
                     .orderByDesc(ChatgptUserConversationRecord::getId)
                     .last(" limit 1"));
-            chatgptUserConversationRecord.setConversationId(conversationId);
-            chatgptUserConversationRecordMapper.updateById(chatgptUserConversationRecord);
+            if (chatgptUserConversationRecord != null) {
+                chatgptUserConversationRecord.setConversationId(conversationId);
+                chatgptUserConversationRecordMapper.updateById(chatgptUserConversationRecord);
+            }
         }
     }
 
@@ -807,6 +821,29 @@ public class ChatGptAccountServiceImpl implements ChatGptAccountService {
             }
         }
         redisService.set("chatgpt:clears_in:" + carId, expTime, expTime);
+
+        try {
+            //记录用户触发限制
+            ChatgptUserCarUsedRecord chatgptUserCarUsedRecord = new ChatgptUserCarUsedRecord();
+            chatgptUserCarUsedRecord.setUserToken(userToken);
+            chatgptUserCarUsedRecord.setCarId(carId);
+
+            String highCarChatKey = RedisService.key.CHATGPT_CAR_HIGH_CHAT.getName() + carId;
+            String lowCarChatKey = RedisService.key.CHATGPT_CAR_LOW_CHAT.getName() + carId;
+
+            Long highCarChatNum = redisService.zCard(highCarChatKey);
+            if (highCarChatNum != null) {
+                chatgptUserCarUsedRecord.setGptFour(Integer.parseInt(highCarChatNum.toString()));
+            }
+            Long lowCarChatNum = redisService.zCard(lowCarChatKey);
+            if (lowCarChatNum != null) {
+                chatgptUserCarUsedRecord.setGpt(Integer.parseInt(lowCarChatNum.toString()));
+            }
+            chatgptUserCarUsedRecordMapper.insert(chatgptUserCarUsedRecord);
+            log.info("记录userToken:{}访问对应镜像车队carId:{}操作成功", userToken, carId);
+        } catch (Exception e) {
+            log.info("记录userToken:{}访问对应镜像车队carId:{}操作失败e:{}", userToken, carId, StringUtil.getErrorText(e));
+        }
     }
 
     @PostConstruct

+ 81 - 3
netflix-service/src/main/java/com/cyksj/service/corp/impl/CorpEventActionServiceImpl.java

@@ -569,6 +569,78 @@ public class CorpEventActionServiceImpl implements CorpEventActionService {
 		return null;
 	}
 
+	@Override
+	public CorpXmlOutMessage customerStartChat(CorpXmlMessage message, Map<String, Object> context) {
+		//微信客户发起会话事件
+		//外部联系人id
+		String externalUserId = message.getExternalUserId();
+		log.info("监听微信客户:{}发起会话事件", externalUserId);
+		try {
+			//等待3s
+			Thread.sleep(3000);
+		} catch (InterruptedException e) {
+		}
+		//获客链接id
+		String linkId = message.getLinkId();
+		CorpUserAuth corpUserAuth = corpUserAuthMapper.selectOne(Wrappers.lambdaQuery(CorpUserAuth.class)
+				.eq(CorpUserAuth::getExternalUserid, externalUserId).last("limit 1"));
+		String unionId = null;
+		if (corpUserAuth != null) {
+			CorpUser corpUser = corpUserMapper.selectById(corpUserAuth.getCorpUserId());
+			if (corpUser != null) {
+				unionId = corpUser.getUnionid();
+			}
+		}
+		if (StrUtil.isEmpty(unionId)) {
+			return null;
+		}
+		CorpCustomerAcquisitionLinkPopularize corpCustomerAcquisitionLinkPopularize = corpCustomerAcquisitionLinkPopularizeMapper.selectOne(Wrappers.lambdaQuery(CorpCustomerAcquisitionLinkPopularize.class)
+				.eq(CorpCustomerAcquisitionLinkPopularize::getIsChat, 1)
+				.eq(CorpCustomerAcquisitionLinkPopularize::getCustomerAcquistionLinkId, linkId).last("limit 1"));
+		if (corpCustomerAcquisitionLinkPopularize != null) {
+			//callback
+			String callback = null;
+			String params = redisService.getStr(String.format(RedisService.key.CORP_CUSTOMER_ACQUISTION_UNIONID_CLICKID.getName(), unionId));
+			if (StringUtils.isNotBlank(params)) {
+				JSONObject paramsObj = JSONUtil.parseObj(params);
+				callback = paramsObj.getStr("callback");
+			}
+			//如果需要延后主动回传的做持久化.
+			if (StrUtil.isNotBlank(callback)) {
+				log.info("开始回传客户:{}发起会话事件", externalUserId);
+				//如果为加粉则直接回传
+				if (corpCustomerAcquisitionLinkPopularize.getType() == 1) {
+					//如果需要延后主动回传的做持久化.
+					if (!corpCustomerAcquisitionLinkPopularize.getDelayedPost()) {
+						postData(callback, corpCustomerAcquisitionLinkPopularize.getEvent());
+					}
+				} else {
+					//深度转化 前置加粉事件回传.
+					if (StringUtils.isNotBlank(corpCustomerAcquisitionLinkPopularize.getAddEvent())) {
+						postData(callback, corpCustomerAcquisitionLinkPopularize.getAddEvent());
+					}
+				}
+				// 是否延后回传都记录,只看是否直接回传.
+				CorpCustomerAcquistionCallback corpCustomerAcquistionCallback =
+						corpCustomerAcquistionCallbackMapper.selectOne(Wrappers.lambdaQuery(CorpCustomerAcquistionCallback.class).eq(CorpCustomerAcquistionCallback::getCallback, callback).eq(CorpCustomerAcquistionCallback::getUnionId, unionId));
+				if (corpCustomerAcquistionCallback == null) {
+					corpCustomerAcquistionCallback = new CorpCustomerAcquistionCallback();
+				}
+				corpCustomerAcquistionCallback.setCallback(callback);
+				corpCustomerAcquistionCallback.setEvent(corpCustomerAcquisitionLinkPopularize.getEvent());
+				corpCustomerAcquistionCallback.setUnionId(unionId);
+				corpCustomerAcquistionCallback.setStatus(!corpCustomerAcquisitionLinkPopularize.getDelayedPost());
+				if (corpCustomerAcquistionCallback.getId() != null) {
+					corpCustomerAcquistionCallbackMapper.updateById(corpCustomerAcquistionCallback);
+				} else {
+					corpCustomerAcquistionCallbackMapper.insert(corpCustomerAcquistionCallback);
+				}
+
+			}
+		}
+		return null;
+	}
+
 	/**
 	 * 修改客户成员关系,客户标签
 	 */
@@ -613,6 +685,7 @@ public class CorpEventActionServiceImpl implements CorpEventActionService {
 
 		//存在被删除的标签
 		if (CollUtil.isNotEmpty(exists_tagIds)) {
+			log.info("需删除用户:{}对应客服:{}关联已删除的标签:{}", externalUserid, relation.getFollowId(), exists_tagIds);
 			corpUserTagMapper.delete(Wrappers.lambdaQuery(CorpUserTag.class)
 					.in(CorpUserTag::getTagId, exists_tagIds)
 					.eq(CorpUserTag::getRelationId, relation.getId()));
@@ -1124,12 +1197,17 @@ public class CorpEventActionServiceImpl implements CorpEventActionService {
 					if (corpCustomerAcquisitionLinkPopularize.getType() == 1) {
 						//如果需要延后主动回传的做持久化.
 						if(!corpCustomerAcquisitionLinkPopularize.getDelayedPost()){
-							postData(callback, corpCustomerAcquisitionLinkPopularize.getEvent());
+							if (!corpCustomerAcquisitionLinkPopularize.getIsChat()) {
+								postData(callback, corpCustomerAcquisitionLinkPopularize.getEvent());
+							}
 						}
 					}else {
 						//深度转化 前置加粉事件回传.
-						if(StringUtils.isNotBlank(corpCustomerAcquisitionLinkPopularize.getAddEvent())){
-							postData(callback, corpCustomerAcquisitionLinkPopularize.getAddEvent());
+						if (StringUtils.isNotBlank(corpCustomerAcquisitionLinkPopularize.getAddEvent())) {
+							//是否是监听客户发起会话事件 false
+							if (!corpCustomerAcquisitionLinkPopularize.getIsChat()) {
+								postData(callback, corpCustomerAcquisitionLinkPopularize.getAddEvent());
+							}
 						}
 
 						//深度回传.

+ 9 - 0
netflix-service/src/main/java/com/cyksj/service/corp/impl/CorpServiceImpl.java

@@ -164,6 +164,15 @@ public class CorpServiceImpl implements CorpService {
 					}
 				})
 				.end()
+				//微信客户发起会话事件
+				.rule().async(false).changeType("customer_start_chat").event("customer_acquisition")
+				.handler(new CorpMessageHandler() {
+					@Override
+					public CorpXmlOutMessage handle(CorpXmlMessage message, Map<String, Object> context, CorpService corpService) throws Exception {
+						return corpEventActionService.customerStartChat(message, context);
+					}
+				})
+				.end()
 		;
 
 	}

+ 1 - 2
netflix-service/src/main/java/com/cyksj/service/corp/impl/WxCorpOpsImpl.java

@@ -5,7 +5,6 @@ import cn.hutool.core.util.StrUtil;
 import cn.hutool.http.HttpUtil;
 import cn.hutool.json.JSONObject;
 import cn.hutool.json.JSONUtil;
-import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.cyksj.common.exception.BusinessRuntimeException;
 import com.cyksj.common.util.IoKit;
 import com.cyksj.common.util.J11HttpC;
@@ -782,7 +781,7 @@ public class WxCorpOpsImpl implements WxCorpOps {
 
 	@Override
 	public WxCpLinkAddResp customerAcquisitionDeleteLink(String corpId, WxCpLinkUpd wxCpLinkUpd) throws Exception {
-		String url = "https://qyapi.weixin.qq.com/cgi-bin/externalcontact/customer_acquisition/delete_link?access_token=";
+		String url = "https://qyapi.weixin.qq.com/cgi-bin/externalcontact/customer_acquisition/delete_link?access_token=" + getAccessToken(corpId);
 
 		HttpResponse<String> res =
 				J11HttpC.custom()

+ 2 - 0
netflix-service/src/main/java/com/cyksj/service/corp/msg/CorpEventActionService.java

@@ -31,4 +31,6 @@ public interface CorpEventActionService {
 	CorpXmlOutMessage delCorpGroupChat(CorpXmlMessage message);
 
     CorpXmlOutMessage msgAuditApproved(CorpXmlMessage message, Map<String, Object> context);
+
+	CorpXmlOutMessage customerStartChat(CorpXmlMessage message, Map<String, Object> context);
 }

+ 6 - 1
netflix-service/src/main/java/com/cyksj/service/exchange/impl/ExchangeCodeServiceImpl.java

@@ -381,7 +381,12 @@ public class ExchangeCodeServiceImpl extends ServiceImpl<ExchangeCodeMapper, Exc
 				if (sku.getDays() != null && sku.getDays() > 0) {
 					newDate = DateUtil.offsetDay(expiryTime, sku.getDays() * 1);
 				} else {
-					newDate = DateUtil.offset(expiryTime, DateField.MONTH, sku.getMonths() * 1);
+					//奈飞月付 按30天计算
+					if (sku.getId() == 4) {
+						newDate = DateUtil.offsetDay(expiryTime, 30);
+					} else {
+						newDate = DateUtil.offset(expiryTime, DateField.MONTH, sku.getMonths() * 1);
+					}
 				}
 				relation.setExpiryTime(newDate);
 				relation.setStartTime(relation.getStartTime() == null ? new Date() : null);

+ 6 - 1
netflix-service/src/main/java/com/cyksj/service/mange/group/CmsGroupServiceImpl.java

@@ -217,7 +217,12 @@ public class CmsGroupServiceImpl extends ServiceImpl<GroupsMapper,GroupsTrips> i
                     if (donSku.getDays() != null && donSku.getDays() > 0) {
                         newDate = DateUtil.offsetDay(expiryTime, donSku.getDays() * 1);
                     } else {
-                        newDate = DateUtil.offset(expiryTime, DateField.MONTH, donSku.getMonths() * 1);
+                        //奈飞月付 按30天计算
+                        if (donSku.getId() == 4) {
+                            newDate = DateUtil.offsetDay(expiryTime, 30);
+                        } else {
+                            newDate = DateUtil.offset(expiryTime, DateField.MONTH, donSku.getMonths() * 1);
+                        }
                     }
                     relation.setExpiryTime(newDate);
                     relation.setStartTime(relation.getStartTime() == null ? new Date() : null);

+ 19 - 4
netflix-service/src/main/java/com/cyksj/service/mange/impl/CmsOrderDonServiceImpl.java

@@ -500,6 +500,9 @@ public class CmsOrderDonServiceImpl extends ServiceImpl<OrderDonMapper,OrderDon>
         relation.setNewRelationId(newRelation.getId());
         relationClearService.clearTicket(relation, source);
 
+        //是否是GPT镜像规格
+        delGptUser(orderDon.getGoodsId(), orderDon.getRelationId());
+
         if (plusPurchaseSkuRelation != null && plus_relationList != null) {
             plus_relationList.remove(relationId);
             plus_relationList.add(newRelation.getId());
@@ -847,10 +850,7 @@ public class CmsOrderDonServiceImpl extends ServiceImpl<OrderDonMapper,OrderDon>
                 giftCardOrderUseRecordService.returnGiftCardCash(orderDon.getId());
             }
             //是否是GPT镜像规格
-            if (orderDon.getGoodsId() == 18 && sku.getIsMirror()) {
-                chatgptUserMapper.delete(Wrappers.lambdaQuery(ChatgptUser.class)
-                        .eq(ChatgptUser::getRelationId, orderDon.getRelationId()));
-            }
+            delGptUser(orderDon.getGoodsId(), orderDon.getRelationId());
             //是否是分销订单
             //处理下级渠道分销提成
             handleSubRewards(orderDon);
@@ -1123,4 +1123,19 @@ public class CmsOrderDonServiceImpl extends ServiceImpl<OrderDonMapper,OrderDon>
         }
         return relation;
     }
+
+    /**
+     * 删除gptUser
+     */
+    public void delGptUser(Long goodsId, Long relationId) {
+        //gpt镜像
+        if (goodsId != null && goodsId == 18) {
+            Integer selectCount = chatgptUserMapper.selectCount(Wrappers.lambdaQuery(ChatgptUser.class)
+                    .eq(ChatgptUser::getRelationId, relationId));
+            if (selectCount > 0) {
+                chatgptUserMapper.delete(Wrappers.lambdaQuery(ChatgptUser.class)
+                        .eq(ChatgptUser::getRelationId, relationId));
+            }
+        }
+    }
 }

+ 11 - 0
netflix-service/src/main/java/com/cyksj/service/mange/upgrade/UpgradePackageService.java

@@ -0,0 +1,11 @@
+package com.cyksj.service.mange.upgrade;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.cyksj.model.entity.UpgradePackage;
+
+/**
+ * @author zwhui
+ * @date 2024/4/24 15:04
+ */
+public interface UpgradePackageService extends IService<UpgradePackage> {
+}

+ 19 - 0
netflix-service/src/main/java/com/cyksj/service/mange/upgrade/impl/UpgradePackageServiceImpl.java

@@ -0,0 +1,19 @@
+package com.cyksj.service.mange.upgrade.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.cyksj.mapper.UpgradePackageMapper;
+import com.cyksj.model.entity.UpgradePackage;
+import com.cyksj.service.mange.upgrade.UpgradePackageService;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+
+/**
+ * @author zwhui
+ * @date 2024/4/24 15:05
+ */
+@Slf4j
+@RequiredArgsConstructor
+@Service
+public class UpgradePackageServiceImpl extends ServiceImpl<UpgradePackageMapper, UpgradePackage> implements UpgradePackageService {
+}

+ 27 - 0
netflix-service/src/main/java/com/cyksj/service/midjourney/MidjourneyAccountService.java

@@ -0,0 +1,27 @@
+package com.cyksj.service.midjourney;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.cyksj.model.entity.Account;
+import com.cyksj.model.entity.MidjourneyAccount;
+import com.cyksj.model.entity.MidjourneyUser;
+
+import java.util.List;
+
+/**
+ * @author zwhui
+ * @date 2024/4/12 15:54
+ */
+public interface MidjourneyAccountService extends IService<MidjourneyAccount> {
+    void addAccount(MidjourneyAccount midjourneyAccount);
+
+    void removeAccount(Long id);
+
+    void updateAccount(MidjourneyAccount midjourneyAccount);
+
+    void updateStatus(Long id);
+
+    void syncAccount(Long id);
+
+    String getLoginUrl(Long userId, Long relationId);
+
+}

+ 29 - 0
netflix-service/src/main/java/com/cyksj/service/midjourney/MidjourneyService.java

@@ -0,0 +1,29 @@
+package com.cyksj.service.midjourney;
+
+import com.cyksj.model.dto.BlendDimensions;
+import com.cyksj.model.entity.MidjourneyUser;
+import com.cyksj.model.entity.MidjourneyUserConversation;
+
+import java.util.List;
+
+/**
+ * @author zwhui
+ * @date 2024/4/23 15:44
+ */
+public interface MidjourneyService {
+    MidjourneyUserConversation submitImagine(MidjourneyUser user, String prompt, List<String> base64Array);
+
+    MidjourneyUserConversation submitDescribe(MidjourneyUser user, String base64);
+
+    MidjourneyUserConversation submitBlend(MidjourneyUser user, BlendDimensions dimensions, List<String> base64Array);
+
+    MidjourneyUserConversation submitModal(MidjourneyUser user, Long taskId, String prompt, String maskBase64);
+
+    MidjourneyUserConversation submitShorten(MidjourneyUser user, String prompt);
+
+    List<MidjourneyUserConversation> listConversationByIds(List<Long> ids);
+
+    MidjourneyUserConversation submitAction(MidjourneyUser user, Long taskId, String customId);
+
+    MidjourneyUserConversation cancelConversation(MidjourneyUser user, Long id);
+}

+ 267 - 0
netflix-service/src/main/java/com/cyksj/service/midjourney/impl/MidJourneyAccountServiceImpl.java

@@ -0,0 +1,267 @@
+package com.cyksj.service.midjourney.impl;
+
+import cn.hutool.core.lang.UUID;
+import cn.hutool.http.HttpRequest;
+import cn.hutool.http.HttpUtil;
+import cn.hutool.json.JSONObject;
+import cn.hutool.json.JSONUtil;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.cyksj.common.exception.BusinessRuntimeException;
+import com.cyksj.common.util.StringUtil;
+import com.cyksj.mapper.*;
+import com.cyksj.model.entity.*;
+import com.cyksj.service.midjourney.MidjourneyAccountService;
+import com.cyksj.service.user.UserBindRelationService;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.dao.DuplicateKeyException;
+import org.springframework.stereotype.Service;
+
+import javax.imageio.stream.FileImageOutputStream;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author zwhui
+ * @date 2024/4/12 15:54
+ */
+@Service
+@Slf4j
+@RequiredArgsConstructor
+public class MidJourneyAccountServiceImpl extends ServiceImpl<MidjourneyAccountMapper, MidjourneyAccount> implements MidjourneyAccountService {
+
+    private static final String HOST = "http://43.154.230.104:8080";
+
+    private final GroupsRelationMapper groupsRelationMapper;
+
+    private final GroupsMapper groupsMapper;
+
+    private final GoodsDonSkuMapper skuMapper;
+
+    private final UserMapper userMapper;
+
+    private final UserBindRelationService userBindRelationService;
+
+    private final MidjourneyUserMapper midjourneyUserMapper;
+
+    @Override
+    public void addAccount(MidjourneyAccount midjourneyAccount) {
+        baseMapper.insert(midjourneyAccount);
+        addAcount(midjourneyAccount);
+        //拉取plus服务账号实例id
+        Long instanceId = getAccount(midjourneyAccount.getId());
+        midjourneyAccount.setInstanceId(instanceId);
+        baseMapper.updateById(midjourneyAccount);
+    }
+
+    @Override
+    public void removeAccount(Long id) {
+        MidjourneyAccount midjourneyAccount = baseMapper.selectById(id);
+        if (midjourneyAccount == null) {
+            throw BusinessRuntimeException.getInstance("账号不存在");
+        }
+        baseMapper.deleteById(id);
+        //删除plus服务账号信息
+        delAcount(midjourneyAccount.getInstanceId());
+    }
+
+    @Override
+    public void updateAccount(MidjourneyAccount midjourneyAccount) {
+        baseMapper.updateById(midjourneyAccount);
+        updAccount(midjourneyAccount);
+    }
+
+    @Override
+    public void updateStatus(Long id) {
+        MidjourneyAccount midjourneyAccount = baseMapper.selectById(id);
+        if (midjourneyAccount == null) {
+            throw BusinessRuntimeException.getInstance("账号不存在");
+        }
+        midjourneyAccount.setStatus(!midjourneyAccount.getStatus());
+        updAccount(midjourneyAccount);
+    }
+
+    @Override
+    public void syncAccount(Long id) {
+        MidjourneyAccount midjourneyAccount = baseMapper.selectById(id);
+        if (midjourneyAccount == null) {
+            throw BusinessRuntimeException.getInstance("账号不存在");
+        }
+        String fastRemainTime = syncInfo(midjourneyAccount.getInstanceId());
+        midjourneyAccount.setFastRemainTime(fastRemainTime);
+        baseMapper.updateById(midjourneyAccount);
+    }
+
+    private void addAcount(MidjourneyAccount midjourneyAccount) {
+        Map<String, Object> accountParam = createAccountParam(midjourneyAccount);
+        String body = HttpUtil.post(HOST + "/mj/account/create", accountParam);
+        log.info("addAccount body:{}", body);
+        JSONObject jsonObject = JSONUtil.parseObj(body);
+        if (jsonObject.getInt("code") != 1) {
+            throw BusinessRuntimeException.getInstance("addAccount error message:" + jsonObject.getStr("description"));
+        }
+    }
+
+    private Map<String, Object> createAccountParam(MidjourneyAccount midjourneyAccount) {
+        Map<String, Object> param = new HashMap<>();
+        param.put("channelId", midjourneyAccount.getChannelId());
+        param.put("guildId", midjourneyAccount.getGuildId());
+        param.put("userToken", midjourneyAccount.getUserToken());
+        param.put("remark", midjourneyAccount.getId());
+        return param;
+    }
+
+    private void delAcount(Long id) {
+        String body = HttpRequest.delete(HOST + "/mj/account/"+id+"/delete").execute().body();
+        log.info("delAcount body:{}", body);
+        JSONObject jsonObject = JSONUtil.parseObj(body);
+        if (jsonObject.getInt("code") != 1) {
+            throw BusinessRuntimeException.getInstance("delAcount error message:" + jsonObject.getStr("description"));
+        }
+    }
+
+    private Long getAccount(Long id) {
+        String body = HttpRequest.post(HOST + "/mj/account/query").form("remark",id).execute().body();
+        log.info("getAccount body:{}", body);
+        JSONObject jsonObject = JSONUtil.parseObj(body);
+        if (jsonObject.getInt("code") != 1) {
+            throw BusinessRuntimeException.getInstance("getAccount error message:" + jsonObject.getStr("description"));
+        }
+
+        return JSONUtil.parseObj(JSONUtil.parseArray(jsonObject.getStr("content")).get(0)).get("id", Long.class);
+    }
+
+    private void updAccount(MidjourneyAccount midjourneyAccount){
+        Map<String, Object> accountParam = createAccountParam(midjourneyAccount);
+        String body = HttpRequest.put(HOST + "/mj/account/"+midjourneyAccount.getInstanceId()+"/update-reconnect")
+                .body(JSONUtil.toJsonStr(accountParam)).execute().body();
+        log.info("updAccount body:{}", body);
+        JSONObject jsonObject = JSONUtil.parseObj(body);
+        if (jsonObject.getInt("code") != 1) {
+            throw BusinessRuntimeException.getInstance("updAccount error message:" + jsonObject.getStr("description"));
+        }
+    }
+
+    private String syncInfo(Long id){
+        String body = HttpRequest.post(HOST + "/mj/account/"+id+"/sync-info").execute().body();
+        log.info("syncInfo body:{}", body);
+        JSONObject jsonObject = JSONUtil.parseObj(body);
+        if (jsonObject.getInt("code") != 1) {
+            throw BusinessRuntimeException.getInstance("syncInfo error message:" + jsonObject.getStr("description"));
+        }
+        return JSONUtil.parseObj(jsonObject.getStr("result")).getStr("fastTimeRemaining");
+    }
+
+
+    @Override
+    public String getLoginUrl(Long userId, Long relationId) {
+        GroupsRelation groupsRelation = getGroupsRelation(userId, relationId);
+        GroupsTrips groupsTrips = getGroupsTrips(groupsRelation);
+        GoodsDonSku goodsDonSku = skuMapper.selectById(groupsTrips.getSkuId());
+
+        if (goodsDonSku != null && goodsDonSku.getIsMirror()) {
+            MidjourneyUser midjourneyUser = getMidjourneyUser(userId, relationId, groupsRelation, groupsTrips, goodsDonSku);
+            return HOST + "/login_token?access_token=" + midjourneyUser.getUserToken();
+        } else {
+            throw BusinessRuntimeException.getInstance("服务器出了点问题");
+        }
+    }
+
+    /**
+     * 获取车位信息
+     *
+     * @param userId
+     * @param relationId
+     * @return
+     */
+    private GroupsRelation getGroupsRelation(Long userId, Long relationId) {
+        List<Long> userIdList = userBindRelationService.getRelationUserIdList(userId, null);
+        GroupsRelation groupsRelation = groupsRelationMapper.selectOne(Wrappers.lambdaQuery(GroupsRelation.class).in(GroupsRelation::getUserId, userIdList).eq(GroupsRelation::getId, relationId));
+        if (groupsRelation == null) {
+            throw BusinessRuntimeException.getInstance("车票不存在");
+        }
+        return groupsRelation;
+    }
+
+    /**
+     * 获取车队信息
+     *
+     * @param groupsRelation
+     * @return
+     */
+    private GroupsTrips getGroupsTrips(GroupsRelation groupsRelation) {
+        GroupsTrips groupsTrips = groupsMapper.selectById(groupsRelation.getGroupsId());
+        if (groupsTrips == null) {
+            throw BusinessRuntimeException.getInstance("车队异常");
+        }
+        return groupsTrips;
+    }
+
+    private MidjourneyUser getMidjourneyUser(Long userId, Long relationId, GroupsRelation groupsRelation, GroupsTrips groupsTrips, GoodsDonSku goodsDonSku) {
+        MidjourneyUser midjourneyUser = midjourneyUserMapper.selectOne(Wrappers.lambdaQuery(MidjourneyUser.class).eq(MidjourneyUser::getRelationId, relationId));
+        User user = userMapper.selectById(userId);
+        if (midjourneyUser == null) {
+            midjourneyUser = createMidjourneyUser(groupsRelation, groupsTrips, user, goodsDonSku);
+        } else {
+            updateMidjourneyUser(groupsRelation, user, midjourneyUser);
+        }
+        return midjourneyUser;
+    }
+
+    /**
+     * 创建MidjourneyUser
+     */
+    private synchronized MidjourneyUser createMidjourneyUser(GroupsRelation groupsRelation, GroupsTrips groupsTrips, User user, GoodsDonSku goodsDonSku) {
+        MidjourneyUser midjourneyUser = new MidjourneyUser();
+        midjourneyUser.setExpireTime(groupsRelation.getExpiryTime());
+        midjourneyUser.setName(user.getNickname());
+        midjourneyUser.setImg(getWxImg(user.getHeadimgurl(), user));
+        midjourneyUser.setRelationId(groupsRelation.getId());
+        midjourneyUser.setUserToken(UUID.randomUUID().toString());
+        midjourneyUser.setMjFastNum(goodsDonSku.getMjFastNum());
+        midjourneyUser.setMjRelaxNum(goodsDonSku.getMjRelaxNum());
+        midjourneyUserMapper.insert(midjourneyUser);
+        return midjourneyUser;
+    }
+
+    private void updateMidjourneyUser(GroupsRelation groupsRelation, User user, MidjourneyUser midjourneyUser) {
+        midjourneyUser.setName(user.getNickname());
+        midjourneyUser.setImg(getWxImg(user.getHeadimgurl(), user));
+        midjourneyUser.setExpireTime(groupsRelation.getExpiryTime());
+        midjourneyUserMapper.updateById(midjourneyUser);
+    }
+
+    /**
+     * 更换wx头像至oss
+     */
+    private String getWxImg(String headimgurl, User user) {
+        if (headimgurl.contains("thirdwx.qlogo.cn")) {
+            try {
+                return uploadPic(headimgurl, "wxheadimg-" + user.getId());
+            } catch (Exception ex) {
+                log.error("上传微信头像错误!msg:{}", StringUtil.getErrorText(ex));
+                return "./avatars.png";
+            }
+        } else {
+            return user.getHeadimgurl();
+        }
+    }
+
+    private static String uploadPic(String url, String prefix) throws IOException {
+        byte[] body = HttpUtil.downloadBytes(url);
+        Path tempFile = Files.createTempFile(prefix, ".jpeg");
+        try (FileImageOutputStream imageOutput = new FileImageOutputStream(tempFile.toFile())) {
+            imageOutput.write(body, 0, body.length);
+        }
+        Map<String, Object> paramMap = new HashMap<>();
+        paramMap.put("file", tempFile.toFile());
+        JSONObject result = JSONUtil.parseObj(HttpUtil.post("https://files.liuliangbang.vip/pic/ups", paramMap));
+        return result.getJSONObject("value").getJSONArray("saved").getJSONObject(0).getJSONObject("info").getStr("cdnUrl");
+    }
+
+}

+ 265 - 0
netflix-service/src/main/java/com/cyksj/service/midjourney/impl/MidjourneyServiceImpl.java

@@ -0,0 +1,265 @@
+package com.cyksj.service.midjourney.impl;
+
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.core.map.MapUtil;
+import cn.hutool.http.HttpUtil;
+import cn.hutool.json.JSONArray;
+import cn.hutool.json.JSONObject;
+import cn.hutool.json.JSONUtil;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.cyksj.common.exception.BusinessRuntimeException;
+import com.cyksj.common.task.GlobalThreadPoolTaskExecutor;
+import com.cyksj.mapper.MidjourneyUserConversationMapper;
+import com.cyksj.model.dto.BlendDimensions;
+import com.cyksj.model.entity.MidjourneyAccount;
+import com.cyksj.model.entity.MidjourneyUser;
+import com.cyksj.model.entity.MidjourneyUserConversation;
+import com.cyksj.service.midjourney.MidjourneyService;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.stereotype.Service;
+
+import javax.imageio.stream.FileImageOutputStream;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.*;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * @author zwhui
+ * @date 2024/4/23 15:44
+ */
+@Service
+@Slf4j
+@RequiredArgsConstructor
+public class MidjourneyServiceImpl implements MidjourneyService {
+    private static final String HOST = "http://43.154.230.104:8080";
+
+    private final MidjourneyUserConversationMapper conversationMapper;
+
+    private static final List<String> progress = Arrays.asList("25%", "45%", "75%", "100%");
+
+    private static final GlobalThreadPoolTaskExecutor TASK_EXECUTOR = GlobalThreadPoolTaskExecutor.getInstance();
+
+
+    @Override
+    public MidjourneyUserConversation submitImagine(MidjourneyUser user, String prompt, List<String> base64Array) {
+        JSONObject imagine = imagine(user.getId(), prompt, base64Array);
+        JSONObject properties = imagine.getJSONObject("properties");
+        return saveConversation(user.getId(), imagine.getLong("result"), properties,"IMAGINE", prompt);
+    }
+
+    public MidjourneyUserConversation saveConversation(Long userId,Long taskId,JSONObject properties, String action,String prompt) {
+        MidjourneyUserConversation conversation = new MidjourneyUserConversation()
+                .setUserId(userId).setTaskId(taskId).setAction(action).setPrompt(prompt)
+                .setMode(1).setStartTime(System.currentTimeMillis()).setProgress("0%")
+                .setStatus("IN_PROGRESS").setChannelId(properties.getLong("discordChannelId"))
+                .setInstanceId(properties.getLong("discordInstanceId")).setTaskId(taskId);
+        conversationMapper.insert(conversation);
+        return conversation;
+    }
+
+    private JSONObject imagine(Long userId,String prompt, List<String> base64Array) {
+        Map<String, Object> imagineParam = MapUtil.builder(new HashMap<String,Object>())
+                .put("prompt", prompt).put("state", userId).build();
+        if (CollectionUtil.isNotEmpty(base64Array)) {
+            imagineParam.put("base64Array", base64Array);
+        }
+        String body = HttpUtil.post(HOST + "/mj/submit/imagine", imagineParam);
+        log.info("imagine body:{}", body);
+        JSONObject jsonObject = JSONUtil.parseObj(body);
+        if (jsonObject.getInt("code") != 1) {
+            throw BusinessRuntimeException.getInstance("imagine error message:" + jsonObject.getStr("description"));
+        }
+        return jsonObject;
+    }
+
+
+    @Override
+    public MidjourneyUserConversation submitDescribe(MidjourneyUser user, String base64) {
+        JSONObject describe = describe(user.getId(), base64);
+        JSONObject properties = describe.getJSONObject("properties");
+        return saveConversation(user.getId(), describe.getLong("result"), properties,"DESCRIBE", StringUtils.EMPTY);
+    }
+
+    private JSONObject describe(Long userId,String base64) {
+        Map<String, Object> param = MapUtil.builder(new HashMap<String,Object>()).put("state", userId).put("base64", base64).build();
+        String body = HttpUtil.post(HOST + "/mj/submit/describe", param);
+        log.info("describe body:{}", body);
+        JSONObject jsonObject = JSONUtil.parseObj(body);
+        if (jsonObject.getInt("code") != 1) {
+            throw BusinessRuntimeException.getInstance("describe error message:" + jsonObject.getStr("description"));
+        }
+        return jsonObject;
+    }
+
+
+
+    @Override
+    public MidjourneyUserConversation submitBlend(MidjourneyUser user, BlendDimensions dimensions, List<String> base64Array) {
+        JSONObject blend = blend(user.getId(), dimensions, base64Array);
+        JSONObject properties = blend.getJSONObject("properties");
+        return saveConversation(user.getId(), blend.getLong("result"), properties,"BLEND", StringUtils.EMPTY);
+    }
+
+    private JSONObject blend(Long userId,BlendDimensions dimensions, List<String> base64Array) {
+        Map<String, Object> param = MapUtil.builder(new HashMap<String,Object>())
+                .put("base64Array", base64Array).put("state", userId).build();
+        if (dimensions != null) {
+            param.put("dimensions", dimensions);
+        }
+        String body = HttpUtil.post(HOST + "/mj/submit/blend", param);
+        log.info("blend body:{}", body);
+        JSONObject jsonObject = JSONUtil.parseObj(body);
+        if (jsonObject.getInt("code") != 1) {
+            throw BusinessRuntimeException.getInstance("blend error message:" + jsonObject.getStr("description"));
+        }
+        return jsonObject;
+    }
+    @Override
+    public MidjourneyUserConversation submitModal(MidjourneyUser user, Long taskId, String prompt, String maskBase64) {
+        JSONObject modal = modal(user.getId(),taskId, prompt, maskBase64);
+        JSONObject properties = modal.getJSONObject("properties");
+        return saveConversation(user.getId(), modal.getLong("result"), properties,"MODAL", prompt);
+    }
+
+    private JSONObject modal(Long userId,Long taskId,String prompt, String maskBase64) {
+        Map<String, Object> param = MapUtil.builder(new HashMap<String,Object>())
+                .put("taskId", taskId).put("state", userId).build();
+        if (StringUtils.isNotBlank(prompt)) {
+            param.put("prompt", prompt);
+        }
+        if (StringUtils.isNotBlank(maskBase64)) {
+            param.put("maskBase64", maskBase64);
+        }
+        String body = HttpUtil.post(HOST + "/mj/submit/modal", param);
+        log.info("shorten body:{}", body);
+        JSONObject jsonObject = JSONUtil.parseObj(body);
+        if (jsonObject.getInt("code") != 1) {
+            throw BusinessRuntimeException.getInstance("shorten error message:" + jsonObject.getStr("description"));
+        }
+        return jsonObject;
+    }
+
+    @Override
+    public MidjourneyUserConversation submitShorten(MidjourneyUser user, String prompt) {
+        JSONObject shorten = shorten(user.getId(), prompt);
+        JSONObject properties = shorten.getJSONObject("properties");
+        return saveConversation(user.getId(), shorten.getLong("result"), properties,"SHORTEN", prompt);
+    }
+
+    private JSONObject shorten(Long userId,String prompt) {
+        Map<String, Object> param = MapUtil.builder(new HashMap<String,Object>())
+                .put("prompt", prompt).put("state", userId).build();
+        String body = HttpUtil.post(HOST + "/mj/submit/shorten", param);
+        log.info("shorten body:{}", body);
+        JSONObject jsonObject = JSONUtil.parseObj(body);
+        if (jsonObject.getInt("code") != 1) {
+            throw BusinessRuntimeException.getInstance("shorten error message:" + jsonObject.getStr("description"));
+        }
+        return jsonObject;
+    }
+
+
+    @Override
+    public MidjourneyUserConversation submitAction(MidjourneyUser user, Long taskId, String customId) {
+        JSONObject action = action(user.getId(), taskId, customId);
+        JSONObject properties = action.getJSONObject("properties");
+        return saveConversation(user.getId(), action.getLong("result"), properties,"ACTION", StringUtils.EMPTY);
+    }
+
+    public JSONObject action(Long userId, Long taskId, String customId) {
+        Map<String, Object> param = MapUtil.builder(new HashMap<String,Object>())
+                .put("taskId", taskId).put("state", userId).put("customId", customId).build();
+        String body = HttpUtil.post(HOST + "/mj/submit/action", param);
+        log.info("action body:{}", body);
+        JSONObject jsonObject = JSONUtil.parseObj(body);
+        if (jsonObject.getInt("code") != 1) {
+            throw BusinessRuntimeException.getInstance("action error message:" + jsonObject.getStr("description"));
+        }
+        return jsonObject;
+    }
+    @Override
+    public List<MidjourneyUserConversation> listConversationByIds(List<Long> ids) {
+        List<MidjourneyUserConversation> list = new ArrayList<>();
+        listByIds(ids).forEach(json -> {
+            JSONObject jsons = JSONUtil.parseObj(json);
+            MidjourneyUserConversation conversation = JSONUtil.toBean(jsons, MidjourneyUserConversation.class);
+            conversation.setUserId(jsons.getLong("state"));
+            conversation.setTaskId(jsons.getLong("id"));
+            list.add(conversation);
+            TASK_EXECUTOR.execute(() -> {
+                try {
+                    sync(conversation);
+                } catch (IOException e) {
+                    throw new RuntimeException(e);
+                }
+            });
+        });
+        return list;
+    }
+
+
+    public void sync(MidjourneyUserConversation conversation) throws IOException {
+        if (progress.contains(conversation.getProgress())){
+            log.info("同步任务:{},进度:{}",conversation.getTaskId(),conversation.getProgress());
+            MidjourneyUserConversation dbConversation = conversationMapper.selectOne(Wrappers.lambdaQuery(MidjourneyUserConversation.class).eq(MidjourneyUserConversation::getTaskId, conversation.getTaskId())
+                    .eq(MidjourneyUserConversation::getUserId, conversation.getUserId()).last("limit 1"));
+            if (dbConversation != null) {
+                if (StringUtils.isNotBlank(conversation.getImageUrl())) {
+                    dbConversation.setImageUrl(uploadPic(conversation.getImageUrl(), "conversation"+dbConversation.getId()));
+                }
+                conversation.setId(dbConversation.getId());
+                conversationMapper.updateById(conversation);
+            }
+        }
+    }
+
+
+    private static String uploadPic(String url, String prefix) throws IOException {
+        byte[] body = HttpUtil.downloadBytes(url);
+        Path tempFile = Files.createTempFile(prefix, ".png");
+        try (FileImageOutputStream imageOutput = new FileImageOutputStream(tempFile.toFile())) {
+            imageOutput.write(body, 0, body.length);
+        }
+        Map<String, Object> paramMap = new HashMap<>();
+        paramMap.put("file", tempFile.toFile());
+        JSONObject result = JSONUtil.parseObj(HttpUtil.post("https://files.liuliangbang.vip/pic/ups", paramMap));
+        return result.getJSONObject("value").getJSONArray("saved").getJSONObject(0).getJSONObject("info").getStr("cdnUrl");
+    }
+    public JSONArray listByIds(List<Long> ids) {
+        Map<String, Object> param = MapUtil.builder(new HashMap<String, Object>()).put("ids", ids).build();
+        String body = HttpUtil.post(HOST + "/mj/task/list-by-ids", param);
+        log.info("listByIds body:{}", body);
+        return JSONUtil.parseArray(body);
+    }
+
+    @Override
+    public MidjourneyUserConversation cancelConversation(MidjourneyUser user, Long id) {
+        MidjourneyUserConversation conversation = conversationMapper.selectOne(Wrappers.lambdaQuery(MidjourneyUserConversation.class).eq(MidjourneyUserConversation::getId, id));
+        if (conversation == null) {
+            throw BusinessRuntimeException.getInstance("会话不存在");
+        }
+        if (!Objects.equals(conversation.getUserId(), user.getId())) {
+            throw BusinessRuntimeException.getInstance("不是您的会话");
+        }
+        conversation.setStatus("CANCEL");
+        conversationMapper.updateById(conversation);
+        cancel(conversation.getTaskId());
+        return conversation;
+    }
+
+    public void cancel(Long taskId) {
+        String body = HttpUtil.post(HOST + "/mj/task/"+taskId+"/cancel",MapUtil.empty());
+        log.info("cancel body:{}", body);
+        JSONObject jsonObject = JSONUtil.parseObj(body);
+        if (jsonObject.getInt("code") != 1) {
+            throw BusinessRuntimeException.getInstance("cancel error message:" + jsonObject.getStr("description"));
+        }
+    }
+
+}

+ 4 - 0
netflix-service/src/main/java/com/cyksj/service/order/OrderDonService.java

@@ -10,6 +10,7 @@ import com.cyksj.model.dto.H5JsPayParams;
 import com.cyksj.model.entity.OrderDetailView;
 import com.cyksj.model.entity.OrderDon;
 import com.cyksj.model.entity.RealGoodsInterestUser;
+import com.cyksj.model.entity.UpgradeOrderDon;
 import com.cyksj.model.request.AlipayOrderDonReq;
 import com.cyksj.model.request.OrderPayRequest;
 
@@ -90,4 +91,7 @@ public interface OrderDonService extends IService<OrderDon> {
     void zeroOrderConfirm(Long orderId);
 
     void orderNotify(OrderDon orderDon);
+
+    UpgradeOrderDon submitUpgrade(OrderPayRequest payRequest);
+
 }

+ 73 - 1
netflix-service/src/main/java/com/cyksj/service/order/impl/OrderDonServiceImpl.java

@@ -286,6 +286,12 @@ public class OrderDonServiceImpl extends ServiceImpl<OrderDonMapper, OrderDon> i
 
 	private final OrderDonSubsidyRelateMapper orderDonSubsidyRelateMapper;
 
+	private final UpgradePackageMapper upgradePackageMapper;
+
+	private final UpgradeOrderDonMapper upgradeOrderDonMapper;
+
+	private final MidjourneyUserMapper midjourneyUserMapper;
+
 	private final List<String> noChekGoodsTemp = List.of("Apple One", "Youtube", "Spotify");
 
 	@Transactional(rollbackFor = Throwable.class)
@@ -1340,7 +1346,12 @@ public class OrderDonServiceImpl extends ServiceImpl<OrderDonMapper, OrderDon> i
 					if (donSku.getDays() != null && donSku.getDays() > 0) {
 						newDate = DateUtil.offsetDay(expiryTime, donSku.getDays() * order.getNum());
 					} else {
-						newDate = DateUtil.offset(expiryTime, DateField.MONTH, donSku.getMonths() * order.getNum());
+						//奈飞月付 按30天计算
+						if (sku.getId() == 4) {
+							newDate = DateUtil.offsetDay(expiryTime, 30 * order.getNum());
+						} else {
+							newDate = DateUtil.offset(expiryTime, DateField.MONTH, donSku.getMonths() * order.getNum());
+						}
 					}
 					relation.setExpiryTime(newDate);
 					relation.setStartTime(relation.getStartTime() == null ? new Date() : null);
@@ -3074,4 +3085,65 @@ public class OrderDonServiceImpl extends ServiceImpl<OrderDonMapper, OrderDon> i
 		}
 		orderDon.setMoney(price);
 	}
+
+
+	@Override
+	public UpgradeOrderDon submitUpgrade(OrderPayRequest payRequest) {
+		GroupsRelation groupsRelation = getGroupsRelation(payRequest.getUserId(), payRequest.getRelationId());
+		GroupsTrips groupsTrips = getGroupsTrips(groupsRelation);
+		GoodsDonSku goodsDonSku = goodsDonSkuMapper.selectById(groupsTrips.getSkuId());
+
+		if (goodsDonSku != null && goodsDonSku.getIsMirror()) {
+			UpgradePackage upgradePackage = upgradePackageMapper.selectById(payRequest.getPackageId());
+			if (upgradePackage == null) {
+				throw BusinessRuntimeException.getInstance("套餐包不存在");
+			}
+			MidjourneyUser midjourneyUser = midjourneyUserMapper.selectOne(Wrappers.lambdaQuery(MidjourneyUser.class).eq(MidjourneyUser::getRelationId, payRequest.getRelationId()));
+			if (midjourneyUser != null){
+				String donNo = SEQUENCE.nextId().toString();
+				UpgradeOrderDon upgradeOrderDon = new UpgradeOrderDon();
+				upgradeOrderDon.setOrderNo(donNo);
+				upgradeOrderDon.setUserId(payRequest.getUserId());
+				upgradeOrderDon.setOriginalOrderId(groupsRelation.getOrderId());
+				upgradeOrderDon.setPackageId(payRequest.getPackageId());
+				upgradeOrderDon.setGoodsId(groupsTrips.getGoodsId());
+				upgradeOrderDon.setMoney(payRequest.getDonMoney());
+				upgradeOrderDon.setStatus(UpgradeOrderDon.Status.noPayment);
+				upgradeOrderDon.setType(UpgradeOrderDon.Type.ALI_PAY);
+				upgradeOrderDonMapper.insert(upgradeOrderDon);
+				return upgradeOrderDon;
+			}
+		}
+		return null;
+	}
+
+	/**
+	 * 获取车位信息
+	 *
+	 * @param userId
+	 * @param relationId
+	 * @return
+	 */
+	private GroupsRelation getGroupsRelation(Long userId, Long relationId) {
+		List<Long> userIdList = userBindRelationService.getRelationUserIdList(userId, null);
+		GroupsRelation groupsRelation = groupsRelationMapper.selectOne(Wrappers.lambdaQuery(GroupsRelation.class).in(GroupsRelation::getUserId, userIdList).eq(GroupsRelation::getId, relationId));
+		if (groupsRelation == null) {
+			throw BusinessRuntimeException.getInstance("车票不存在");
+		}
+		return groupsRelation;
+	}
+
+	/**
+	 * 获取车队信息
+	 *
+	 * @param groupsRelation
+	 * @return
+	 */
+	private GroupsTrips getGroupsTrips(GroupsRelation groupsRelation) {
+		GroupsTrips groupsTrips = groupsMapper.selectById(groupsRelation.getGroupsId());
+		if (groupsTrips == null) {
+			throw BusinessRuntimeException.getInstance("车队异常");
+		}
+		return groupsTrips;
+	}
 }

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

@@ -6,6 +6,7 @@ import com.cyksj.model.entity.GroupsRelation;
 import com.cyksj.model.request.SpecialGoodsTicketReq;
 import com.cyksj.model.views.RenewalView;
 import com.cyksj.model.views.UserRecommendGoodsFrontView;
+import com.ejlchina.searcher.SearchResult;
 
 import java.util.List;
 
@@ -16,7 +17,7 @@ import java.util.List;
  *创建时间:2022/12/29 15:42
  */
 public interface GroupRelationFrontService {
-	List<RenewalView> getMyTicket(long userId, Boolean isLoginPopularize, String customId);
+	SearchResult<RenewalView> getMyTicket(long userId, Boolean isLoginPopularize, String customId, String account);
 
 	Boolean isJoinCorpWx(Long userId, Boolean isJoin, Boolean noCoupon);
 
@@ -50,4 +51,6 @@ public interface GroupRelationFrontService {
 	void setGroupsTripsParkingTimeEmpty(GoodsDonSku sku, Long relationId);
 
 	Integer getUserCodeNumBySkuId(Long userId, Long skuId, Boolean isHasVerifyCode);
+
+	List<RenewalView>  getHasPayGoods(long userId);
 }

+ 20 - 13
netflix-service/src/main/java/com/cyksj/service/relation/impl/GroupRelationFrontServiceImpl.java

@@ -31,6 +31,7 @@ import com.cyksj.service.shop.YhShopFrontService;
 import com.cyksj.service.user.UserBindRelationService;
 import com.cyksj.service.user.UserLoginRecordService;
 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;
@@ -43,7 +44,6 @@ import javax.servlet.http.HttpServletRequest;
 import java.util.*;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
-import java.util.stream.Collectors;
 
 import static com.cyksj.enums.GatewayApiCode.GROUP_INDEX_ALREADY_BE_USER;
 import static com.cyksj.enums.GatewayApiCode.GROUP_INDEX_NOT_FIND;
@@ -101,33 +101,31 @@ public class GroupRelationFrontServiceImpl implements GroupRelationFrontService
 	private final static String VERIFY_CODE_SECRET = "q1w2e3";
 
 	@Override
-	public List<RenewalView> getMyTicket(long userId, Boolean isLoginPopularize, String customId) {
+	public SearchResult<RenewalView> getMyTicket(long userId, Boolean isLoginPopularize, String customId, String account) {
 		User u = userMapper.selectById(userId);
 		if (u == null) throw BusinessRuntimeException.getGatewayApiCode(GatewayApiCode.CMS_TOKEN_VALID);
 		if (u.getIsBlack()) {
-			return new ArrayList<>();
+			return new SearchResult<>();
 		}
 		List<Long> userIds = userBindRelationService.getRelationUserIdList(userId, u);
 		MapBuilder builder = MapUtils.flatBuilder(request.getParameterMap());
 		//Long yhsId = yhShopFrontService.getYhsIdByCustomId(customId);
-		List<RenewalView> list = beanSearcher.searchAll(RenewalView.class, builder
+		DateTime now = DateTime.now();
+		if (StrUtil.isNotBlank(account)) {
+			builder.field(RenewalView::getAccount, account).op(Operator.Contain);
+		}
+		SearchResult<RenewalView> list = beanSearcher.search(RenewalView.class, builder
 				.field(RenewalView::getUserId, 0).op(Operator.GreaterThan)
 				.field(RenewalView::getUserId, userIds).op(Operator.InList)
 				//.field(RenewalView::getYhsId, yhsId)
+				.field("condition", String.format("(gr.expiry_time is null or gr.expiry_time > '%s')", now))
 				.field(RenewalView::getStatus, List.of("validity", "overdue", "outside")).op(Operator.InList)
 				.orderBy(RenewalView::getExpiryTime).asc()
 				.build());
 		//过滤邀请制、已失效的车位
-		DateTime now = DateTime.now();
-		list = list.stream().filter(e -> {
-			if (e.getExpiryTime() != null && e.getExpiryTime().before(now)) {
-				return false;
-			}
-			return true;
-		}).collect(Collectors.toList());
-		Integer size = list.size();
+		Integer size = list.getTotalCount().intValue();
 
-		list.forEach(ticket -> {
+		list.getDataList().forEach(ticket -> {
 			if (ticket.getSkuId() == null || ticket.getGoodsId() == null) {
 				return;
 			}
@@ -604,6 +602,15 @@ public class GroupRelationFrontServiceImpl implements GroupRelationFrontService
 		return num;
 	}
 
+	@Override
+	public List<RenewalView> getHasPayGoods(long userId) {
+		User user = userMapper.selectById(userId);
+		List<Long> userIds = userBindRelationService.getRelationUserIdList(userId, user);
+		DateTime now = DateTime.now();
+		List<RenewalView> list = groupsRelationMapper.getUserHasPayGoods(userIds, now);
+		return list;
+	}
+
 	public String getDifferentGoodsCode(Long goodsId, String body, Integer type) {
 		String code = null;
 		//奈飞

+ 10 - 3
netflix-web/src/main/java/com/cyksj/web/controller/group/GroupRelationController.java

@@ -19,7 +19,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.*;
@@ -45,6 +44,7 @@ import com.cyksj.service.user.UserBindRelationService;
 import com.cyksj.service.user.UserService;
 import com.cyksj.web.util.StpUserUtil;
 import com.ejlchina.searcher.BeanSearcher;
+import com.ejlchina.searcher.SearchResult;
 import com.ejlchina.searcher.param.Operator;
 import com.ejlchina.searcher.util.MapUtils;
 import lombok.RequiredArgsConstructor;
@@ -121,12 +121,19 @@ public class GroupRelationController {
     private final static Sequence SEQUENCE = new Sequence(0);
 
     @RequestMapping("/get/renewal")
-    public Result<List<RenewalView>> get(Boolean isLoginPopularize, String customId) {
+    public Result<SearchResult<RenewalView>> get(Boolean isLoginPopularize, String customId, String account) {
         long userId = StpUserUtil.getLoginIdAsLong();
-        List<RenewalView> list = groupRelationFrontService.getMyTicket(userId, isLoginPopularize, customId);
+        SearchResult<RenewalView> list = groupRelationFrontService.getMyTicket(userId, isLoginPopularize, customId, account);
         return GatewayResponse.SUCCESS.newBuilder().toResult(list);
     }
 
+    @GetMapping("/get/pay/goods")
+    public Result<List<RenewalView>> getHasPayGoods() {
+        long userId = StpUserUtil.getLoginIdAsLong();
+        List<RenewalView> hasPayGoods = groupRelationFrontService.getHasPayGoods(userId);
+        return GatewayResponse.SUCCESS.newBuilder().toResult(hasPayGoods);
+    }
+
     @PostMapping("/post/renewal")
     public Result<OrderDon> renewal(@RequestBody OrderPayRequest payRequest) throws Exception {
         long userId = StpUserUtil.getLoginIdAsLong();

+ 15 - 4
netflix-web/src/main/java/com/cyksj/web/controller/manage/CmsUserController.java

@@ -82,10 +82,12 @@ public class CmsUserController{
 
     private final CmsUserMapper cmsUserMapper;
 
+    private final UserCertRecordMapper userCertRecordMapper;
+
     private final UserDoubleVerifyCodeChangeRecordMapper userDoubleVerifyCodeChangeRecordMapper;
 
     @GetMapping("/get")
-    public Result<SearchResult<UserView>> get(Long id, String otherPhone, Long sharedId, String userid, Long businessId, String sort, String order) {
+    public Result<SearchResult<UserView>> get(Long id, String otherPhone, Long sharedId, String userid, Long businessId, String sort, String order, Boolean isCert) {
         MapBuilder builder = MapUtils.flatBuilder(request.getParameterMap());
         String otherSql = StrUtil.EMPTY;
         if (StrUtil.isNotBlank(otherPhone)) {
@@ -103,24 +105,33 @@ public class CmsUserController{
                 builder.field(UserView::getId, relationUserIdList).op(Operator.InList);
             }
         }
+        if (isCert != null) {
+            if (StrUtil.isNotBlank(otherSql)) {
+                otherSql += " and ";
+            }
+            otherSql += "exists (select 1 from user_cert_record where user_id = u.id)";
+        }
         if (StrUtil.isNotBlank(otherSql)) {
             builder.put("otherConditionSql", otherSql);
         }
         SearchResult<UserView> search = beanSearcher.search(UserView.class, builder.build());
-        search.getDataList().forEach(data->{
+        search.getDataList().forEach(data -> {
             Long userId = data.getId();
             UserBindDetail userBindDetail = beanSearcher.searchFirst(UserBindDetail.class, MapUtils.builder().field(UserBindDetail::getUserId, userId).onlySelect(UserBindDetail::getPhone, UserBindDetail::getEmail).build());
-            Optional.ofNullable(userBindDetail).ifPresent(bind->{
+            Optional.ofNullable(userBindDetail).ifPresent(bind -> {
                 data.setBindEmail(bind.getEmail());
                 data.setBindPhone(bind.getPhone());
             });
             if (data.getSharedId() != null) {
                 UserDistributeBusinessInfoView userDistributeBusinessInfoView = beanSearcher.searchFirst(UserDistributeBusinessInfoView.class, MapUtils.builder().field(UserDistributeBusinessInfoView::getUserId, data.getSharedId()).build());
-                Optional.ofNullable(userDistributeBusinessInfoView).ifPresent(info->{
+                Optional.ofNullable(userDistributeBusinessInfoView).ifPresent(info -> {
                     data.setDistributeName(info.getDistributeName());
                     data.setBusinessName(info.getBusinessName());
                 });
             }
+            Integer selectCount = userCertRecordMapper.selectCount(Wrappers.lambdaQuery(UserCertRecord.class)
+                    .eq(UserCertRecord::getUserId, userId));
+            data.setIsCert(selectCount > 0 ? true : false);
         });
         return GatewayResponse.SUCCESS.newBuilder().toResult(search);
     }

+ 16 - 14
netflix-web/src/main/java/com/cyksj/web/controller/manage/corp/WxCorpController.java

@@ -18,10 +18,13 @@ import com.cyksj.dto.CorpOauth2UserInfo;
 import com.cyksj.dto.Result;
 import com.cyksj.enums.GatewayResponse;
 import com.cyksj.mapper.GroupsRelationExpiryRecordMapper;
-import com.cyksj.mapper.UserMapper;
+import com.cyksj.mapper.corp.CorpUserAuthMapper;
 import com.cyksj.mapper.corp.CorpUserTagMapper;
 import com.cyksj.model.dto.AuthRedirect;
-import com.cyksj.model.entity.*;
+import com.cyksj.model.entity.CorpCustomerAcquistionCallback;
+import com.cyksj.model.entity.CorpFollow;
+import com.cyksj.model.entity.CorpMsgFollowAssociation;
+import com.cyksj.model.entity.QyMsgContent;
 import com.cyksj.model.manage.views.CorpQyMsgAuditChatView;
 import com.cyksj.model.request.corp.CorpCommonReq;
 import com.cyksj.model.views.CorpUserIntentionView;
@@ -78,7 +81,7 @@ public class WxCorpController {
 
 	private final CorpUserTagMapper corpUserTagMapper;
 
-	private final UserMapper userMapper;
+	private final CorpUserAuthMapper corpUserAuthMapper;
 
 	private final static String CORP_UUID = "corp-uuid";
 
@@ -323,18 +326,17 @@ public class WxCorpController {
 	 * @Param unionId 用户unionId
 	 */
 	@GetMapping("/acquistionLinkCallback")
-	public Result<CorpCustomerAcquistionCallback> getAcquistionLinkCallback(Long userId) {
-		MapBuilder builder = MapUtils.flatBuilder(request.getParameterMap());
-		if (userId != null) {
-			User user = userMapper.selectById(userId);
-			if (user != null && StrUtil.isNotBlank(user.getUnionid())) {
-				builder.field(CorpCustomerAcquistionCallback::getUnionId, user.getUnionid());
-			}
-
-			CorpCustomerAcquistionCallback corpCustomerAcquistionCallback = beanSearcher.searchFirst(CorpCustomerAcquistionCallback.class, builder.build());
-			return GatewayResponse.SUCCESS.newBuilder().toResult(corpCustomerAcquistionCallback);
+	public Result<CorpCustomerAcquistionCallback> getAcquistionLinkCallback(String externalUserId) {
+		if (StrUtil.isEmpty(externalUserId)) {
+			return GatewayResponse.SUCCESS.newBuilder().toResult();
 		}
-		return GatewayResponse.SUCCESS.newBuilder().toResult();
+		String unionId = corpUserAuthMapper.getUnionIdByExternalUserId(externalUserId);
+		if (StrUtil.isEmpty(unionId)) {
+			return GatewayResponse.SUCCESS.newBuilder().toResult();
+		}
+		MapBuilder builder = MapUtils.flatBuilder(request.getParameterMap()).field(CorpCustomerAcquistionCallback::getUnionId, unionId);
+		CorpCustomerAcquistionCallback corpCustomerAcquistionCallback = beanSearcher.searchFirst(CorpCustomerAcquistionCallback.class, builder.build());
+		return GatewayResponse.SUCCESS.newBuilder().toResult(corpCustomerAcquistionCallback);
 	}
 
 	/**

+ 106 - 0
netflix-web/src/main/java/com/cyksj/web/controller/manage/mj/MidJourneyController.java

@@ -0,0 +1,106 @@
+package com.cyksj.web.controller.manage.mj;
+
+import cn.hutool.core.util.StrUtil;
+import com.cyksj.dto.Result;
+import com.cyksj.enums.GatewayResponse;
+import com.cyksj.model.entity.MidjourneyAccount;
+import com.cyksj.model.manage.views.AccountView;
+import com.cyksj.model.views.MidjourneyAccountView;
+import com.cyksj.service.midjourney.MidjourneyAccountService;
+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;
+import org.springframework.web.bind.annotation.*;
+
+import javax.servlet.http.HttpServletRequest;
+
+/**
+ * @author zwhui
+ * @date 2024/4/15 14:38
+ */
+@Slf4j
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/manage/mj")
+public class MidJourneyController {
+
+    private final BeanSearcher beanSearcher;
+
+    private final HttpServletRequest request;
+
+    private final MidjourneyAccountService midjourneyAccountService;
+
+
+    /**
+     * 移入MJ账号池
+     */
+    @PostMapping("/addAccount")
+    public Result<Void> addAccount(@RequestBody MidjourneyAccount midjourneyAccount) {
+        log.info("移入MJ账号池 midjourneyAccount:{}", midjourneyAccount);
+        midjourneyAccountService.addAccount(midjourneyAccount);
+        return GatewayResponse.SUCCESS.newBuilder().toResult();
+    }
+
+    /**
+     * 移除MJ账号池
+     */
+    @DeleteMapping("/removeAccount/{id}")
+    public Result<Void> removeAccount(@PathVariable Long id) {
+        log.info("移除MJ账号池 id:{}", id);
+        midjourneyAccountService.removeAccount(id);
+        return GatewayResponse.SUCCESS.newBuilder().toResult();
+    }
+
+    /**
+     * 修改MJ账号池
+     */
+    @PutMapping("/updateAccount")
+    public Result<Void> updateAccount(@RequestBody MidjourneyAccount midjourneyAccount) {
+        log.info("修改MJ账号池 midjourneyAccount:{}", midjourneyAccount);
+        midjourneyAccountService.updateAccount(midjourneyAccount);
+        return GatewayResponse.SUCCESS.newBuilder().toResult();
+    }
+
+    /**
+     * 上下架MJ账号
+     */
+    @PutMapping("/updateStatus/{id}")
+    public Result<Void> updateStatus(@PathVariable Long id) {
+        log.info("上下架MJ账号 id:{}", id);
+        midjourneyAccountService.updateStatus(id);
+        return GatewayResponse.SUCCESS.newBuilder().toResult();
+    }
+
+    /**
+     * 同步账号信息
+     */
+    @PutMapping("/syncAccount/{id}")
+    public Result<Void> syncAccount(@PathVariable Long id) {
+        log.info("同步账号信息 id:{}", id);
+        midjourneyAccountService.syncAccount(id);
+        return GatewayResponse.SUCCESS.newBuilder().toResult();
+    }
+
+
+    /**
+     * 查询账号池列表
+     */
+    @GetMapping("/getAccount")
+    public Result<SearchResult<MidjourneyAccountView>> getAccount(String expiryStartTime, String expiryEndTime) {
+        log.info("查询账号池列表");
+        MapBuilder mapBuilder = MapUtils.flatBuilder(request.getParameterMap());
+        if (StrUtil.isNotEmpty(expiryStartTime) || StrUtil.isNotEmpty(expiryEndTime)) {
+            mapBuilder.field(AccountView::getExpiryTime, expiryStartTime, expiryEndTime)
+                    .op(Operator.Between);
+        }
+        SearchResult<MidjourneyAccountView> search = beanSearcher.search(MidjourneyAccountView.class, mapBuilder.build());
+        return GatewayResponse.SUCCESS.newBuilder().toResult(search);
+    }
+
+
+
+}

+ 121 - 0
netflix-web/src/main/java/com/cyksj/web/controller/manage/upgrade/UpgradePackageController.java

@@ -0,0 +1,121 @@
+package com.cyksj.web.controller.manage.upgrade;
+
+import cn.dev33.satoken.annotation.SaCheckPermission;
+import cn.hutool.core.map.MapUtil;
+import com.cyksj.common.annotation.Log;
+import com.cyksj.common.exception.BusinessRuntimeException;
+import com.cyksj.dto.Result;
+import com.cyksj.enums.BusinessType;
+import com.cyksj.enums.GatewayResponse;
+import com.cyksj.model.entity.UpgradePackage;
+import com.cyksj.model.views.UpgradePackageView;
+import com.cyksj.service.mange.upgrade.UpgradePackageService;
+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;
+import org.springframework.web.bind.annotation.*;
+
+import javax.servlet.http.HttpServletRequest;
+import java.util.Map;
+
+
+/**
+ * @author zwhui
+ * @date 2024/4/24 15:06
+ */
+@Slf4j
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/manage/upgrade")
+public class UpgradePackageController {
+
+    private final UpgradePackageService upgradePackageService;
+
+    private final HttpServletRequest request;
+
+    private final BeanSearcher beanSearcher;
+
+    /**
+     * 新增套餐
+     */
+    @PostMapping
+    @SaCheckPermission("upgrade:add")
+    @Log(module = "套餐管理/新增套餐", businessType = BusinessType.POST, isSaveRequestData = true)
+    public Result<String> post(@RequestBody UpgradePackage upgradePackage){
+        log.info("新增套餐:{}", upgradePackage);
+        upgradePackageService.save(upgradePackage);
+        return GatewayResponse.SUCCESS.newBuilder().toResult();
+    }
+
+    /**
+     * 修改套餐
+     */
+    @PutMapping
+    @SaCheckPermission("upgrade:edit")
+    @Log(module = "套餐管理/修改套餐", businessType = BusinessType.PUT, isSaveRequestData = true)
+    public Result<String> put(@RequestBody UpgradePackage upgradePackage){
+        log.info("修改套餐:{}", upgradePackage);
+        upgradePackageService.updateById(upgradePackage);
+        return GatewayResponse.SUCCESS.newBuilder().toResult();
+    }
+
+    /**
+     * 删除套餐
+     */
+    @DeleteMapping("/{id}")
+    @SaCheckPermission("upgrade:delete")
+    @Log(module = "套餐管理/删除套餐", businessType = BusinessType.DELETE, isSaveRequestData = true)
+    public Result<String> delete(@PathVariable Long id){
+        log.info("删除套餐:{}", id);
+        UpgradePackage byId = upgradePackageService.getById(id);
+        if (byId == null){
+            throw BusinessRuntimeException.getInstance("套餐不存在");
+        }
+        byId.setDeleted(false);
+        upgradePackageService.updateById(byId);
+        return GatewayResponse.SUCCESS.newBuilder().toResult();
+    }
+
+    /**
+     * 上下架套餐
+     */
+    @PutMapping("/put/status/{id}")
+    @SaCheckPermission("upgrade:putStatus")
+    @Log(module = "套餐管理/上下架套餐", businessType = BusinessType.PUT, isSaveRequestData = true)
+    public Result<Boolean> putStatus(@PathVariable Long id){
+        log.info("上下架套餐:{}", id);
+        UpgradePackage byId = upgradePackageService.getById(id);
+        if (byId == null){
+            throw BusinessRuntimeException.getInstance("套餐不存在");
+        }
+        byId.setStatus(!byId.getStatus());
+        upgradePackageService.updateById(byId);
+        return GatewayResponse.SUCCESS.newBuilder().toResult(byId.getStatus());
+    }
+
+    /**
+     * 获取套餐
+     */
+    @GetMapping("/{id}")
+    public Result<UpgradePackage> get(@PathVariable Long id){
+        log.info("获取套餐:{}", id);
+        UpgradePackage byId = upgradePackageService.getById(id);
+        return GatewayResponse.SUCCESS.newBuilder().toResult(byId);
+    }
+
+    /**
+     * 获取套餐列表
+     */
+    @GetMapping
+    public Result<SearchResult<UpgradePackageView>> list() {
+        log.info("获取套餐列表");
+        Map<String, Object> build = MapUtils.flatBuilder(request.getParameterMap()).build();
+        SearchResult<UpgradePackageView> search = beanSearcher.search(UpgradePackageView.class, build);
+        return GatewayResponse.SUCCESS.newBuilder().toResult(search);
+    }
+
+
+}

+ 161 - 0
netflix-web/src/main/java/com/cyksj/web/controller/mirror/MidjourneyController.java

@@ -0,0 +1,161 @@
+package com.cyksj.web.controller.mirror;
+
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.cyksj.dto.Result;
+import com.cyksj.model.dto.*;
+import com.cyksj.enums.GatewayResponse;
+import com.cyksj.mapper.MidjourneyUserMapper;
+import com.cyksj.model.entity.MidjourneyUser;
+import com.cyksj.model.entity.MidjourneyUserConversation;
+import com.cyksj.service.midjourney.MidjourneyAccountService;
+import com.cyksj.service.midjourney.MidjourneyService;
+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;
+import org.springframework.web.bind.annotation.*;
+
+import javax.servlet.http.HttpServletRequest;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * @author zwhui
+ * @date 2024/4/23 10:31
+ */
+@Slf4j
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/applets/midjourney")
+public class MidjourneyController {
+
+    private final MidjourneyAccountService midjourneyAccountService;
+
+    private final MidjourneyUserMapper midjourneyUserMapper;
+
+    private final HttpServletRequest request;
+
+    private final MidjourneyService midjourneyService;
+
+    private final BeanSearcher beanSearcher;
+
+    public MidjourneyUser getUser(){
+        return midjourneyUserMapper.selectOne(Wrappers.lambdaQuery(MidjourneyUser.class)
+                .eq(MidjourneyUser::getUserToken, request.getHeader("user-token")).last("limit 1"));
+    }
+
+
+    /**
+     * 检查用户fast次数
+     */
+    public void checkUserFast(MidjourneyUser user){
+       if (user.getMode() == 1){
+           if (user.getMjFastNum() < 0 || user.getExpireTime().before(new Date())) {
+               user.setMode(2);
+               midjourneyUserMapper.updateById(user);
+           }
+       }
+    }
+
+
+
+    /**
+     * 提交Imagine任务
+     */
+    @PostMapping("/submit/imagine")
+    public Result<MidjourneyUserConversation> submitImagine(SubmitImagineDTO submitImagineDTO){
+        log.info("提交Imagine任务,提示:{},base64数组长度:{}",submitImagineDTO.getPrompt(),submitImagineDTO.getBase64Array().size());
+        MidjourneyUser user = getUser();
+        checkUserFast(user);
+        return GatewayResponse.SUCCESS.newBuilder().toResult(midjourneyService.submitImagine(user,submitImagineDTO.getPrompt(),submitImagineDTO.getBase64Array()));
+    }
+
+    /**
+     * 提交Describe任务
+     */
+    @PostMapping("/submit/describe")
+    public Result<MidjourneyUserConversation> submitDescribe(SubmitDescribeDTO submitDescribeDTO){
+        log.info("提交Describe任务");
+        MidjourneyUser user = getUser();
+        checkUserFast(user);
+        return GatewayResponse.SUCCESS.newBuilder().toResult(midjourneyService.submitDescribe(user,submitDescribeDTO.getBase64()));
+    }
+
+    /**
+     * 提交Blend任务
+     */
+    @PostMapping("/submit/blend")
+    public Result<MidjourneyUserConversation> submitBlend(SubmitBlendDTO submitBlendDTO) {
+        log.info("提交Blend任务 dimensions:{},base64数组长度:{}", submitBlendDTO.getDimensions(), submitBlendDTO.getBase64Array().size());
+        MidjourneyUser user = getUser();
+        checkUserFast(user);
+        return GatewayResponse.SUCCESS.newBuilder().toResult(midjourneyService.submitBlend(user, submitBlendDTO.getDimensions(), submitBlendDTO.getBase64Array()));
+    }
+
+    /**
+     * 提交Modal任务
+     */
+    @PostMapping("/submit/modal")
+    public Result<MidjourneyUserConversation> submitModal(SubmitModalDTO submitModalDTO){
+        log.info("提交Modal任务,taskId:{},提示:{},base64数组长度:{}",submitModalDTO.getTaskId(),submitModalDTO.getPrompt(),submitModalDTO.getMaskBase64().length());
+        MidjourneyUser user = getUser();
+        checkUserFast(user);
+        return GatewayResponse.SUCCESS.newBuilder().toResult(midjourneyService.submitModal(user,submitModalDTO.getTaskId(),submitModalDTO.getPrompt(),submitModalDTO.getMaskBase64()));
+    }
+
+    /**
+     * 提交Shorten任务
+     */
+    @PostMapping("/submit/shorten")
+    public Result<MidjourneyUserConversation> submitShorten(SubmitShortenDTO submitShortenDTO){
+        log.info("提交Shorten任务 提示词:{}",submitShortenDTO.getPrompt());
+        MidjourneyUser user = getUser();
+        checkUserFast(user);
+        return GatewayResponse.SUCCESS.newBuilder().toResult(midjourneyService.submitShorten(user,submitShortenDTO.getPrompt()));
+    }
+
+    /**
+     * 执行动作
+     */
+    @PostMapping("/submit/action")
+    public Result<MidjourneyUserConversation> action(SubmitActionDTO actionDTO){
+        log.info("任务id:{},执行动作:{}",actionDTO.getTaskId(),actionDTO.getCustomId());
+        MidjourneyUser user = getUser();
+        checkUserFast(user);
+        return GatewayResponse.SUCCESS.newBuilder().toResult(midjourneyService.submitAction(user,actionDTO.getTaskId(), actionDTO.getCustomId()));
+    }
+
+
+    /**
+     * 查询会话列表
+     */
+    @GetMapping("/conversation/list")
+    public Result<SearchResult<MidjourneyUserConversation>> conversationList(){
+        MidjourneyUser user = getUser();
+        log.info("查询会话列表 userId:{}",user.getId());
+        MapBuilder builder = MapUtils.flatBuilder(request.getParameterMap());
+        return GatewayResponse.SUCCESS.newBuilder().toResult(beanSearcher.search(MidjourneyUserConversation.class,
+                builder.field(MidjourneyUserConversation::getUserId, user.getId()).build()));
+    }
+
+    /**
+     * 根据ids查询会话
+     */
+    @GetMapping("/conversation/listByIds")
+    public Result<List<MidjourneyUserConversation>> conversationListByIds(@RequestParam(value = "ids" ) List<Long> ids){
+        log.info("根据ids查询会话");
+        return GatewayResponse.SUCCESS.newBuilder().toResult(midjourneyService.listConversationByIds(ids));
+    }
+
+    /**
+     * 取消任务
+     */
+    @PostMapping("/conversation/{id}/cancel")
+    public Result<MidjourneyUserConversation> conversationCancel(@PathVariable("id") Long id){
+        MidjourneyUser user = getUser();
+        log.info("取消任务 id:{}",id);
+        return GatewayResponse.SUCCESS.newBuilder().toResult(midjourneyService.cancelConversation(user,id));
+    }
+}

+ 19 - 6
netflix-web/src/main/java/com/cyksj/web/controller/mirror/MirrorController.java

@@ -14,6 +14,7 @@ import com.cyksj.model.views.ChatGptUserConversationRecordHistoryView;
 import com.cyksj.model.views.ChatGptUserView;
 import com.cyksj.model.views.ChatgptCarInfoView;
 import com.cyksj.service.chatgpt.ChatGptAccountService;
+import com.cyksj.service.midjourney.MidjourneyAccountService;
 import com.cyksj.web.util.StpUserUtil;
 import com.ejlchina.searcher.BeanSearcher;
 import com.ejlchina.searcher.SearchResult;
@@ -53,6 +54,8 @@ public class MirrorController {
 
     private final BeanSearcher beanSearcher;
 
+    private final MidjourneyAccountService midjourneyAccountService;
+
 
     /**
      * GPT车票跳转登录
@@ -75,6 +78,7 @@ public class MirrorController {
     @RequestMapping("/gpt/oauth")
     public Result<String> gptOauth(@RequestParam("usertoken") String userToken, @RequestParam("carid") String carId) {
         try {
+            log.info("用户通过userToken:{}访问镜像车队carId:{}", userToken, carId);
             ChatgptUser user = chatGptAccountService.findByUserTokenAndExpireTimeAfter(userToken, LocalDateTime.now());
             if (user == null) {
                 return GatewayResponse.SUCCESS.newBuilder().setMsg("用户不存在或已过期").setCode(0).toResult();
@@ -82,6 +86,7 @@ public class MirrorController {
 
             ChatgptSession session = chatGptAccountService.checkSession(carId);
             if (session.getIsCar()) {
+                log.info("用户:{}通过userToken:{}访问镜像车队carId:{}成功", user.getName(), userToken, carId);
                 return GatewayResponse.SUCCESS.newBuilder().setMsg("登陆成功").setCode(1).toResult();
             }
         } catch (Exception e) {
@@ -177,15 +182,14 @@ public class MirrorController {
      * @return
      */
     @GetMapping("/gpt/cars")
-    public Result<Set<ChatgptCarInfoView>> getCarInfoList(Long relationId) {
+    public Result<Set<ChatgptCarInfoView>> getCarInfoList(Long relationId,@RequestParam(defaultValue = "10") Integer limit,@RequestParam(defaultValue = "false") Boolean isPlus) {
         long userId = StpUserUtil.getLoginIdAsLong();
         //查看用户是否存在车票
         ChatgptUser carChatGptUser = chatGptAccountService.getCarChatGptUser(userId, relationId);
         if (carChatGptUser == null) {
             throw BusinessRuntimeException.getInstance("您还未购买车票");
         }
-
-        Set<ChatgptCarInfoView> carInfoList = chatGptAccountService.getCarInfoList(carChatGptUser.getUserToken());
+        Set<ChatgptCarInfoView> carInfoList = chatGptAccountService.getCarInfoList(carChatGptUser.getUserToken(),10, isPlus);
         return GatewayResponse.SUCCESS.newBuilder().toResult(carInfoList);
     }
 
@@ -264,14 +268,13 @@ public class MirrorController {
      * 根据userToken获取车队列表
      */
     @GetMapping("/gpt/cars/withToken")
-    public Result<Set<ChatgptCarInfoView>> getCarInfoListWithToken(String userToken) {
+    public Result<Set<ChatgptCarInfoView>> getCarInfoListWithToken(String userToken,@RequestParam(defaultValue = "10") Integer limit, @RequestParam(defaultValue = "false") Boolean isPlus) {
         //查看用户是否存在车票
         ChatgptUser carChatGptUser = chatGptAccountService.getCarChatGptUserWithToken(userToken);
         if (carChatGptUser == null) {
             throw BusinessRuntimeException.getInstance("您还未购买车票");
         }
-
-        Set<ChatgptCarInfoView> carInfoList = chatGptAccountService.getCarInfoList(carChatGptUser.getUserToken());
+        Set<ChatgptCarInfoView> carInfoList = chatGptAccountService.getCarInfoList(carChatGptUser.getUserToken(), limit, isPlus);
         return GatewayResponse.SUCCESS.newBuilder().toResult(carInfoList);
     }
 
@@ -291,4 +294,14 @@ public class MirrorController {
 
 
 
+    /**
+     * MJ车票跳转登录
+     *
+     * @param relationId 车票id
+     */
+    @GetMapping("/midjourneyMirror/{relationId}")
+    public Result<String> midjourneyMirror(@PathVariable Long relationId) throws IOException {
+        Long userId = StpUserUtil.getLoginIdAsLong();
+        return GatewayResponse.SUCCESS.newBuilder().toResult(midjourneyAccountService.getLoginUrl(userId, relationId));
+    }
 }

+ 19 - 0
netflix-web/src/main/java/com/cyksj/web/controller/payment/OrderController.java

@@ -167,6 +167,25 @@ public class OrderController {
         return GatewayResponse.SUCCESS.newBuilder().toResult(orderDon);
     }
 
+    /**
+     * 套餐提交支付
+     */
+    @PostMapping("/post/submit")
+    public Result<UpgradeOrderDon> submitUpgrade(@Validated @RequestBody OrderPayRequest payRequest) throws Exception {
+        final String methodName = "套餐吊起支付";
+        Long userId = StpUserUtil.getUserIdAfterLogin();
+        payRequest.setUserId(userId);
+        log.info("{}[start] params:{}", methodName, payRequest);
+
+        String ip = ServletUtil.getClientIP(request);
+
+        payRequest.setIp(ip);
+
+        UpgradeOrderDon orderDon = orderDonService.submitUpgrade(payRequest);
+
+        return GatewayResponse.SUCCESS.newBuilder().toResult(orderDon);
+    }
+
     /**
      * 0元订单确认
      */

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 0 - 0
netflix-web/src/main/resources/application-dev.yml


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 0 - 0
netflix-web/src/main/resources/application-prd.yml


+ 9 - 5
netflix-web/src/main/resources/application-pre.yml

@@ -92,8 +92,12 @@ sa-token:
   timeout: 2592000
   # token临时有效期 (指定时间内无操作就视为token过期) 单位: 秒
   activity-timeout: -1
+  # 是否允许同一账号多地同时登录 (为 true 时允许一起登录, 为 false 时新登录挤掉旧登录)
+  is-concurrent: true
   # 在多人登录同一账号时,是否共用一个token (为true时所有登录共用一个token, 为false时每次登录新建一个token)
   is-share: false
+  # 同一账号最大登录数量
+  maxLoginCount: 3
   # token风格
   token-style: uuid
 
@@ -123,7 +127,7 @@ wechat:
   oldAppid: wxd58016eee53b6558
   appid: wx6cbc2de2a55e5579
   secret: 2ab6340e7787ab24de9f29094dee9d24
-  domain: https://nf.video/8081/api/
+  domain: https://nf.video/8082/api/
   #默认微信商户
   shopid: 1634772026
   shopKey: p2B8BAKi2V3PgMDSSez82V67aIvMKBt5
@@ -145,7 +149,7 @@ wx-login:
 wx-shop-login:
   appid: wx7c5494c38c6a78bd #todo
   secret: 95c7c542a583b42840765d758ec49bf5 #todo
-  redirectUri: https://shop.liuliangbang.vip/8081/api/auth/wx/authLogin/baseRedirect
+  redirectUri: https://shop.liuliangbang.vip/8082/api/auth/wx/authLogin/baseRedirect
   loginUrl: https://shop.liuliangbang.vip/
   remark: 小店店铺网页微信授权
 
@@ -154,7 +158,7 @@ yhlx:
   corpSecret: Ov0mlArSItBrs9EuOMt5Ou_faGdplDDIvPgIhgup51E
   encodingAESKey: bqoACJutQEgW7KOgBoezuQkk7y2HQSyRp1sQ8qnAi6C
   token: 2e0aWIfBewWNN5BNMq9cBeLf9x
-  domain: https://nf.video/8081/api/
+  domain: https://nf.video/8082/api/
 
 #银河录像局小程序
 yhmini:
@@ -167,7 +171,7 @@ advertisement:
   secret: 19b5f5121bc7cc1bc010ee7c4ac509e9
   shopId: 1644299849
   shopKey: 5y5ZScTJGm0q0umHQOD4r3EfjRvCioUx
-  notify: https://nf.video/8081/api/
+  notify: https://nf.video/8082/api/
 
 #广告投放公众号
 advertisementwxapp:
@@ -175,7 +179,7 @@ advertisementwxapp:
   secret: 44c1e7431099fc0bd21dc320822b0108
   shopId: 1644299849
   shopKey: 5y5ZScTJGm0q0umHQOD4r3EfjRvCioUx
-  notify: https://xue.niupian.com.cn/8081/api/
+  notify: https://xue.niupian.com.cn/8082/api/
 
 chatgpt:
   domain: "https://gpt.galaxydvd.com"

Vissa filer visades inte eftersom för många filer har ändrats