Prechádzať zdrojové kódy

mj试用车票;绘画广场;绘画记录

zoujiajian 2 rokov pred
rodič
commit
8d9d59afb0
25 zmenil súbory, kde vykonal 769 pridanie a 7 odobranie
  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/MidjourneyPaintingCollectRecordMapper.java
  3. 22 0
      netflix-dao/src/main/java/com/cyksj/mapper/MidjourneyPaintingPlazaMapper.java
  4. 13 0
      netflix-dao/src/main/java/com/cyksj/mapper/UserReceiveTrialTicketRecordMapper.java
  5. 13 0
      netflix-dao/src/main/java/com/cyksj/mapper/UserTrialTicketJumpPayRecordMapper.java
  6. 27 0
      netflix-dao/src/main/java/com/cyksj/model/entity/MidjourneyPaintingCollectRecord.java
  7. 39 0
      netflix-dao/src/main/java/com/cyksj/model/entity/MidjourneyPaintingPlaza.java
  8. 22 0
      netflix-dao/src/main/java/com/cyksj/model/entity/UserReceiveTrialTicketRecord.java
  9. 16 0
      netflix-dao/src/main/java/com/cyksj/model/entity/UserTrialTicketJumpPayRecord.java
  10. 5 0
      netflix-dao/src/main/java/com/cyksj/model/request/OrderPayRequest.java
  11. 23 0
      netflix-dao/src/main/java/com/cyksj/model/views/MidjourneyPaintingUserView.java
  12. 30 0
      netflix-dao/src/main/java/com/cyksj/model/views/MidjourneyUserPaintingDayRecordView.java
  13. 33 0
      netflix-dao/src/main/java/com/cyksj/model/views/MidjourneyUserPaintingRecordView.java
  14. 6 0
      netflix-dao/src/main/java/com/cyksj/model/views/RenewalView.java
  15. 21 0
      netflix-dao/src/main/resources/mapper/MidjourneyPaintingPlazaMapper.xml
  16. 0 3
      netflix-service/src/main/java/com/cyksj/service/midjourney/MidjourneyAccountService.java
  17. 14 0
      netflix-service/src/main/java/com/cyksj/service/midjourney/MidjourneyPaintingPlazaService.java
  18. 8 2
      netflix-service/src/main/java/com/cyksj/service/midjourney/impl/MidJourneyAccountServiceImpl.java
  19. 33 0
      netflix-service/src/main/java/com/cyksj/service/midjourney/impl/MidjourneyPaintingPlazaServiceImpl.java
  20. 15 0
      netflix-service/src/main/java/com/cyksj/service/order/impl/OrderDonServiceImpl.java
  21. 13 0
      netflix-service/src/main/java/com/cyksj/service/ticket/UserReceiveTrialTicketRecordService.java
  22. 139 0
      netflix-service/src/main/java/com/cyksj/service/ticket/impl/UserReceiveTrialTicketRecordServiceImpl.java
  23. 47 0
      netflix-web/src/main/java/com/cyksj/web/controller/group/MidJourneyGuideController.java
  24. 107 0
      netflix-web/src/main/java/com/cyksj/web/controller/manage/mj/MidjourneyPaintingController.java
  25. 105 2
      netflix-web/src/main/java/com/cyksj/web/controller/mirror/MidjourneyController.java

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

@@ -322,4 +322,9 @@ public interface Constant {
 	 * 大学生快递站 体验车票规格
 	 */
 	Long GPT_MIRROR_SKU_ID = 429l;
+
+	/**
+	 * MJ试用规格id
+	 */
+	Long MIDJOURNEY_TRIAL_SKU_ID = 185L;
 }

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

@@ -0,0 +1,13 @@
+package com.cyksj.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.cyksj.model.entity.MidjourneyPaintingCollectRecord;
+
+/**
+ * 项目名: yhlxj
+ * 文件名: MidjourneyPaintingCollectRecordMapper
+ * 创建者: JavaZou
+ * 创建时间:2024/6/3 17:22
+ */
+public interface MidjourneyPaintingCollectRecordMapper extends BaseMapper<MidjourneyPaintingCollectRecord> {
+}

+ 22 - 0
netflix-dao/src/main/java/com/cyksj/mapper/MidjourneyPaintingPlazaMapper.java

@@ -0,0 +1,22 @@
+package com.cyksj.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.cyksj.model.entity.MidjourneyPaintingPlaza;
+import com.cyksj.model.views.MidjourneyPaintingUserView;
+import org.apache.ibatis.annotations.Param;
+import org.apache.ibatis.annotations.Update;
+
+/**
+ * 项目名: yhlxj
+ * 文件名: MidjourneyPaintingPlazaMapper
+ * 创建者: JavaZou
+ * 创建时间:2024/6/3 17:22
+ */
+public interface MidjourneyPaintingPlazaMapper extends BaseMapper<MidjourneyPaintingPlaza> {
+
+	@Update("update midjourney_painting_plaza set copy_num = copy_num + 1 where id = #{id}")
+	void updatePaintingCopyNum(Long id);
+
+	Page<MidjourneyPaintingUserView> getPaintingList(@Param("page") Page<MidjourneyPaintingUserView> page, @Param("collect") Boolean collect, @Param("userId") Long userId);
+}

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

