Просмотр исходного кода

加粉延后回传,主动回传;用户意愿

chenbiao 2 лет назад
Родитель
Сommit
3ac17afea1

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

@@ -0,0 +1,11 @@
+package com.cyksj.mapper.corp;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.cyksj.model.entity.CorpCustomerAcquistionCallback;
+
+/**
+ * @author chan
+ * @date 2024/3/13 16:05
+ */
+public interface CorpCustomerAcquistionCallbackMapper extends BaseMapper<CorpCustomerAcquistionCallback> {
+}

+ 8 - 2
netflix-dao/src/main/java/com/cyksj/mapper/corp/CorpUserTagMapper.java

@@ -4,7 +4,9 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.cyksj.model.entity.CorpUserTag;
 import com.cyksj.model.excel.CorpUserTagExcelData;
+import com.cyksj.model.views.CorpUserIntentionView;
 import com.cyksj.model.views.CorpUserView;
+import com.cyksj.model.views.UserIntentionPieView;
 import com.cyksj.model.views.UserOrderDetailView;
 import org.apache.ibatis.annotations.Param;
 
@@ -20,7 +22,11 @@ public interface CorpUserTagMapper extends BaseMapper<CorpUserTag> {
 
 	List<CorpUserTagExcelData> exportUserTagDetail(@Param("tagIds") String[] tagIds, @Param("groupIds") String[] groupIds, @Param("wxCorpId") Long wxCorpId);
 
-	UserOrderDetailView countTagUser(@Param("tagIdStr") String tagIdStr, @Param("startTime") String startTime, @Param("endTime") String endTime);
+	UserOrderDetailView countTagUser(@Param("tagIdStr") String tagIdStr, @Param("startTime") String startTime, @Param("endTime") String endTime, @Param("thisDate") String thisDate);
 
 	List<Long> getTagIdByCorpUserId(Long corpUserId);
-}
+
+	List<UserIntentionPieView> getUserIntentionPie(@Param("tagIdStr") String tagId, @Param("thisDate") String date);
+
+	Page<CorpUserIntentionView> getCorpUserIntentionView(@Param("page") Page<CorpUserIntentionView> page, @Param("userId") Long userId, @Param("nickname") String nickname, @Param("tagIdStr") String tagId, @Param("thisDate") String date, @Param("intention") Integer intention);
+}

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

@@ -35,6 +35,11 @@ public class CorpCustomerAcquisitionLinkPopularize extends BaseEntity {
      */
     private Long time;
 
+    /**
+     * 是否记录回传
+     */
+    private Boolean delayedPost;
+
     @TableField(exist = false)
     @DbIgnore
     private String url;

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

@@ -0,0 +1,39 @@
+package com.cyksj.model.entity;
+
+import com.ejlchina.searcher.bean.SearchBean;
+import lombok.Data;
+
+/**
+ * 获客链接加粉 主动回传记录
+ * @author chan
+ * @date 2024/3/13 16:00
+ */
+@SearchBean(tables = "corp_customer_acquistion_callback")
+@Data
+public class CorpCustomerAcquistionCallback extends BaseEntity {
+
+    /**
+     * 回传标识
+     */
+    private String callback;
+
+    /**
+     * 事件
+     */
+    private String event;
+
+    /**
+     * 企业微信用户unionId
+     */
+    private String unionId;
+
+    /**
+     * 回传状态
+     */
+    private Boolean status;
+
+    /**
+     * 意向 0无回复、1无意向、2问相关问题、3有意向、4很有意向
+     */
+    private Integer intention;
+}

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

@@ -0,0 +1,33 @@
+package com.cyksj.model.views;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * 项目名: yhlxj
+ * 文件名: CorpUserIntentionView
+ * 创建者: JavaZou
+ * 创建时间:2024/4/3 12:09
+ */
+@Getter
+@Setter
+public class CorpUserIntentionView {
+	/**
+	 * 回传意愿id
+	 */
+	private Long intentionId;
+
+	private Long userId;
+
+	private String nickname;
+
+	/**
+	 * 意向 0无意向 1有意向 2很有意向
+	 */
+	private Integer intention;
+
+	/**
+	 * 创建时间
+	 */
+	private String createdTime;
+}

+ 22 - 0
netflix-dao/src/main/java/com/cyksj/model/views/UserIntentionPieView.java

@@ -0,0 +1,22 @@
+package com.cyksj.model.views;
+
+import com.cyksj.model.entity.BaseEntity;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * 项目名: yhlxj
+ * 文件名: UserIntentionPieView
+ * 创建者: JavaZou
+ * 创建时间:2024/4/3 11:53
+ */
+@Getter
+@Setter
+public class UserIntentionPieView extends BaseEntity {
+	/**
+	 * 意向 0无意向 1有意向 2很有意向
+	 */
+	private Integer intention;
+
+	private Integer count;
+}

+ 44 - 0
netflix-dao/src/main/resources/mapper/CorpUserTagMapper.xml

@@ -72,6 +72,9 @@
         </if>
         <if test="endTime != null">
             and ct.created_time &lt; #{endTime}
+        </if>
+        <if test="thisDate != null">
+            and date_format(ct.created_time,'%Y-%m-%d') = #{thisDate}
         </if>) s
         left join corp_user_follow_relation cufr on cufr.id = s.relation_id
         left join corp_user_auth ca on ca.external_userid = cufr.corp_user_id
