实现“用户转化漏斗统计”

This commit is contained in:
longbinbin 2024-12-12 18:26:11 +08:00
parent 9d22f9d8cf
commit 715c351f5f
6 changed files with 426 additions and 86 deletions

View File

@ -1,9 +1,7 @@
package com.ycwl.basic.controller.mobile;
import com.ycwl.basic.model.mobile.statistic.AppSta1VO;
import com.ycwl.basic.model.mobile.statistic.AppSta2VO;
import com.ycwl.basic.model.mobile.statistic.AppSta3VO;
import com.ycwl.basic.model.mobile.statistic.CommonQueryReq;
import com.ycwl.basic.annotation.IgnoreToken;
import com.ycwl.basic.model.mobile.statistic.*;
import com.ycwl.basic.service.mobile.AppStatisticsService;
import com.ycwl.basic.utils.ApiResponse;
import io.swagger.annotations.Api;
@ -26,6 +24,7 @@ public class AppStatisticsController {
@ApiOperation("支付订单金额、预览_支付转化率、扫码_付费用户转化率")
@PostMapping("/one")
@IgnoreToken
public ApiResponse<AppSta1VO> oneStatistics(@RequestBody CommonQueryReq query) {
return statisticsService.oneStatistics(query);
@ -33,6 +32,7 @@ public class AppStatisticsController {
@ApiOperation("支付订单数、现场订单数、推送订单数统计")
@PostMapping("/two")
@IgnoreToken
public ApiResponse<AppSta2VO> twoStatistics(@RequestBody CommonQueryReq query) {
return statisticsService.twoStatistics(query);
@ -40,9 +40,24 @@ public class AppStatisticsController {
@ApiOperation("扫码访问人数、推送订阅人数、预览视频人数统计")
@PostMapping("/free")
@IgnoreToken
public ApiResponse<AppSta3VO> freeStatistics(@RequestBody CommonQueryReq query) {
return statisticsService.freeStatistics(query);
}
@ApiOperation("用户转化漏斗")
@PostMapping("/userConversionFunnel")
@IgnoreToken
public ApiResponse<AppStatisticsFunnelVO> userConversionFunnel(@RequestBody CommonQueryReq query) {
return statisticsService.userConversionFunnel(query);
}
@ApiOperation("统计数据记录")
@PostMapping("/statistics")
public ApiResponse statistics() {
return null;
}
}

View File

@ -23,47 +23,65 @@ public interface StatisticsMapper {
* @param query
* @return
*/
int countPreviewOfMember(CommonQueryReq query);
Integer countPreviewVideoOfMember(CommonQueryReq query);
/**
* 统计扫码访问人数
* @param query
* @return
*/
int countScanCodeOfMember(CommonQueryReq query);
Integer countScanCodeOfMember(CommonQueryReq query);
/**
* 统计点击购买人数
* @param query
* @return
*/
int countClickPayOfMember(CommonQueryReq query);
Integer countClickPayOfMember(CommonQueryReq query);
/**
* 统计付费人数
* @param query
* @return
*/
int countPayOfMember(CommonQueryReq query);
Integer countPayOfMember(CommonQueryReq query);
/**
* 统计现场支付订单数
* @param query
* @return
*/
int countSceneOrderNum(CommonQueryReq query);
Integer countSceneOrderNum(CommonQueryReq query);
/**
* 统计推送支付订单数
* @param query
* @return
*/
int countPushOrderNum(CommonQueryReq query);
Integer countPushOrderNum(CommonQueryReq query);
/**
* 统计推送订阅人数
* @param query
* @return
*/
int countPushOfMember(CommonQueryReq query);
Integer countPushOfMember(CommonQueryReq query);
Integer countCameraShotOfMember(CommonQueryReq query);
Integer countUploadFaceOfMember(CommonQueryReq query);
Integer countCompleteVideoOfMember(CommonQueryReq query);
Integer countTotalVisitorOfMember(CommonQueryReq query);
Integer countCompleteOfVideo(CommonQueryReq query);
Integer countPreviewOfVideo(CommonQueryReq query);
Integer countPayOfOrder(CommonQueryReq query);
Integer countRefundOfOrder(CommonQueryReq query);
BigDecimal countRefundAmount(CommonQueryReq query);
}

View File

@ -0,0 +1,60 @@
package com.ycwl.basic.model.mobile.statistic;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
* @Authorlongbinbin
* @Date2024/12/12 16:24
*/
@Data
@ApiModel("移动端用户转化漏斗")
public class AppStatisticsFunnelVO {
@ApiModelProperty("镜头检测游客数")
private Integer cameraShotOfMemberNum;
@ApiModelProperty("镜头检测游客数_扫码访问人数_转化率")
private String csom_scaom;
@ApiModelProperty("扫码访问人数")
private Integer scanCodeVisitorOfMemberNum;
@ApiModelProperty("扫码访问人数_上传头像人数_转化率")
private String scaom_ufom;
@ApiModelProperty("上传头像(人脸)人数")
private Integer uploadFaceOfMemberNum;
@ApiModelProperty("上传头像人数_推送订阅人数_转化率")
private String ufom_pom;
@ApiModelProperty("推送订阅人数")
private Integer pushOfMemberNum;
@ApiModelProperty("推送订阅人数_生成视频人数_转化率")
private String pom_cvom;
@ApiModelProperty("生成视频人数")
private Integer completeVideoOfMemberNum;
@ApiModelProperty("生成视频人数_预览视频人数_转化率")
private String cvom_pvom;
@ApiModelProperty("预览视频人数")
private Integer previewVideoOfMemberNum;
@ApiModelProperty("预览视频人数_点击购买人数_转化率")
private String pvom_cpom;
@ApiModelProperty("点击购买人数")
private Integer clickOnPayOfMemberNum;
@ApiModelProperty("点击购买人数_支付订单人数_转化率")
private String cpom_pom;
@ApiModelProperty("支付订单人数")
private Integer payOfMemberNum;
@ApiModelProperty("总访问人数")
private Integer totalVisitorOfMemberNum;
@ApiModelProperty("生成视频条数")
private Integer completeOfVideoNum;
@ApiModelProperty("预览视频条数")
private Integer previewOfVideoNum;
@ApiModelProperty("支付订单数")
private Integer payOfOrderNum;
@ApiModelProperty("支付订单金额")
private String payOfOrderAmount;
@ApiModelProperty("退款订单数")
private Integer refundOfOrderNum;
@ApiModelProperty("退款订单金额")
private String refundOfOrderAmount;
}

View File

@ -1,10 +1,7 @@
package com.ycwl.basic.service.impl.mobile;
import com.ycwl.basic.mapper.StatisticsMapper;
import com.ycwl.basic.model.mobile.statistic.AppSta1VO;
import com.ycwl.basic.model.mobile.statistic.AppSta2VO;
import com.ycwl.basic.model.mobile.statistic.AppSta3VO;
import com.ycwl.basic.model.mobile.statistic.CommonQueryReq;
import com.ycwl.basic.model.mobile.statistic.*;
import com.ycwl.basic.service.mobile.AppStatisticsService;
import com.ycwl.basic.utils.ApiResponse;
import com.ycwl.basic.utils.DateUtils;
@ -114,6 +111,110 @@ public class AppStatisticsServiceImpl implements AppStatisticsService {
return ApiResponse.success(vo);
}
@Override
public ApiResponse<AppStatisticsFunnelVO> userConversionFunnel(CommonQueryReq query) {
AppStatisticsFunnelVO vo = new AppStatisticsFunnelVO();
if(query.getEndTime()==null && query.getStartTime()==null){
// 没有传时间则代表用户没有自定义查询时间使用standard来判断查询时间范围
Integer standard = query.getStandard();
if(standard==null){
query.setStandard(0);
}
//获取当前周期的具体时间范围
standardToNewSpecificTime(query);
}
//镜头检测游客数
Integer cameraShotOfMemberNum=statisticsMapper.countCameraShotOfMember(query);
//扫码访问人数
Integer scanCodeVisitorOfMemberNum=statisticsMapper.countScanCodeOfMember(query);
//镜头检测游客数_扫码访问人数_转化率
vo.setCsom_scaom(calculateConversionRate(scanCodeVisitorOfMemberNum,cameraShotOfMemberNum));
//上传头像人脸人数
Integer uploadFaceOfMemberNum=statisticsMapper.countUploadFaceOfMember(query);
//扫码访问人数_上传头像人数_转化率
vo.setScaom_ufom(calculateConversionRate(uploadFaceOfMemberNum,scanCodeVisitorOfMemberNum));
//推送订阅人数
Integer pushOfMemberNum =statisticsMapper.countPushOfMember(query);
//上传头像人数_推送订阅人数_转化率
vo.setUfom_pom((calculateConversionRate(pushOfMemberNum,uploadFaceOfMemberNum)));
//生成视频人数
Integer completeVideoOfMemberNum =statisticsMapper.countCompleteVideoOfMember(query);
//推送订阅人数_生成视频人数_转化率
vo.setPom_cvom((calculateConversionRate(completeVideoOfMemberNum,pushOfMemberNum)));
//预览视频人数
Integer previewVideoOfMemberNum =statisticsMapper.countPreviewVideoOfMember(query);
//生成视频人数_预览视频人数_转化率
vo.setCvom_pvom((calculateConversionRate(previewVideoOfMemberNum,completeVideoOfMemberNum)));
//点击购买人数
Integer clickOnPayOfMemberNum =statisticsMapper.countClickPayOfMember(query);
//预览视频人数_点击购买人数_转化率
vo.setPvom_cpom((calculateConversionRate(clickOnPayOfMemberNum,previewVideoOfMemberNum)));
//支付订单人数
Integer payOfMemberNum =statisticsMapper.countPayOfMember(query);
//点击购买人数_支付订单人数_转化率
vo.setCpom_pom((calculateConversionRate(payOfMemberNum,clickOnPayOfMemberNum)));
//总访问人数
//TODO 2024/12/12 17:56 目前只有扫码访问的方式所以这里总访问人数先等于扫码访问人数
// Integer totalVisitorOfMemberNum =statisticsMapper.countTotalVisitorOfMember(query);
Integer totalVisitorOfMemberNum =scanCodeVisitorOfMemberNum;
//生成视频条数
Integer completeOfVideoNum =statisticsMapper.countCompleteOfVideo(query);
//预览视频条数
Integer previewOfVideoNum =statisticsMapper.countPreviewOfVideo(query);
//支付订单数
Integer payOfOrderNum =statisticsMapper.countPayOfOrder(query);
//支付订单金额
BigDecimal payOfOrderAmount =statisticsMapper.countOrderAmount(query);
//退款订单数
Integer refundOfOrderNum =statisticsMapper.countRefundOfOrder(query);
//退款订单金额
BigDecimal refundOfOrderAmount =statisticsMapper.countRefundAmount(query);
vo.setCameraShotOfMemberNum(cameraShotOfMemberNum);
vo.setScanCodeVisitorOfMemberNum(scanCodeVisitorOfMemberNum);
vo.setUploadFaceOfMemberNum(uploadFaceOfMemberNum);
vo.setPushOfMemberNum(pushOfMemberNum);
vo.setCompleteVideoOfMemberNum(completeVideoOfMemberNum);
vo.setPreviewVideoOfMemberNum(previewVideoOfMemberNum);
vo.setClickOnPayOfMemberNum(clickOnPayOfMemberNum);
vo.setPayOfMemberNum(payOfMemberNum);
//转化率格式
DecimalFormat df = new DecimalFormat("0.0");
vo.setTotalVisitorOfMemberNum(totalVisitorOfMemberNum);
vo.setCompleteOfVideoNum(completeOfVideoNum);
vo.setPreviewOfVideoNum(previewOfVideoNum);
vo.setPayOfOrderNum(payOfOrderNum);
vo.setPayOfOrderAmount(df.format(payOfOrderAmount.setScale(2, RoundingMode.HALF_UP)));
vo.setRefundOfOrderNum(refundOfOrderNum);
vo.setRefundOfOrderAmount(df.format(refundOfOrderAmount.setScale(2, RoundingMode.HALF_UP)));
return ApiResponse.success(vo);
}
/**
*
* @param num1
* @param num2
* @return
*/
private String calculateConversionRate(Integer num1,Integer num2){
//转化率格式
DecimalFormat df = new DecimalFormat("0.00");
if(num2==0){
return "0.00";
}else {
BigDecimal result = new BigDecimal(num1).divide(new BigDecimal(num2), 4, RoundingMode.HALF_UP).multiply(new BigDecimal(100));
return df.format(result);
}
}
/**
*
* @param cycle 周期 1当前 2往期
@ -126,7 +227,7 @@ public class AppStatisticsServiceImpl implements AppStatisticsService {
//查询推送订阅人数
int pushNum=statisticsMapper.countPushOfMember(query);
// 查询预览视频人数
Integer previewNum=statisticsMapper.countPreviewOfMember(query);
Integer previewNum=statisticsMapper.countPreviewVideoOfMember(query);
if(cycle==1){
//当前周期的扫码访问人数
@ -190,7 +291,7 @@ public class AppStatisticsServiceImpl implements AppStatisticsService {
// 计算当前周期的支付订单金额
BigDecimal orderAmount=statisticsMapper.countOrderAmount(query).setScale(2, RoundingMode.HALF_UP);
//查询预览视频人数
int preview=statisticsMapper.countPreviewOfMember(query);
int preview=statisticsMapper.countPreviewVideoOfMember(query);
//查询扫码人数
int scanCode=statisticsMapper.countScanCodeOfMember(query);
//查询付费人数
@ -211,7 +312,7 @@ public class AppStatisticsServiceImpl implements AppStatisticsService {
}
}else if(cycle==2){
//上一个周期的支付订单金额
vo.setNowOrderAmount(orderAmountDf.format(orderAmount));
vo.setPreviousOrderAmount(orderAmountDf.format(orderAmount));
// 计算预览_支付转化率
if(pay==0){
vo.setPreviousPreviewPay("0.00");

View File

@ -1,9 +1,6 @@
package com.ycwl.basic.service.mobile;
import com.ycwl.basic.model.mobile.statistic.AppSta1VO;
import com.ycwl.basic.model.mobile.statistic.AppSta2VO;
import com.ycwl.basic.model.mobile.statistic.AppSta3VO;
import com.ycwl.basic.model.mobile.statistic.CommonQueryReq;
import com.ycwl.basic.model.mobile.statistic.*;
import com.ycwl.basic.utils.ApiResponse;
/**
@ -17,4 +14,6 @@ public interface AppStatisticsService {
ApiResponse<AppSta2VO> twoStatistics(CommonQueryReq query);
ApiResponse<AppSta3VO> freeStatistics(CommonQueryReq query);
ApiResponse<AppStatisticsFunnelVO> userConversionFunnel(CommonQueryReq query);
}

View File

@ -6,95 +6,242 @@
from `order`
where
status = 1 and scenic_id = #{scenicId}
<if test="startTime!= null and startTime!= ''">
<if test="startTime!= null">
and create_at >= #{startTime}
</if>
<if test="endTime!= null and endTime!= ''">
<if test="endTime!= null">
and create_at &lt;= #{endTime}
</if>
</select>
<select id="countPreviewOfMember" resultType="java.lang.Integer">
select ifnull(count(1),0) as count
from statistics
where type=2 and scenic_id = #{scenicId}
<if test="startTime!= null and startTime!= ''">
and create_time >= #{startTime}
</if>
<if test="endTime!= null and endTime!= ''">
and create_time &lt;= #{endTime}
</if>
group by member_id
<select id="countPreviewVideoOfMember" resultType="java.lang.Integer">
SELECT
IFNULL(SUM(count), 0) AS count
FROM (
select count(1) as count
from statistics
where type=2 and scenic_id = #{scenicId}
<if test="startTime!= null">
and create_time >= #{startTime}
</if>
<if test="endTime!= null">
and create_time &lt;= #{endTime}
</if>
group by member_id
)a
</select>
<select id="countScanCodeOfMember" resultType="java.lang.Integer">
select ifnull(count(1),0) as count
from statistics
where type=0 and scenic_id = #{scenicId}
<if test="startTime!= null and startTime!= ''">
and create_time >= #{startTime}
</if>
<if test="endTime!= null and endTime!= ''">
and create_time &lt;= #{endTime}
</if>
group by member_id
SELECT
IFNULL(SUM(count), 0) AS count
FROM (
select count(1) as count
from statistics
where type=0 and scenic_id = #{scenicId}
<if test="startTime!= null">
and create_time >= #{startTime}
</if>
<if test="endTime!= null">
and create_time &lt;= #{endTime}
</if>
group by member_id
) AS subquery;
</select>
<select id="countClickPayOfMember" resultType="java.lang.Integer">
select ifnull(count(1),0) as count
from statistics
where type=9 and scenic_id = #{scenicId}
<if test="startTime!= null and startTime!= ''">
and create_time >= #{startTime}
</if>
<if test="endTime!= null and endTime!= ''">
and create_time &lt;= #{endTime}
</if>
group by member_id
SELECT
IFNULL(SUM(count), 0) AS count
FROM (
select count(1) as count
from statistics
where type=9 and scenic_id = #{scenicId}
<if test="startTime!= null">
and create_time >= #{startTime}
</if>
<if test="endTime!= null">
and create_time &lt;= #{endTime}
</if>
group by member_id
)a
</select>
<select id="countPayOfMember" resultType="java.lang.Integer">
select ifnull(count(1),0) as count
from statistics
where type in(3,4) and scenic_id = #{scenicId}
<if test="startTime!= null and startTime!= ''">
and create_time >= #{startTime}
</if>
<if test="endTime!= null and endTime!= ''">
and create_time &lt;= #{endTime}
</if>
group by member_id
SELECT
IFNULL(SUM(count), 0) AS count
FROM (
select count(1) as count
from statistics
where type in(3,4) and scenic_id = #{scenicId}
<if test="startTime!= null">
and create_time >= #{startTime}
</if>
<if test="endTime!= null">
and create_time &lt;= #{endTime}
</if>
group by member_id
)a
</select>
<select id="countSceneOrderNum" resultType="java.lang.Integer">
select ifnull(count(1),0) as count
from statistics
where type=3 and scenic_id = #{scenicId}
<if test="startTime!= null and startTime!= ''">
and create_time >= #{startTime}
</if>
<if test="endTime!= null and endTime!= ''">
and create_time &lt;= #{endTime}
</if>
group by morph_id
SELECT
IFNULL(SUM(count), 0) AS count
FROM (
select count(1) as count
from statistics
where type=3 and scenic_id = #{scenicId}
<if test="startTime!= null">
and create_time >= #{startTime}
</if>
<if test="endTime!= null">
and create_time &lt;= #{endTime}
</if>
group by morph_id
)a
</select>
<select id="countPushOrderNum" resultType="java.lang.Integer">
select ifnull(count(1),0) as count
from statistics
where type=4 and scenic_id = #{scenicId}
<if test="startTime!= null and startTime!= ''">
SELECT
IFNULL(SUM(count), 0) AS count
FROM (
select count(1) as count
from statistics
where type=4 and scenic_id = #{scenicId}
<if test="startTime!= null">
and create_time >= #{startTime}
</if>
<if test="endTime!= null">
and create_time &lt;= #{endTime}
</if>
group by morph_id
)a
</select>
<select id="countPushOfMember" resultType="java.lang.Integer">
SELECT
IFNULL(SUM(count), 0) AS count
FROM (
select count(1) as count
from statistics
where type=6 and scenic_id = #{scenicId}
<if test="startTime!= null">
and create_time >= #{startTime}
</if>
<if test="endTime!= null">
and create_time &lt;= #{endTime}
</if>
group by member_id
)a
</select>
<select id="countCameraShotOfMember" resultType="java.lang.Integer">
select count(1) as count
from face_sample
where scenic_id = #{scenicId}
<if test="startTime!= null">
and create_at >= #{startTime}
</if>
<if test="endTime!= null">
and create_at &lt;= #{endTime}
</if>
</select>
<select id="countUploadFaceOfMember" resultType="java.lang.Integer">
select count(1) as count
from face
where scenic_id = #{scenicId}
<if test="startTime!= null">
and create_at >= #{startTime}
</if>
<if test="endTime!= null">
and create_at &lt;= #{endTime}
</if>
</select>
<select id="countCompleteVideoOfMember" resultType="java.lang.Integer">
select ifnull(sum(count),0) as count
from(
select count(1) as count
from video
where scenic_id = #{scenicId}
<if test="startTime!= null">
and create_time >= #{startTime}
</if>
<if test="endTime!= null">
and create_time &lt;= #{endTime}
</if>
group by member_id
)a
</select>
<select id="countTotalVisitorOfMember" resultType="java.lang.Integer">
SELECT
IFNULL(SUM(count), 0) AS count
FROM (
select count(1) as count
from statistics
where type=0 and scenic_id = #{scenicId}
<if test="startTime!= null">
and create_time >= #{startTime}
</if>
<if test="endTime!= null">
and create_time &lt;= #{endTime}
</if>
group by member_id
) AS a;
</select>
<select id="countCompleteOfVideo" resultType="java.lang.Integer">
select count(1) as count
from video
where scenic_id = #{scenicId}
<if test="startTime!= null">
and create_time >= #{startTime}
</if>
<if test="endTime!= null and endTime!= ''">
<if test="endTime!= null">
and create_time &lt;= #{endTime}
</if>
</select>
<select id="countPreviewOfVideo" resultType="java.lang.Integer">
SELECT
IFNULL(SUM(count), 0) AS count
FROM (
select count(1) as count
from statistics
where type=0 and scenic_id = #{scenicId}
<if test="startTime!= null">
and create_time >= #{startTime}
</if>
<if test="endTime!= null">
and create_time &lt;= #{endTime}
</if>
group by morph_id
)a
</select>
<select id="countPayOfOrder" resultType="java.lang.Integer">
SELECT
IFNULL(SUM(count), 0) AS count
FROM (
select count(1) as count
from statistics
where type in(3,4) and scenic_id = #{scenicId}
<if test="startTime!= null">
and create_time >= #{startTime}
</if>
<if test="endTime!= null">
and create_time &lt;= #{endTime}
</if>
group by morph_id
)a
</select>
<select id="countPushOfMember" resultType="java.lang.Integer">
select ifnull(count(1),0) as count
<select id="countRefundOfOrder" resultType="java.lang.Integer">
select count(1) as count
from statistics
where type=6 and scenic_id = #{scenicId}
<if test="startTime!= null and startTime!= ''">
where type =5 and scenic_id = #{scenicId}
<if test="startTime!= null">
and create_time >= #{startTime}
</if>
<if test="endTime!= null and endTime!= ''">
<if test="endTime!= null">
and create_time &lt;= #{endTime}
</if>
group by member_id
</select>
<select id="countRefundAmount" resultType="java.math.BigDecimal">
select ifnull(sum(pay_price),0) as payPrice
from `order`
where
status = 2 and scenic_id = #{scenicId}
<if test="startTime!= null">
and create_at >= #{startTime}
</if>
<if test="endTime!= null">
and create_at &lt;= #{endTime}
</if>
</select>
</mapper>