@@ -0,0 +1,13 @@
+package com.cyksj.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.cyksj.model.entity.UserReceiveTrialTicketRecord;
+
+/**
+ * 项目名: yhlxj
+ * 文件名: UserReceiveTrialTicketRecordMapper
+ * 创建者: JavaZou
+ * 创建时间:2024/6/3 17:58
+ */
+public interface UserReceiveTrialTicketRecordMapper extends BaseMapper<UserReceiveTrialTicketRecord> {
+}

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

@@ -0,0 +1,13 @@
+package com.cyksj.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.cyksj.model.entity.UserTrialTicketJumpPayRecord;
+
+/**
+ * 项目名: yhlxj
+ * 文件名: UserTrialTicketJumpPayRecordMapper
+ * 创建者: JavaZou
+ * 创建时间:2024/6/3 18:27
+ */
+public interface UserTrialTicketJumpPayRecordMapper extends BaseMapper<UserTrialTicketJumpPayRecord> {
+}

+ 27 - 0
netflix-dao/src/main/java/com/cyksj/model/entity/MidjourneyPaintingCollectRecord.java

@@ -0,0 +1,27 @@
+package com.cyksj.model.entity;
+
+import com.cyksj.model.BaseEntity;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * 项目名: yhlxj
+ * 文件名: MidjourneyPaintingCollectRecord
+ * 创建者: JavaZou
+ * 创建时间:2024/6/3 17:18
+ */
+@Getter
+@Setter
+public class MidjourneyPaintingCollectRecord extends BaseEntity {
+	private Long userId;
+
+	/**
+	 * 绘画id
+	 */
+	private Long plazaId;
+
+	/**
+	 * 收藏状态
+	 */
+	private Boolean status;
+}

+ 39 - 0
netflix-dao/src/main/java/com/cyksj/model/entity/MidjourneyPaintingPlaza.java

@@ -0,0 +1,39 @@
+package com.cyksj.model.entity;
+
+import com.cyksj.model.BaseEntity;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * 项目名: yhlxj
+ * 文件名: MidjourneyPaintingPlaza
+ * 创建者: JavaZou
+ * 创建时间:2024/6/3 17:19
+ */
+@Getter
+@Setter
+public class MidjourneyPaintingPlaza extends BaseEntity {
+	/**
+	 * 提示词
+	 */
+	private String tips;
+
+	/**
+	 * 图片
+	 */
+	private String img;
+
+	/**
+	 * 备注
+	 */
+	private String remark;
+
+	/**
+	 * 复制次数
+	 */
+	private Integer copyNum;
+
+	private Boolean status;
+
+	private Boolean deleted;
+}

+ 22 - 0
netflix-dao/src/main/java/com/cyksj/model/entity/UserReceiveTrialTicketRecord.java

@@ -0,0 +1,22 @@
+package com.cyksj.model.entity;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * 项目名: yhlxj
+ * 文件名: UserReceiveTrialTicketRecord
+ * 创建者: JavaZou
+ * 创建时间:2024/6/3 17:53
+ */
+@Getter
+@Setter
+public class UserReceiveTrialTicketRecord extends BaseEntity{
+	private Long userId;
+
+	private Long goodsId;
+
+	private Long skuId;
+
+	private Long relationId;
+}

+ 16 - 0
netflix-dao/src/main/java/com/cyksj/model/entity/UserTrialTicketJumpPayRecord.java

@@ -0,0 +1,16 @@
+package com.cyksj.model.entity;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * 项目名: yhlxj
+ * 文件名: UserTrialTicketJumpPayRecord
+ * 创建者: JavaZou
+ * 创建时间:2024/6/3 18:26
+ */
+@Getter
+@Setter
+public class UserTrialTicketJumpPayRecord extends BaseEntity {
+	private Long orderId;
+}

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

@@ -175,4 +175,9 @@ public class OrderPayRequest {
      * 源订单id
      */
     private Long originalOrderId;
+
+    /**
+     * 是否是试用车票跳转
+     */
+    private Boolean isTrial;
 }

+ 23 - 0
netflix-dao/src/main/java/com/cyksj/model/views/MidjourneyPaintingUserView.java

@@ -0,0 +1,23 @@
+package com.cyksj.model.views;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * 项目名: yhlxj
+ * 文件名: MidjourneyPaintingUserView
+ * 创建者: JavaZou
+ * 创建时间:2024/6/4 13:54
+ */
+@Getter
+@Setter
+public class MidjourneyPaintingUserView {
+
+	private Long id;
+
+	private String tips;
+
+	private String img;
+
+	private Boolean collect;
+}

+ 30 - 0
netflix-dao/src/main/java/com/cyksj/model/views/MidjourneyUserPaintingDayRecordView.java