@@ -84,4 +87,45 @@
                  inner join corp_user_tag cut on cut.relation_id = cufr.id
                  inner join corp_tag ct on ct.tag_id = cut.tag_id
     </select>
+
+    <select id="getUserIntentionPie" resultType="com.cyksj.model.views.UserIntentionPieView">
+        select count(distinct ca.corp_user_id) as `count`, ccc.intention
+        as intention
+        from (select relation_id
+        from `corp_user_tag` ct
+        where tag_id = #{tagIdStr}
+        <if test="thisDate != null">
+            and date_format(ct.created_time,'%Y-%m-%d') = #{thisDate}
+        </if>) s
+        left join corp_user_follow_relation cufr on cufr.id = s.relation_id
+        left join corp_user_auth ca on ca.external_userid = cufr.corp_user_id
+        left join corp_user cu on cu.id = ca.corp_user_id
+        inner join corp_customer_acquistion_callback ccc on ccc.union_id = cu.unionid
+        group by ccc.intention
+    </select>
+
+    <select id="getCorpUserIntentionView" resultType="com.cyksj.model.views.CorpUserIntentionView">
+        select cu.user_id,cu.name,cu.created_time,ccc.id as intentionId,ccc.intention
+        from (select relation_id
+        from `corp_user_tag` ct
+        where tag_id = #{tagIdStr}
+        <if test="thisDate != null">
+            and date_format(ct.created_time,'%Y-%m-%d') = #{thisDate}
+        </if>) s
+        left join corp_user_follow_relation cufr on cufr.id = s.relation_id
+        left join corp_user_auth ca on ca.external_userid = cufr.corp_user_id
+        left join corp_user cu on cu.id = ca.corp_user_id
+        left join corp_customer_acquistion_callback ccc on ccc.union_id = cu.unionid
+        <where>
+            <if test="userId != null">
+                cu.user_id = #{userId}
+            </if>
+            <if test="userId != null">
+                and cu.name like concat('%',#{userName},'%')
+            </if>
+            <if test="intention != null">
+                and ccc.intention = #{intention}
+            </if>
+        </where>
+    </select>
 </mapper>

+ 14 - 0
netflix-service/src/main/java/com/cyksj/service/corp/CorpService.java

@@ -1,6 +1,7 @@
 package com.cyksj.service.corp;
 
 import com.cyksj.dto.CorpOauth2UserInfo;
+import com.cyksj.model.entity.CorpCustomerAcquistionCallback;
 import com.cyksj.model.entity.CorpFollow;
 import com.cyksj.model.request.corp.Attachments;
 
@@ -36,4 +37,17 @@ public interface CorpService {
 	 * @return
 	 */
 	Attachments updateMaterial(Attachments attachments, String corpId,Integer type);
+
+	/**
+	 * 回传加粉延后回传记录
+	 * @param id 记录id
+	 */
+	void postAcquistionLinkCallback(Long id);
+
+	/**
+	 * 更新加粉回传 意向
+	 * @param corpCustomerAcquistionCallback
+	 */
+	void upCallbackIntention(CorpCustomerAcquistionCallback corpCustomerAcquistionCallback);
+
 }

+ 22 - 1
netflix-service/src/main/java/com/cyksj/service/corp/impl/CorpEventActionServiceImpl.java

@@ -135,6 +135,8 @@ public class CorpEventActionServiceImpl implements CorpEventActionService {
 
 	private final CorpWelcomeTemplateMapper corpWelcomeTemplateMapper;
 
+	private final CorpCustomerAcquistionCallbackMapper corpCustomerAcquistionCallbackMapper;
+
 	private static final String DEFAULT_MSG = "您好,欢迎加入银河录像局";
 
 	/**
@@ -1097,7 +1099,10 @@ public class CorpEventActionServiceImpl implements CorpEventActionService {
 				if (corpCustomerAcquisitionLinkPopularize != null) {
 					//如果为加粉则直接回传
 					if (corpCustomerAcquisitionLinkPopularize.getType() == 1) {
-						postData(callback, corpCustomerAcquisitionLinkPopularize.getEvent());
+						//如果需要延后主动回传的做持久化.
+						if(!corpCustomerAcquisitionLinkPopularize.getDelayedPost()){
+							postData(callback, corpCustomerAcquisitionLinkPopularize.getEvent());
+						}
 					}else {
 						//深度转化 前置加粉事件回传.
 						if(StringUtils.isNotBlank(corpCustomerAcquisitionLinkPopularize.getAddEvent())){
@@ -1107,6 +1112,22 @@ public class CorpEventActionServiceImpl implements CorpEventActionService {
 						//深度回传.
 						redisService.set(String.format(RedisService.key.CORP_CUSTOMER_ACQUISTION_UNIONID_CLICKID.getName(),unionId), json, corpCustomerAcquisitionLinkPopularize.getTime() * 60 * 60);
 					}
+
+					if(corpCustomerAcquisitionLinkPopularize.getDelayedPost()){
+						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(corpCustomerAcquistionCallback.getEvent());
+						corpCustomerAcquistionCallback.setUnionId(unionId);
+						if(corpCustomerAcquistionCallback.getId() != null){
+							corpCustomerAcquistionCallbackMapper.updateById(corpCustomerAcquistionCallback);
+						}else {
+							corpCustomerAcquistionCallbackMapper.insert(corpCustomerAcquistionCallback);
+						}
+					}
 				}
 			}
 		}

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

@@ -13,9 +13,12 @@ import com.cyksj.common.util.corp.WxCryptUtil;
 import com.cyksj.config.corp.WeChatCorpFactory;
 import com.cyksj.config.corp.YHLXWxCorpConfig;
 import com.cyksj.dto.CorpOauth2UserInfo;
+import com.cyksj.mapper.corp.CorpCustomerAcquistionCallbackMapper;
 import com.cyksj.mapper.corp.CorpFollowMapper;
 import com.cyksj.model.dto.WxCorpEncryptDto;
+import com.cyksj.model.entity.CorpCustomerAcquistionCallback;
 import com.cyksj.model.entity.CorpFollow;
+import com.cyksj.model.entity.OrderDonPost;
 import com.cyksj.model.entity.WxCorpApp;
 import com.cyksj.model.request.corp.Attachments;
 import com.cyksj.model.request.corp.CorpXmlMessage;
@@ -28,6 +31,7 @@ import com.cyksj.service.corp.WxCorpOps;
 import com.cyksj.service.corp.msg.CorpEventActionService;
 import com.cyksj.service.corp.msg.CorpMessageHandler;
 import com.cyksj.service.corp.msg.CorpMessageRouter;
+import com.cyksj.service.order.OrderDonPostService;
 import com.cyksj.util.WxCorpUtil;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang3.StringUtils;
@@ -70,6 +74,12 @@ public class CorpServiceImpl implements CorpService {
 	@Autowired
 	private RedisService redisService;
 
+	@Autowired
+	private OrderDonPostService orderDonPostService;
+
+	@Autowired
+	private CorpCustomerAcquistionCallbackMapper corpCustomerAcquistionCallbackMapper;
+
 	@PostConstruct
 	private void init() {
 		corpMessageRouter = new CorpMessageRouter(this)
@@ -327,4 +337,30 @@ public class CorpServiceImpl implements CorpService {
 
 		return mediaId;
 	}
+
+	/**
+	 *  加粉回传 目前 OE
+	 */
+	@Override
+	public void postAcquistionLinkCallback(Long id) {
+		try {
+			CorpCustomerAcquistionCallback corpCustomerAcquistionCallback = corpCustomerAcquistionCallbackMapper.selectById(id);
+			if(corpCustomerAcquistionCallback == null){
+				throw BusinessRuntimeException.getInstance("回传记录不存在");
+			}
+			if (corpCustomerAcquistionCallback.getStatus()) {
+				throw BusinessRuntimeException.getInstance("该记录已回传");
+			}
+			orderDonPostService.post(OrderDonPost.Type.OE.getType(), corpCustomerAcquistionCallback.getCallback(), corpCustomerAcquistionCallback.getEvent());
+			corpCustomerAcquistionCallback.setStatus(true);
+			corpCustomerAcquistionCallbackMapper.updateById(corpCustomerAcquistionCallback);
+		} catch (Exception e) {
+			throw BusinessRuntimeException.getInstance("加粉回传出错. error:" + StringUtil.getErrorText(e));
+		}
+	}
+
+	@Override
+	public void upCallbackIntention(CorpCustomerAcquistionCallback corpCustomerAcquistionCallback) {
+		corpCustomerAcquistionCallbackMapper.update(null, Wrappers.lambdaUpdate(CorpCustomerAcquistionCallback.class).eq(CorpCustomerAcquistionCallback::getId, corpCustomerAcquistionCallback.getId()).set(CorpCustomerAcquistionCallback::getIntention, corpCustomerAcquistionCallback.getIntention()));
+	}
 }

+ 6 - 1
netflix-service/src/main/java/com/cyksj/service/corp/impl/CorpTagServiceImpl.java

@@ -424,12 +424,17 @@ public class CorpTagServiceImpl implements CorpTagService {
 	public UserOrderDetailView getTagUserData(Integer start, Integer limit, String tagIdStr, String startTime, String endTime) {
 		UserOrderDetailView u = orderDonMapper.getTagUserData(tagIdStr, startTime, endTime);
 
-		UserOrderDetailView u2 = corpUserTagMapper.countTagUser(tagIdStr, startTime, endTime);
+		UserOrderDetailView u2 = corpUserTagMapper.countTagUser(tagIdStr, startTime, endTime,null);
 
 		u.setNumOfUser(u2.getNumOfUser());
 		u.setDelNumOfUser(u2.getDelNumOfUser());
 		u.setOrderRate(u.getNumOfUser() == 0 ? BigDecimal.ZERO : BigDecimal.valueOf(u.getNumOfEpOrder()).divide(BigDecimal.valueOf(u.getNumOfUser()), 2, RoundingMode.HALF_DOWN));
 		Page<UserOrderDetailView> records = orderDonMapper.getTagUserDataPage(new Page<>(start, limit), tagIdStr, startTime, endTime);
+		records.getRecords().forEach(e->{
+			String date = e.getDate();
+			UserOrderDetailView userOrderDetailView = corpUserTagMapper.countTagUser(tagIdStr, null, null, date);
+			e.setNumOfUser(userOrderDetailView.getNumOfUser());
+		});
 
 		u.setRecords(records);
 		return u;

+ 74 - 8
netflix-web/src/main/java/com/cyksj/web/controller/manage/corp/WxCorpController.java

@@ -4,6 +4,7 @@ import cn.hutool.core.date.DateTime;
 import cn.hutool.core.date.DateUtil;
 import cn.hutool.core.util.StrUtil;
 import cn.hutool.http.HttpUtil;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.cyksj.common.exception.BusinessRuntimeException;
 import com.cyksj.common.snowflake.Sequence;
 import com.cyksj.common.util.Codec;
@@ -15,14 +16,15 @@ import com.cyksj.dto.CorpJsSdkTicket;
 import com.cyksj.dto.CorpOauth2UserInfo;
 import com.cyksj.dto.Result;
 import com.cyksj.enums.GatewayResponse;
-import com.cyksj.mapper.GroupsRelationCustomerServiceFollowRecordMapper;
 import com.cyksj.mapper.GroupsRelationExpiryRecordMapper;
+import com.cyksj.mapper.UserMapper;
+import com.cyksj.mapper.corp.CorpUserTagMapper;
 import com.cyksj.model.dto.AuthRedirect;
-import com.cyksj.model.entity.CorpFollow;
-import com.cyksj.model.entity.CorpMsgFollowAssociation;
-import com.cyksj.model.entity.QyMsgContent;
+import com.cyksj.model.entity.*;
 import com.cyksj.model.manage.views.CorpQyMsgAuditChatView;
 import com.cyksj.model.request.corp.CorpCommonReq;
+import com.cyksj.model.views.CorpUserIntentionView;
+import com.cyksj.model.views.UserIntentionPieView;
 import com.cyksj.model.views.YHLXUserDetailView;
 import com.cyksj.redis.RedisService;
 import com.cyksj.service.corp.CorpService;
@@ -30,6 +32,7 @@ import com.cyksj.service.corp.CorpUserService;
 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;
@@ -72,7 +75,9 @@ public class WxCorpController {
 
 	private final GroupsRelationExpiryRecordMapper groupsRelationExpiryRecordMapper;
 
-	private final GroupsRelationCustomerServiceFollowRecordMapper relationCustomerServiceFollowRecordMapper;
+	private final CorpUserTagMapper corpUserTagMapper;
+
+	private final UserMapper userMapper;
 
 	private final static String CORP_UUID = "corp-uuid";
 
@@ -80,7 +85,7 @@ public class WxCorpController {
 	 * 企业微信 消息推送url
 	 */
 	@RequestMapping(value = "/msg/notify", method = {RequestMethod.GET, RequestMethod.POST})
-	public String msgNotify(@RequestParam(value = "msg_signature") String msgSignature, String timestamp, String nonce, @RequestParam(value = "echostr",required = false) String echoStr) throws Exception {
+	public String msgNotify(@RequestParam(value = "msg_signature") String msgSignature, String timestamp, String nonce, @RequestParam(value = "echostr", required = false) String echoStr) throws Exception {
 		if (StrUtil.hasEmpty(msgSignature, timestamp, nonce)) {
 			return StringUtil.EMPTY;
 		}
@@ -216,7 +221,7 @@ public class WxCorpController {
 		return GatewayResponse.SUCCESS.newBuilder().toResult(jsSdkTicket);
 	}
 
-	public String getCorpUuid(){
+	public String getCorpUuid() {
 		return Optional.ofNullable(request.getHeader(CORP_UUID)).orElse(StringUtil.EMPTY);
 	}
 
@@ -276,6 +281,7 @@ public class WxCorpController {
 
 	/**
 	 * 企微会话列表
+	 *
 	 * @param externalUserid 用户 externalUserid
 	 */
 	@GetMapping("/getMsgAuditChat")
@@ -300,8 +306,68 @@ public class WxCorpController {
 	 * 获取聊天记录
 	 */
 	@GetMapping("/getMsgByFollowIdAndUserId")
-	public Result<SearchResult<QyMsgContent>> getMsgByFollowIdAndUserId(){
+	public Result<SearchResult<QyMsgContent>> getMsgByFollowIdAndUserId() {
 		SearchResult<QyMsgContent> search = beanSearcher.search(QyMsgContent.class, MapUtils.flatBuilder(request.getParameterMap()).build());
 		return GatewayResponse.SUCCESS.newBuilder().toResult(search);
 	}
+
+	/**
+	 * 获取主动回传 回传数据
+	 *
+	 * @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);
+	}
+
+	/**
+	 * 主动回传
+	 *
+	 * @param id 记录id
+	 */
+	@GetMapping("/acquistionLinkCallback/{id}")
+	public Result<String> postAcquistionLinkCallback(@PathVariable Long id) {
+		corpService.postAcquistionLinkCallback(id);
+		return GatewayResponse.SUCCESS.newBuilder().toResult();
+	}
+
+	/**
+	 * 修改 意向
+	 */
+	@PutMapping("/upCallbackIntention")
+	public Result<String> upCallbackIntention(@RequestBody CorpCustomerAcquistionCallback corpCustomerAcquistionCallback) {
+		log.info("修改意向:{}", corpCustomerAcquistionCallback);
+		if (corpCustomerAcquistionCallback.getId() == null || corpCustomerAcquistionCallback.getId() == 0 || corpCustomerAcquistionCallback.getIntention() == null) {
+			throw BusinessRuntimeException.getInstance("缺少必填参数.");
+		}
+		corpService.upCallbackIntention(corpCustomerAcquistionCallback);
+		return GatewayResponse.SUCCESS.newBuilder().toResult();
+	}
+
+	/**
+	 * 用户意愿饼图
+	 */
+	@GetMapping("/get/user/intention/pie")
+	public Result<List<UserIntentionPieView>> getUserIntentionPie(String tagId, String date) {
+		List<UserIntentionPieView> userIntentionPieViews = corpUserTagMapper.getUserIntentionPie(tagId, date);
+		return GatewayResponse.SUCCESS.newBuilder().toResult(userIntentionPieViews);
+	}
+
+	/**
+	 * 标签用户列表
+	 */
+	@GetMapping("/get/tag/user/list")
+	public Result<Page<CorpUserIntentionView>> getCorpUserIntentionView(Long userId, String nickname, String tagId, String date, Integer intention, @RequestParam(defaultValue = "1") Integer start, @RequestParam(defaultValue = "10") Integer limit) {
+		Page<CorpUserIntentionView> page = corpUserTagMapper.getCorpUserIntentionView(new Page<>(start, limit), userId, nickname, tagId, date, intention);
+		return GatewayResponse.SUCCESS.newBuilder().toResult(page);
+	}
 }