@@ -0,0 +1,30 @@
+package com.cyksj.model.views;
+
+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.util.List;
+
+/**
+ * 项目名: yhlxj
+ * 文件名: MidjourneyUserPaintingDayRecordView
+ * 创建者: JavaZou
+ * 创建时间:2024/6/4 15:42
+ */
+@Getter
+@Setter
+@SearchBean(tables = "midjourney_user_conversation mc"
+		, where = "mc.status = 'SUCCESS' :condition:"
+		, groupBy = "DATE_FORMAT(mc.created_time,'%Y-%m-%d')",
+		orderBy = "DATE_FORMAT(mc.created_time,'%Y-%m-%d') desc")
+public class MidjourneyUserPaintingDayRecordView {
+
+	@DbField("DATE_FORMAT(mc.created_time,'%Y-%m-%d')")
+	private String date;
+
+	@DbIgnore
+	private List<MidjourneyUserPaintingRecordView> list;
+}

+ 33 - 0
netflix-dao/src/main/java/com/cyksj/model/views/MidjourneyUserPaintingRecordView.java

@@ -0,0 +1,33 @@
+package com.cyksj.model.views;
+
+import com.ejlchina.searcher.bean.DbField;
+import com.ejlchina.searcher.bean.SearchBean;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.Date;
+
+/**
+ * 项目名: yhlxj
+ * 文件名: MidjourneyUserPaintingRecordView
+ * 创建者: JavaZou
+ * 创建时间:2024/6/4 15:40
+ */
+@Getter
+@Setter
+@SearchBean(tables = "midjourney_user_conversation mc",
+		where = "mc.status = 'SUCCESS' :condition: :date:")
+public class MidjourneyUserPaintingRecordView {
+
+	/**
+	 * 提示词
+	 */
+	@DbField("mc.prompt")
+	private String prompt;
+
+	@DbField("mc.image_url")
+	private String imageUrl;
+
+	@DbField("mc.created_time")
+	private Date createdTime;
+}

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

@@ -160,6 +160,12 @@ public class RenewalView {
     @DbField("gr.yhs_id")
     private Long yhsId;
 
+    /**
+     * 车票获取类型 默认1购买,2.体验
+     */
+    @DbField("gr.aq_type")
+    private Integer aqType;
+
     @DbIgnore
     private Date payTime;
 

+ 21 - 0
netflix-dao/src/main/resources/mapper/MidjourneyPaintingPlazaMapper.xml

@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.cyksj.mapper.MidjourneyPaintingPlazaMapper">
+
+    <select id="getPaintingList" resultType="com.cyksj.model.views.MidjourneyPaintingUserView">
+        select mpp.id,
+        mpp.tips,
+        mpp.img,
+        ifnull((select status
+        from midjourney_painting_collect_record pr
+        where pr.plaza_id = mpp.id and user_id = #{userId}), false) as collect
+        from midjourney_painting_plaza mpp
+        where mpp.status is true
+        and mpp.deleted is true
+        <if test="collect != null">
+            and EXISTS (select 1 from midjourney_painting_collect_record pr
+            where pr.plaza_id = mpp.id and user_id = #{userId} and pr.status is ${collect} limit 1)
+        </if>
+        order by mpp.update_time desc
+    </select>
+</mapper>

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

@@ -1,12 +1,9 @@
 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

+ 14 - 0
netflix-service/src/main/java/com/cyksj/service/midjourney/MidjourneyPaintingPlazaService.java

@@ -0,0 +1,14 @@
+package com.cyksj.service.midjourney;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.cyksj.model.entity.MidjourneyPaintingPlaza;
+
+/**
+ * 项目名: yhlxj
+ * 文件名: MidjourneyPaintingPlazaService
+ * 创建者: JavaZou
+ * 创建时间:2024/6/3 17:32
+ */
+public interface MidjourneyPaintingPlazaService extends IService<MidjourneyPaintingPlaza> {
+	void saveOrUpdatePainting(MidjourneyPaintingPlaza midjourneyPaintingPlaza);
+}

+ 8 - 2
netflix-service/src/main/java/com/cyksj/service/midjourney/impl/MidJourneyAccountServiceImpl.java

@@ -233,8 +233,14 @@ public class MidJourneyAccountServiceImpl extends ServiceImpl<MidjourneyAccountM
         midjourneyUser.setImg(getWxImg(user.getHeadimgurl(), user));
         midjourneyUser.setRelationId(groupsRelation.getId());
         midjourneyUser.setUserToken(UUID.randomUUID().toString());
-        midjourneyUser.setMjFastNum(goodsDonSku.getMjFastNum());
-        midjourneyUser.setMjRelaxNum((goodsDonSku.getMjRelaxNum() == null || goodsDonSku.getMjRelaxNum() == 0) ? null : goodsDonSku.getMjRelaxNum());
+        if (groupsRelation.getAqType() == 2) {
+            //fast模式 5次
+            midjourneyUser.setMjFastNum(5);
+            midjourneyUser.setMjRelaxNum(0);
+        } else {
+            midjourneyUser.setMjFastNum(goodsDonSku.getMjFastNum());
+            midjourneyUser.setMjRelaxNum((goodsDonSku.getMjRelaxNum() == null || goodsDonSku.getMjRelaxNum() == 0) ? null : goodsDonSku.getMjRelaxNum());
+        }
         midjourneyUserMapper.insert(midjourneyUser);
         redisService.set(RedisService.key.MIDJOURNEY_FAST_LIMIT.getName() + midjourneyUser.getId(), midjourneyUser.getMjFastNum(),RedisService.key.MIDJOURNEY_FAST_LIMIT.getTimeout());
         redisService.set(RedisService.key.MIDJOURNEY_USER.getName() + midjourneyUser.getUserToken(), midjourneyUser,RedisService.key.MIDJOURNEY_USER.getTimeout());

+ 33 - 0
netflix-service/src/main/java/com/cyksj/service/midjourney/impl/MidjourneyPaintingPlazaServiceImpl.java

@@ -0,0 +1,33 @@
+package com.cyksj.service.midjourney.impl;
+
+import cn.hutool.core.util.StrUtil;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.cyksj.common.exception.BusinessRuntimeException;
+import com.cyksj.mapper.MidjourneyPaintingPlazaMapper;
+import com.cyksj.model.entity.MidjourneyPaintingPlaza;
+import com.cyksj.service.midjourney.MidjourneyPaintingPlazaService;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+
+/**
+ * 项目名: yhlxj
+ * 文件名: MidjourneyPaintingPlazaServiceImpl
+ * 创建者: JavaZou
+ * 创建时间:2024/6/3 17:32
+ */
+@Service
+@RequiredArgsConstructor
+public class MidjourneyPaintingPlazaServiceImpl extends ServiceImpl<MidjourneyPaintingPlazaMapper, MidjourneyPaintingPlaza> implements MidjourneyPaintingPlazaService {
+	@Override
+	public void saveOrUpdatePainting(MidjourneyPaintingPlaza midjourneyPaintingPlaza) {
+		String tips = midjourneyPaintingPlaza.getTips();
+		if (StrUtil.isEmpty(tips)) {
+			throw BusinessRuntimeException.getInstance("请输入对应的关键词");
+		}
+		String img = midjourneyPaintingPlaza.getImg();
+		if (StrUtil.isEmpty(img)) {
+			throw BusinessRuntimeException.getInstance("图片不为空");
+		}
+		this.saveOrUpdate(midjourneyPaintingPlaza);
+	}
+}

+ 15 - 0
netflix-service/src/main/java/com/cyksj/service/order/impl/OrderDonServiceImpl.java

@@ -305,6 +305,8 @@ public class OrderDonServiceImpl extends ServiceImpl<OrderDonMapper, OrderDon> i
 
 	private final DistributeExtraRebateService distributeExtraRebateService;
 
+	private final UserTrialTicketJumpPayRecordMapper userTrialTicketJumpPayRecordMapper;
+
 	private final List<String> noChekGoodsTemp = List.of("Apple One", "Youtube", "Spotify");
 
 	@Transactional(rollbackFor = Throwable.class)
@@ -617,6 +619,8 @@ public class OrderDonServiceImpl extends ServiceImpl<OrderDonMapper, OrderDon> i
 		recordOrderDonLocationRelate(orderDon.getId(), payRequest.getIp());
 		//记录补贴订单关联
 		recordOrderDonSubsidyRelate(orderDon.getId(), subsidyId);
+		//试用车票跳转记录
+		recordOrderTrialTicketJumpPay(payRequest.getIsTrial(),orderDon.getId());
 		return orderDon;
 	}
 
@@ -3506,4 +3510,15 @@ public class OrderDonServiceImpl extends ServiceImpl<OrderDonMapper, OrderDon> i
 			}
         return beanSearcher.searchFirst(UpgradeOrderDetailView.class, builder.build());
 	}
+
+	/**
+	 * 试用车票跳转购买正式车票订单记录
+	 */
+	public void recordOrderTrialTicketJumpPay(Boolean isTrial, Long orderId) {
+		if (isTrial != null && isTrial) {
+			UserTrialTicketJumpPayRecord userTrialTicketJumpPayRecord = new UserTrialTicketJumpPayRecord();
+			userTrialTicketJumpPayRecord.setOrderId(orderId);
+			userTrialTicketJumpPayRecordMapper.insert(userTrialTicketJumpPayRecord);
+		}
+	}
 }

+ 13 - 0
netflix-service/src/main/java/com/cyksj/service/ticket/UserReceiveTrialTicketRecordService.java

@@ -0,0 +1,13 @@
+package com.cyksj.service.ticket;
+
+/**
+ * 项目名: yhlxj
+ * 文件名: UserReceiveTrialTicketRecordService
+ * 创建者: JavaZou
+ * 创建时间:2024/6/3 17:55
+ */
+public interface UserReceiveTrialTicketRecordService {
+	void sendTicketAndRecord(Long userId, Long trialSkuId);
+
+	Boolean isReceiveTrialTicket(long userId, Long trialSkuId);
+}

+ 139 - 0
netflix-service/src/main/java/com/cyksj/service/ticket/impl/UserReceiveTrialTicketRecordServiceImpl.java

@@ -0,0 +1,139 @@
+package com.cyksj.service.ticket.impl;
+
+import cn.hutool.core.date.DateTime;
+import cn.hutool.core.date.DateUtil;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.cyksj.common.exception.BusinessRuntimeException;
+import com.cyksj.common.util.StringUtil;
+import com.cyksj.mapper.GoodsDonSkuMapper;
+import com.cyksj.mapper.GroupsMapper;
+import com.cyksj.mapper.GroupsRelationMapper;
+import com.cyksj.mapper.UserReceiveTrialTicketRecordMapper;
+import com.cyksj.model.entity.GoodsDonSku;
+import com.cyksj.model.entity.GroupsRelation;
+import com.cyksj.model.entity.GroupsTrips;
+import com.cyksj.model.entity.UserReceiveTrialTicketRecord;
+import com.cyksj.service.groups.GroupsFuncService;
+import com.cyksj.service.ticket.UserReceiveTrialTicketRecordService;
+import com.cyksj.service.user.UserBindRelationService;
+import com.github.rholder.retry.*;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.dao.DuplicateKeyException;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * 项目名: yhlxj
+ * 文件名: UserReceiveTrialTicketRecordServiceImpl
+ * 创建者: JavaZou
+ * 创建时间:2024/6/3 17:55
+ */
+@Service
+@RequiredArgsConstructor
+@Slf4j
+public class UserReceiveTrialTicketRecordServiceImpl implements UserReceiveTrialTicketRecordService {
+	private final UserBindRelationService userBindRelationService;
+
+	private final UserReceiveTrialTicketRecordMapper userReceiveTrialTicketRecordMapper;
+
+	private final GroupsMapper groupsMapper;
+
+	private final GroupsRelationMapper groupsRelationMapper;
+
+	private final GoodsDonSkuMapper goodsDonSkuMapper;
+
+	private final GroupsFuncService groupsFuncService;
+
+	@Override
+	public void sendTicketAndRecord(Long userId, Long trialSkuId) {
+		List<Long> userIdList = userBindRelationService.getRelationUserIdList(userId, null);
+		GoodsDonSku sku = goodsDonSkuMapper.selectById(trialSkuId);
+		if (sku == null) {
+			throw BusinessRuntimeException.getInstance("系统异常,请联系客服..");
+		}
+		Long goodsId = sku.getGoodsId();
+
+		Integer selectCount = userReceiveTrialTicketRecordMapper.selectCount(Wrappers.lambdaQuery(UserReceiveTrialTicketRecord.class)
+				.in(UserReceiveTrialTicketRecord::getUserId, userIdList)
+				.eq(UserReceiveTrialTicketRecord::getSkuId, trialSkuId));
+		if (selectCount > 0) {
+			throw BusinessRuntimeException.getInstance("您已领取该试用车票");
+		}
+
+		try {
+			UserReceiveTrialTicketRecord userReceiveTrialTicketRecord = new UserReceiveTrialTicketRecord();
+			userReceiveTrialTicketRecord.setUserId(userId);
+			userReceiveTrialTicketRecord.setGoodsId(goodsId);
+			userReceiveTrialTicketRecord.setSkuId(trialSkuId);
+
+			userReceiveTrialTicketRecordMapper.insert(userReceiveTrialTicketRecord);
+
+			Long relationId = getTrialTicketByUserIdAndGoodsId(userId, trialSkuId);
+			userReceiveTrialTicketRecord.setRelationId(relationId);
+			userReceiveTrialTicketRecordMapper.updateById(userReceiveTrialTicketRecord);
+
+		} catch (DuplicateKeyException e) {
+			throw BusinessRuntimeException.getInstance("您已领取该试用车票");
+		}
+	}
+
+	@Override
+	public Boolean isReceiveTrialTicket(long userId, Long trialSkuId) {
+		List<Long> userIdList = userBindRelationService.getRelationUserIdList(userId, null);
+		Integer selectCount = userReceiveTrialTicketRecordMapper.selectCount(Wrappers.lambdaQuery(UserReceiveTrialTicketRecord.class)
+				.in(UserReceiveTrialTicketRecord::getUserId, userIdList)
+				.eq(UserReceiveTrialTicketRecord::getSkuId, trialSkuId));
+		return selectCount > 0 ? true : false;
+	}
+
+	public Long getTrialTicketByUserIdAndGoodsId(Long userId, Long trialSkuId) {
+		Retryer<Long> build = RetryerBuilder.<Long>newBuilder()
+				.retryIfException()
+				//运行时异常重试
+				.retryIfRuntimeException()
+				//false重试
+				.retryIfResult(res -> res == null)
+				//1s 间隔
+				.withWaitStrategy(WaitStrategies.fixedWait(1, TimeUnit.SECONDS))
+				//停止策略 : 尝试请求3次
+				.withStopStrategy(StopStrategies.stopAfterAttempt(3)).build();
+		try {
+			return build.call(() -> {
+				//体验规格
+				GroupsTrips groups = groupsMapper.selectCollegeStudentUserGptTicket(trialSkuId);
+				GroupsRelation relation = null;
+				if (groups != null) {
+					relation = groupsRelationMapper.selectRandomOneRelationByGroupsId(groups.getId());
+				}
+				if (relation == null) {
+					//生成空车队
+					GoodsDonSku sku = goodsDonSkuMapper.selectById(trialSkuId);
+					relation = groupsFuncService.createNewGroupsTrips(sku);
+				}
+				DateTime startTime = DateTime.now();
+				DateTime expiryTime = DateUtil.offsetDay(startTime, 1);
+				int update = groupsRelationMapper.update(null, Wrappers.lambdaUpdate(GroupsRelation.class)
+						.set(GroupsRelation::getUserId, userId)
+						.set(GroupsRelation::getStartTime, startTime)
+						.set(GroupsRelation::getExpiryTime, expiryTime)
+						.set(GroupsRelation::getStatus, GroupsRelation.Status.validity)
+						.set(GroupsRelation::getAqType, 2)
+						.eq(GroupsRelation::getId, relation.getId())
+						.eq(GroupsRelation::getUserId, 0));
+				if (update > 0) {
+					groupsMapper.decrAvailableNum(groups.getId());
+					return relation.getId();
+				}
+				log.error("发送用户:{} GPT镜像车票体验失败,进行重试", userId);
+				return null;
+			});
+		} catch (ExecutionException | RetryException e) {
+			log.error("发送用户GPT镜像体验失败:{}", StringUtil.getErrorText(e));
+			return null;
+		}
+	}
+}

+ 47 - 0
netflix-web/src/main/java/com/cyksj/web/controller/group/MidJourneyGuideController.java

@@ -0,0 +1,47 @@
+package com.cyksj.web.controller.group;
+
+import com.cyksj.common.constant.Constant;
+import com.cyksj.dto.Result;
+import com.cyksj.enums.GatewayResponse;
+import com.cyksj.service.ticket.UserReceiveTrialTicketRecordService;
+import com.cyksj.web.util.StpUserUtil;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * 项目名: yhlxj
+ * 文件名: MidJourneyGuideController
+ * 创建者: JavaZou
+ * 创建时间:2024/6/3 17:46
+ */
+@Slf4j
+@RequestMapping("/applets/mj")
+@RestController
+@RequiredArgsConstructor
+public class MidJourneyGuideController {
+	private final UserReceiveTrialTicketRecordService userReceiveTrialTicketRecordService;
+
+	/**
+	 * 领取mj试用车票
+	 */
+	@PostMapping("/receive/trial")
+	public Result<String> receiveTrialTicket() {
+		long userId = StpUserUtil.getLoginIdAsLong();
+		userReceiveTrialTicketRecordService.sendTicketAndRecord(userId, Constant.MIDJOURNEY_TRIAL_SKU_ID);
+		return GatewayResponse.SUCCESS.newBuilder().toResult();
+	}
+
+	/**
+	 * 是否已领取mj试用车票
+	 */
+	@GetMapping("/hasReceived")
+	public Result<Boolean> isReceiveTrialTicket() {
+		long userId = StpUserUtil.getLoginIdAsLong();
+		Boolean flag = userReceiveTrialTicketRecordService.isReceiveTrialTicket(userId, Constant.MIDJOURNEY_TRIAL_SKU_ID);
+		return GatewayResponse.SUCCESS.newBuilder().toResult(flag);
+	}
+}

+ 107 - 0
netflix-web/src/main/java/com/cyksj/web/controller/manage/mj/MidjourneyPaintingController.java

@@ -0,0 +1,107 @@
+package com.cyksj.web.controller.manage.mj;
+
+import cn.hutool.core.collection.CollUtil;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.cyksj.common.exception.BusinessRuntimeException;
+import com.cyksj.dto.Result;
+import com.cyksj.enums.GatewayResponse;
+import com.cyksj.model.entity.MidjourneyPaintingPlaza;
+import com.cyksj.service.midjourney.MidjourneyPaintingPlazaService;
+import com.ejlchina.searcher.BeanSearcher;
+import com.ejlchina.searcher.SearchResult;
+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.List;
+
+/**
+ * 项目名: yhlxj
+ * 文件名: MidjourneyPaintingController
+ * 创建者: JavaZou
+ * 创建时间:2024/6/3 17:24
+ */
+@Slf4j
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/manage/mj/painting")
+public class MidjourneyPaintingController {
+	private final MidjourneyPaintingPlazaService midjourneyPaintingPlazaService;
+
+	private final BeanSearcher beanSearcher;
+
+	private final HttpServletRequest request;
+
+	/**
+	 * 新增记录
+	 */
+	@PostMapping("/post")
+	public Result<String> savePainting(@RequestBody MidjourneyPaintingPlaza midjourneyPaintingPlaza) {
+		midjourneyPaintingPlazaService.saveOrUpdatePainting(midjourneyPaintingPlaza);
+		return GatewayResponse.SUCCESS.newBuilder().toResult();
+	}
+
+	/**
+	 * 删除记录
+	 */
+	@DeleteMapping("/delete/{id}")
+	public Result<String> deleteById(@PathVariable Long id) {
+		MidjourneyPaintingPlaza byId = midjourneyPaintingPlazaService.getById(id);
+		if (byId != null && byId.getDeleted()) {
+			byId.setDeleted(false);
+			midjourneyPaintingPlazaService.updateById(byId);
+		}
+		return GatewayResponse.SUCCESS.newBuilder().toResult();
+	}
+
+
+	/**
+	 * 修改记录
+	 */
+	@PutMapping("/update")
+	public Result<String> updatePainting(@RequestBody MidjourneyPaintingPlaza midjourneyPaintingPlaza) {
+		midjourneyPaintingPlazaService.saveOrUpdatePainting(midjourneyPaintingPlaza);
+		return GatewayResponse.SUCCESS.newBuilder().toResult();
+	}
+
+	/**
+	 * 列表
+	 */
+	@GetMapping("/get")
+	public Result<SearchResult<MidjourneyPaintingPlaza>> saveOrUpdatePainting() {
+		SearchResult<MidjourneyPaintingPlaza> search = beanSearcher.search(MidjourneyPaintingPlaza.class, MapUtils.flatBuilder(request.getParameterMap())
+				.field(MidjourneyPaintingPlaza::getDeleted, 1)
+				.build());
+		return GatewayResponse.SUCCESS.newBuilder().toResult(search);
+	}
+
+	/**
+	 * 上下架
+	 */
+	@PutMapping("/update/status/{id}")
+	public Result<String> updateStatus(@PathVariable Long id) {
+		MidjourneyPaintingPlaza byId = midjourneyPaintingPlazaService.getById(id);
+		if (byId != null) {
+			byId.setStatus(!byId.getStatus());
+			midjourneyPaintingPlazaService.updateById(byId);
+		}
+		return GatewayResponse.SUCCESS.newBuilder().toResult();
+	}
+
+	/**
+	 * 批量上下架
+	 */
+	@PutMapping("/update/status")
+	public Result<String> updateStatus(@RequestParam(value = "ids") List<Long> ids, Boolean status) {
+		if (CollUtil.isEmpty(ids) || status == null) {
+			throw BusinessRuntimeException.getInstance("参数错误");
+		}
+		midjourneyPaintingPlazaService.update(null, Wrappers.lambdaUpdate(MidjourneyPaintingPlaza.class)
+				.set(MidjourneyPaintingPlaza::getStatus, status)
+				.in(MidjourneyPaintingPlaza::getId, ids)
+				.ne(MidjourneyPaintingPlaza::getStatus, status));
+		return GatewayResponse.SUCCESS.newBuilder().toResult();
+	}
+}

+ 105 - 2
netflix-web/src/main/java/com/cyksj/web/controller/mirror/MidjourneyController.java

@@ -1,29 +1,42 @@
 package com.cyksj.web.controller.mirror;
 
+import cn.hutool.core.util.StrUtil;
 import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.cyksj.common.exception.BusinessRuntimeException;
 import com.cyksj.dto.Result;
-import com.cyksj.model.dto.*;
 import com.cyksj.enums.GatewayResponse;
+import com.cyksj.mapper.GroupsRelationMapper;
+import com.cyksj.mapper.MidjourneyPaintingCollectRecordMapper;
+import com.cyksj.mapper.MidjourneyPaintingPlazaMapper;
 import com.cyksj.mapper.MidjourneyUserMapper;
+import com.cyksj.model.dto.*;
+import com.cyksj.model.entity.MidjourneyPaintingCollectRecord;
+import com.cyksj.model.entity.MidjourneyPaintingPlaza;
 import com.cyksj.model.entity.MidjourneyUser;
 import com.cyksj.model.entity.MidjourneyUserConversation;
+import com.cyksj.model.views.MidjourneyPaintingUserView;
+import com.cyksj.model.views.MidjourneyUserPaintingDayRecordView;
+import com.cyksj.model.views.MidjourneyUserPaintingRecordView;
 import com.cyksj.redis.RedisService;
 import com.cyksj.service.midjourney.MidjourneyService;
+import com.cyksj.service.user.UserBindRelationService;
 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.dao.DuplicateKeyException;
 import org.springframework.web.bind.annotation.*;
 
 import javax.servlet.http.HttpServletRequest;
 import java.util.Date;
 import java.util.List;
+import java.util.Optional;
 
-/**
+/** server/镜像服务/mj绘画
  * @author zwhui
  * @date 2024/4/23 10:31
  */
@@ -43,6 +56,14 @@ public class MidjourneyController {
     
     private final RedisService redisService;
 
+    private final GroupsRelationMapper groupsRelationMapper;
+
+    private final UserBindRelationService userBindRelationService;
+
+    private final MidjourneyPaintingPlazaMapper midjourneyPaintingPlazaMapper;
+
+    private final MidjourneyPaintingCollectRecordMapper midjourneyPaintingCollectRecordMapper;
+
     public MidjourneyUser getUser(){
         String userToken = request.getHeader("user-token");
         MidjourneyUser midjourneyUser = (MidjourneyUser) redisService.get(RedisService.key.MIDJOURNEY_USER.getName() + userToken);
@@ -338,4 +359,86 @@ public class MidjourneyController {
         redisService.del(RedisService.key.MIDJOURNEY_USER.getName() + midjourneyUser.getUserToken());
         return GatewayResponse.SUCCESS.newBuilder().toResult();
     }
+
+
+    /**
+     * mj绘画广场 我的收藏
+     */
+    @GetMapping("/get/painting")
+    public Result<Page<MidjourneyPaintingUserView>> getPaintingCollect(@RequestParam(defaultValue = "1") Integer start, @RequestParam(defaultValue = "10") Integer limit, Boolean collect) {
+        if (limit > 20) {
+            limit = 20;
+        }
+        MidjourneyUser user = getUser();
+        Page<MidjourneyPaintingUserView> page = midjourneyPaintingPlazaMapper.getPaintingList(new Page<>(start, limit), collect, user.getId());
+        return GatewayResponse.SUCCESS.newBuilder().toResult(page);
+    }
+
+    /**
+     * 修改 mj绘画广场 收藏状态
+     */
+    @PutMapping("/collect/painting/{id}")
+    public Result<SearchResult<MidjourneyPaintingUserView>> collectPainting(@PathVariable Long id) {
+        MidjourneyUser user = getUser();
+        MidjourneyPaintingPlaza midjourneyPaintingPlaza = midjourneyPaintingPlazaMapper.selectById(id);
+        if (midjourneyPaintingPlaza == null || !midjourneyPaintingPlaza.getDeleted()) {
+         return GatewayResponse.SUCCESS.newBuilder().toResult();
+        }
+        MidjourneyPaintingCollectRecord record = Optional.ofNullable(midjourneyPaintingCollectRecordMapper.selectOne(Wrappers.lambdaQuery(MidjourneyPaintingCollectRecord.class)
+                .eq(MidjourneyPaintingCollectRecord::getPlazaId, id)
+                .eq(MidjourneyPaintingCollectRecord::getUserId, user.getId()).last("limit 1"))).orElse(new MidjourneyPaintingCollectRecord());
+        if (record.getId() == null) {
+            try {
+                record.setStatus(true);
+                record.setUserId(user.getId());
+                record.setPlazaId(id);
+                midjourneyPaintingCollectRecordMapper.insert(record);
+            } catch (DuplicateKeyException e) {
+            }
+        } else {
+            record.setStatus(!record.getStatus());
+            midjourneyPaintingCollectRecordMapper.updateById(record);
+        }
+        return GatewayResponse.SUCCESS.newBuilder().toResult();
+    }
+
+    /**
+     * 复制mj绘画广场 提示词
+     */
+    @PostMapping("/painting/copy/{id}")
+    public Result<String> resetPaintingCopyNum(@PathVariable Long id) {
+        MidjourneyPaintingPlaza midjourneyPaintingPlaza = midjourneyPaintingPlazaMapper.selectById(id);
+        if (midjourneyPaintingPlaza != null) {
+            midjourneyPaintingPlazaMapper.updatePaintingCopyNum(id);
+        }
+        return GatewayResponse.SUCCESS.newBuilder().toResult();
+    }
+
+    /**
+     * 用户绘画记录
+     */
+    @GetMapping("/get/painting/record")
+    public Result<SearchResult<MidjourneyUserPaintingDayRecordView>> getPaintingRecord(String prompt) {
+        MidjourneyUser user = getUser();
+        String condition = String.format(" and mc.user_id = %s", user.getId());
+        if (StrUtil.isNotBlank(prompt)) {
+            condition += String.format(" and mc.prompt = '%s'", prompt);
+        }
+        SearchResult<MidjourneyUserPaintingDayRecordView> search = beanSearcher.search(MidjourneyUserPaintingDayRecordView.class, MapUtils.flatBuilder(request.getParameterMap())
+                .put("condition", condition)
+                .orderBy(MidjourneyUserPaintingRecordView::getCreatedTime).desc()
+                .build());
+        String dateSql;
+        for (MidjourneyUserPaintingDayRecordView e : search.getDataList()) {
+            String date = e.getDate();
+            dateSql = String.format(" and DATE_FORMAT(mc.created_time,'%%Y-%%m-%%d') = '%s'", date);
+            List<MidjourneyUserPaintingRecordView> list = beanSearcher.searchAll(MidjourneyUserPaintingRecordView.class, MapUtils.builder()
+                    .put("condition", condition)
+                    .put("date", dateSql)
+                    .orderBy(MidjourneyUserPaintingRecordView::getCreatedTime).desc()
+                    .build());
+            e.setList(list);
+        }
+        return GatewayResponse.SUCCESS.newBuilder().toResult(search);
+    }
 }