You've already forked FrameTour-BE
Compare commits
4 Commits
a9655814ae
...
f9fcb06355
Author | SHA1 | Date | |
---|---|---|---|
f9fcb06355 | |||
2ae0b3c4b3 | |||
3bd8face68 | |||
1841e43b85 |
@ -2,9 +2,11 @@ package com.ycwl.basic.controller.mobile;
|
|||||||
|
|
||||||
import com.github.pagehelper.PageInfo;
|
import com.github.pagehelper.PageInfo;
|
||||||
import com.ycwl.basic.annotation.IgnoreToken;
|
import com.ycwl.basic.annotation.IgnoreToken;
|
||||||
|
import com.ycwl.basic.constant.BaseContextHandler;
|
||||||
import com.ycwl.basic.model.jwt.JwtInfo;
|
import com.ycwl.basic.model.jwt.JwtInfo;
|
||||||
import com.ycwl.basic.model.mobile.scenic.ScenicAppVO;
|
import com.ycwl.basic.model.mobile.scenic.ScenicAppVO;
|
||||||
import com.ycwl.basic.model.mobile.scenic.ScenicDeviceCountVO;
|
import com.ycwl.basic.model.mobile.scenic.ScenicDeviceCountVO;
|
||||||
|
import com.ycwl.basic.model.mobile.scenic.ScenicIndexVO;
|
||||||
import com.ycwl.basic.model.mobile.scenic.content.ContentPageVO;
|
import com.ycwl.basic.model.mobile.scenic.content.ContentPageVO;
|
||||||
import com.ycwl.basic.model.pc.scenic.entity.ScenicConfigEntity;
|
import com.ycwl.basic.model.pc.scenic.entity.ScenicConfigEntity;
|
||||||
import com.ycwl.basic.model.pc.scenic.req.ScenicReqQuery;
|
import com.ycwl.basic.model.pc.scenic.req.ScenicReqQuery;
|
||||||
@ -22,6 +24,7 @@ import org.apache.commons.lang3.StringUtils;
|
|||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -41,11 +44,21 @@ public class AppScenicController {
|
|||||||
private AppScenicService appScenicService;
|
private AppScenicService appScenicService;
|
||||||
@Autowired
|
@Autowired
|
||||||
private ScenicRepository scenicRepository;
|
private ScenicRepository scenicRepository;
|
||||||
|
private static final List<String> ENABLED_USER_IDs = new ArrayList<>(){{
|
||||||
|
add("3932535453961555968");
|
||||||
|
add("3936121342868459520");
|
||||||
|
add("3936940597855784960");
|
||||||
|
}};
|
||||||
|
|
||||||
@ApiOperation("分页查询景区列表")
|
@ApiOperation("分页查询景区列表")
|
||||||
@PostMapping("/page")
|
@PostMapping("/page")
|
||||||
public ApiResponse<PageInfo<ScenicAppVO>> pageQuery(@RequestBody ScenicReqQuery scenicReqQuery){
|
public ApiResponse<PageInfo<ScenicAppVO>> pageQuery(@RequestBody ScenicReqQuery scenicReqQuery){
|
||||||
return appScenicService.pageQuery(scenicReqQuery);
|
String userId = BaseContextHandler.getUserId();
|
||||||
|
if (ENABLED_USER_IDs.contains(userId)) {
|
||||||
|
return appScenicService.pageQuery(scenicReqQuery);
|
||||||
|
} else {
|
||||||
|
return ApiResponse.success(new PageInfo<>(new ArrayList<>()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ApiOperation("根据id查询景区详情")
|
@ApiOperation("根据id查询景区详情")
|
||||||
@IgnoreToken
|
@IgnoreToken
|
||||||
@ -96,4 +109,10 @@ public class AppScenicController {
|
|||||||
List<ContentPageVO> contentPageVOS = faceService.faceContentList(faceId);
|
List<ContentPageVO> contentPageVOS = faceService.faceContentList(faceId);
|
||||||
return ApiResponse.success(contentPageVOS);
|
return ApiResponse.success(contentPageVOS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PostMapping("/nearby")
|
||||||
|
public ApiResponse<List<ScenicAppVO>> nearby(@RequestBody ScenicIndexVO scenicIndexVO) {
|
||||||
|
List<ScenicAppVO> list = appScenicService.scenicListByLnLa(scenicIndexVO);
|
||||||
|
return ApiResponse.success(list);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@ package com.ycwl.basic.exception;
|
|||||||
|
|
||||||
import com.ycwl.basic.enums.BizCodeEnum;
|
import com.ycwl.basic.enums.BizCodeEnum;
|
||||||
import com.ycwl.basic.utils.ApiResponse;
|
import com.ycwl.basic.utils.ApiResponse;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import org.apache.tomcat.util.http.fileupload.impl.SizeLimitExceededException;
|
import org.apache.tomcat.util.http.fileupload.impl.SizeLimitExceededException;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
@ -11,6 +12,8 @@ import org.springframework.web.bind.annotation.ExceptionHandler;
|
|||||||
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||||
|
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -54,6 +57,12 @@ public class CustomExceptionHandle {
|
|||||||
response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
|
response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
|
||||||
return ApiResponse.buildResponse(bizException.getCode(), bizException.getMsg());
|
return ApiResponse.buildResponse(bizException.getCode(), bizException.getMsg());
|
||||||
}
|
}
|
||||||
|
@ExceptionHandler(value = MethodArgumentTypeMismatchException.class)
|
||||||
|
public ApiResponse<String> handle(HttpServletRequest request, HttpServletResponse response, MethodArgumentTypeMismatchException exception) {
|
||||||
|
response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
|
||||||
|
LOGGER.error("参数错误 -> 请求地址:{},请求方式:{}", request.getRequestURI(), request.getMethod());
|
||||||
|
return ApiResponse.buildResponse(5000, "参数错误!");
|
||||||
|
}
|
||||||
|
|
||||||
@ExceptionHandler(value =IOException.class)
|
@ExceptionHandler(value =IOException.class)
|
||||||
public ApiResponse<String> handle(HttpServletResponse response, IOException e) {
|
public ApiResponse<String> handle(HttpServletResponse response, IOException e) {
|
||||||
|
@ -2,6 +2,7 @@ package com.ycwl.basic.mapper;
|
|||||||
|
|
||||||
import com.ycwl.basic.model.mobile.statistic.req.CommonQueryReq;
|
import com.ycwl.basic.model.mobile.statistic.req.CommonQueryReq;
|
||||||
import com.ycwl.basic.model.mobile.statistic.req.StatisticsRecordAddReq;
|
import com.ycwl.basic.model.mobile.statistic.req.StatisticsRecordAddReq;
|
||||||
|
import com.ycwl.basic.model.mobile.statistic.resp.AppStatisticsFunnelVO;
|
||||||
import org.apache.ibatis.annotations.Mapper;
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
@ -93,4 +94,7 @@ public interface StatisticsMapper {
|
|||||||
List<Long> getBrokerIdListForUser(Long memberId, Date startTime, Date endTime);
|
List<Long> getBrokerIdListForUser(Long memberId, Date startTime, Date endTime);
|
||||||
|
|
||||||
Long getUserRecentEnterType(Long memberId, Date endTime);
|
Long getUserRecentEnterType(Long memberId, Date endTime);
|
||||||
|
|
||||||
|
List<AppStatisticsFunnelVO> listStatByScenic(Long scenicId, Date startTime, Date endTime);
|
||||||
|
int insertStat(Long scenicId, Date date, AppStatisticsFunnelVO data);
|
||||||
}
|
}
|
||||||
|
@ -70,7 +70,7 @@ public class ScenicAppVO {
|
|||||||
/**
|
/**
|
||||||
* 距离
|
* 距离
|
||||||
*/
|
*/
|
||||||
@ApiModelProperty("距离")
|
@ApiModelProperty("距离米")
|
||||||
private BigDecimal distance;
|
private BigDecimal distance;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -18,6 +18,7 @@ public class CommonQueryReq {
|
|||||||
private Integer standard;
|
private Integer standard;
|
||||||
@ApiModelProperty(value = "景区id")
|
@ApiModelProperty(value = "景区id")
|
||||||
private Long scenicId;
|
private Long scenicId;
|
||||||
|
private boolean realtime;
|
||||||
private Date startTime;
|
private Date startTime;
|
||||||
private Date endTime;
|
private Date endTime;
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,8 @@ package com.ycwl.basic.model.mobile.statistic.resp;
|
|||||||
import io.swagger.annotations.ApiModel;
|
import io.swagger.annotations.ApiModel;
|
||||||
import io.swagger.annotations.ApiModelProperty;
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.math.RoundingMode;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @Author:longbinbin
|
* @Author:longbinbin
|
||||||
@ -13,49 +15,118 @@ import lombok.Data;
|
|||||||
public class AppStatisticsFunnelVO {
|
public class AppStatisticsFunnelVO {
|
||||||
|
|
||||||
@ApiModelProperty("镜头检测游客数")
|
@ApiModelProperty("镜头检测游客数")
|
||||||
// private Integer cameraShotOfMemberNum;
|
private int cameraShotOfMemberNum; // cs1
|
||||||
private String cameraShotOfMemberNum;
|
|
||||||
@ApiModelProperty("镜头检测游客数_扫码访问人数_转化率")
|
|
||||||
private String csom_scaom;
|
|
||||||
@ApiModelProperty("扫码访问人数")
|
@ApiModelProperty("扫码访问人数")
|
||||||
private Integer scanCodeVisitorOfMemberNum;
|
private int scanCodeVisitorOfMemberNum; // sv1
|
||||||
@ApiModelProperty("扫码访问人数_上传头像人数_转化率")
|
|
||||||
private String scaom_ufom;
|
|
||||||
@ApiModelProperty("上传头像(人脸)人数")
|
@ApiModelProperty("上传头像(人脸)人数")
|
||||||
private Integer uploadFaceOfMemberNum;
|
private int uploadFaceOfMemberNum; // u1
|
||||||
@ApiModelProperty("上传头像人数_推送订阅人数_转化率")
|
|
||||||
private String ufom_pom;
|
|
||||||
@ApiModelProperty("推送订阅人数")
|
@ApiModelProperty("推送订阅人数")
|
||||||
private Integer pushOfMemberNum;
|
private int pushOfMemberNum; // m1
|
||||||
@ApiModelProperty("推送订阅人数_生成视频人数_转化率")
|
|
||||||
private String pom_cvom;
|
|
||||||
@ApiModelProperty("生成视频人数")
|
@ApiModelProperty("生成视频人数")
|
||||||
private Integer completeVideoOfMemberNum;
|
private int completeVideoOfMemberNum; // gv1
|
||||||
@ApiModelProperty("生成视频人数_预览视频人数_转化率")
|
|
||||||
private String cvom_pvom;
|
|
||||||
@ApiModelProperty("预览视频人数")
|
@ApiModelProperty("预览视频人数")
|
||||||
private Integer previewVideoOfMemberNum;
|
private int previewVideoOfMemberNum; // pv1
|
||||||
@ApiModelProperty("预览视频人数_点击购买人数_转化率")
|
|
||||||
private String pvom_cpom;
|
|
||||||
@ApiModelProperty("点击购买人数")
|
@ApiModelProperty("点击购买人数")
|
||||||
private Integer clickOnPayOfMemberNum;
|
private int clickOnPayOfMemberNum; // cp1
|
||||||
@ApiModelProperty("点击购买人数_支付订单人数_转化率")
|
|
||||||
private String cpom_pom;
|
|
||||||
@ApiModelProperty("支付订单人数")
|
@ApiModelProperty("支付订单人数")
|
||||||
private Integer payOfMemberNum;
|
private int payOfMemberNum; // p1
|
||||||
|
|
||||||
@ApiModelProperty("总访问人数")
|
@ApiModelProperty("总访问人数")
|
||||||
private Integer totalVisitorOfMemberNum;
|
private int totalVisitorOfMemberNum; // v1
|
||||||
@ApiModelProperty("生成视频条数")
|
@ApiModelProperty("生成视频条数")
|
||||||
private Integer completeOfVideoNum;
|
private int completeOfVideoNum; // gv2
|
||||||
@ApiModelProperty("预览视频条数")
|
@ApiModelProperty("预览视频条数")
|
||||||
private Integer previewOfVideoNum;
|
private int previewOfVideoNum; // pv2
|
||||||
@ApiModelProperty("支付订单数")
|
@ApiModelProperty("支付订单数")
|
||||||
private Integer payOfOrderNum;
|
private int payOfOrderNum; // p2
|
||||||
@ApiModelProperty("支付订单金额")
|
@ApiModelProperty("支付订单金额")
|
||||||
private String payOfOrderAmount;
|
private BigDecimal payOfOrderAmount; // o3
|
||||||
@ApiModelProperty("退款订单数")
|
@ApiModelProperty("退款订单数")
|
||||||
private Integer refundOfOrderNum;
|
private int refundOfOrderNum; // ro2
|
||||||
@ApiModelProperty("退款订单金额")
|
@ApiModelProperty("退款订单金额")
|
||||||
private String refundOfOrderAmount;
|
private BigDecimal refundOfOrderAmount; // ro3
|
||||||
|
|
||||||
|
@ApiModelProperty("镜头检测游客数_扫码访问人数_转化率")
|
||||||
|
public String getCsom_scaom() {
|
||||||
|
return "-"; // TODO: REAL
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiModelProperty("扫码访问人数_上传头像人数_转化率")
|
||||||
|
public String getScaom_ufom() {
|
||||||
|
if (uploadFaceOfMemberNum == 0 || scanCodeVisitorOfMemberNum == 0) {
|
||||||
|
return "0.00";
|
||||||
|
}
|
||||||
|
return new BigDecimal(uploadFaceOfMemberNum)
|
||||||
|
.multiply(new BigDecimal(100))
|
||||||
|
.divide(new BigDecimal(scanCodeVisitorOfMemberNum), 2, RoundingMode.HALF_UP)
|
||||||
|
.toString();
|
||||||
|
}
|
||||||
|
@ApiModelProperty("上传头像人数_推送订阅人数_转化率")
|
||||||
|
public String getUfom_pom() {
|
||||||
|
if (pushOfMemberNum == 0 || uploadFaceOfMemberNum == 0) {
|
||||||
|
return "0.00";
|
||||||
|
}
|
||||||
|
return new BigDecimal(uploadFaceOfMemberNum)
|
||||||
|
.multiply(new BigDecimal(100))
|
||||||
|
.divide(new BigDecimal(pushOfMemberNum), 2, RoundingMode.HALF_UP)
|
||||||
|
.toString();
|
||||||
|
}
|
||||||
|
@ApiModelProperty("推送订阅人数_生成视频人数_转化率")
|
||||||
|
public String getPom_cvom() {
|
||||||
|
if (completeVideoOfMemberNum == 0 || pushOfMemberNum == 0) {
|
||||||
|
return "0.00";
|
||||||
|
}
|
||||||
|
return new BigDecimal(completeVideoOfMemberNum)
|
||||||
|
.multiply(new BigDecimal(100))
|
||||||
|
.divide(new BigDecimal(pushOfMemberNum), 2, RoundingMode.HALF_UP)
|
||||||
|
.toString();
|
||||||
|
}
|
||||||
|
@ApiModelProperty("生成视频人数_预览视频人数_转化率")
|
||||||
|
public String getCvom_pvom() {
|
||||||
|
if (previewVideoOfMemberNum == 0 || completeVideoOfMemberNum == 0) {
|
||||||
|
return "0.00";
|
||||||
|
}
|
||||||
|
return new BigDecimal(previewVideoOfMemberNum)
|
||||||
|
.multiply(new BigDecimal(100))
|
||||||
|
.divide(new BigDecimal(completeVideoOfMemberNum), 2, RoundingMode.HALF_UP)
|
||||||
|
.toString();
|
||||||
|
}
|
||||||
|
@ApiModelProperty("预览视频人数_点击购买人数_转化率")
|
||||||
|
public String getPvom_cpom() {
|
||||||
|
if (clickOnPayOfMemberNum == 0 || previewVideoOfMemberNum == 0) {
|
||||||
|
return "0.00";
|
||||||
|
}
|
||||||
|
return new BigDecimal(clickOnPayOfMemberNum)
|
||||||
|
.multiply(new BigDecimal(100))
|
||||||
|
.divide(new BigDecimal(previewVideoOfMemberNum), 2, RoundingMode.HALF_UP)
|
||||||
|
.toString();
|
||||||
|
}
|
||||||
|
@ApiModelProperty("点击购买人数_支付订单人数_转化率")
|
||||||
|
public String getCpom_pom() {
|
||||||
|
if (payOfMemberNum == 0 || clickOnPayOfMemberNum == 0) {
|
||||||
|
return "0.00";
|
||||||
|
}
|
||||||
|
return new BigDecimal(payOfMemberNum)
|
||||||
|
.multiply(new BigDecimal(100))
|
||||||
|
.divide(new BigDecimal(clickOnPayOfMemberNum), 2, RoundingMode.HALF_UP)
|
||||||
|
.toString();
|
||||||
|
}
|
||||||
|
public BigDecimal payOfOrderAmount() {
|
||||||
|
return payOfOrderAmount;
|
||||||
|
}
|
||||||
|
public String getPayOfOrderAmount() {
|
||||||
|
if (payOfOrderAmount == null) {
|
||||||
|
return "0.00";
|
||||||
|
}
|
||||||
|
return payOfOrderAmount.toString();
|
||||||
|
}
|
||||||
|
public BigDecimal refundOfOrderAmount() {
|
||||||
|
return refundOfOrderAmount;
|
||||||
|
}
|
||||||
|
public String getRefundOfOrderAmount() {
|
||||||
|
if (refundOfOrderAmount == null) {
|
||||||
|
return "0.00";
|
||||||
|
}
|
||||||
|
return refundOfOrderAmount.toString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ package com.ycwl.basic.service.mobile;
|
|||||||
import com.github.pagehelper.PageInfo;
|
import com.github.pagehelper.PageInfo;
|
||||||
import com.ycwl.basic.model.mobile.scenic.ScenicAppVO;
|
import com.ycwl.basic.model.mobile.scenic.ScenicAppVO;
|
||||||
import com.ycwl.basic.model.mobile.scenic.ScenicDeviceCountVO;
|
import com.ycwl.basic.model.mobile.scenic.ScenicDeviceCountVO;
|
||||||
|
import com.ycwl.basic.model.mobile.scenic.ScenicIndexVO;
|
||||||
import com.ycwl.basic.model.mobile.scenic.account.ScenicLoginReq;
|
import com.ycwl.basic.model.mobile.scenic.account.ScenicLoginReq;
|
||||||
import com.ycwl.basic.model.mobile.scenic.account.ScenicLoginRespVO;
|
import com.ycwl.basic.model.mobile.scenic.account.ScenicLoginRespVO;
|
||||||
import com.ycwl.basic.model.pc.device.resp.DeviceRespVO;
|
import com.ycwl.basic.model.pc.device.resp.DeviceRespVO;
|
||||||
@ -28,4 +29,6 @@ public interface AppScenicService {
|
|||||||
ApiResponse<ScenicRespVO> getMyScenic();
|
ApiResponse<ScenicRespVO> getMyScenic();
|
||||||
|
|
||||||
ApiResponse<List<DeviceRespVO>> getMyDevices();
|
ApiResponse<List<DeviceRespVO>> getMyDevices();
|
||||||
|
|
||||||
|
List<ScenicAppVO> scenicListByLnLa(ScenicIndexVO scenicIndexVO);
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@ import com.ycwl.basic.mapper.*;
|
|||||||
import com.ycwl.basic.model.jwt.JwtInfo;
|
import com.ycwl.basic.model.jwt.JwtInfo;
|
||||||
import com.ycwl.basic.model.mobile.scenic.ScenicAppVO;
|
import com.ycwl.basic.model.mobile.scenic.ScenicAppVO;
|
||||||
import com.ycwl.basic.model.mobile.scenic.ScenicDeviceCountVO;
|
import com.ycwl.basic.model.mobile.scenic.ScenicDeviceCountVO;
|
||||||
|
import com.ycwl.basic.model.mobile.scenic.ScenicIndexVO;
|
||||||
import com.ycwl.basic.model.mobile.scenic.account.ScenicLoginReq;
|
import com.ycwl.basic.model.mobile.scenic.account.ScenicLoginReq;
|
||||||
import com.ycwl.basic.model.mobile.scenic.account.ScenicLoginRespVO;
|
import com.ycwl.basic.model.mobile.scenic.account.ScenicLoginRespVO;
|
||||||
import com.ycwl.basic.model.pc.device.resp.DeviceRespVO;
|
import com.ycwl.basic.model.pc.device.resp.DeviceRespVO;
|
||||||
@ -21,6 +22,7 @@ import lombok.extern.slf4j.Slf4j;
|
|||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -110,4 +112,10 @@ public class AppScenicServiceImpl implements AppScenicService {
|
|||||||
List<DeviceRespVO> deviceRespVOList = deviceMapper.listByScenicIdWithWVP(account.getScenicId());
|
List<DeviceRespVO> deviceRespVOList = deviceMapper.listByScenicIdWithWVP(account.getScenicId());
|
||||||
return ApiResponse.success(deviceRespVOList);
|
return ApiResponse.success(deviceRespVOList);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ScenicAppVO> scenicListByLnLa(ScenicIndexVO scenicIndexVO) {
|
||||||
|
List<ScenicAppVO> scenicAppVOS = scenicMapper.scenicListByLnLa(scenicIndexVO);
|
||||||
|
return scenicAppVOS.stream().filter(scenic -> scenic.getDistance().compareTo(scenic.getRadius().multiply(BigDecimal.valueOf(1_000L))) < 0).toList();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,8 @@ package com.ycwl.basic.service.mobile.impl;
|
|||||||
|
|
||||||
import cn.hutool.core.date.DateField;
|
import cn.hutool.core.date.DateField;
|
||||||
import cn.hutool.core.date.DateUtil;
|
import cn.hutool.core.date.DateUtil;
|
||||||
|
import com.alibaba.fastjson.JSON;
|
||||||
|
import com.alibaba.fastjson.JSONObject;
|
||||||
import com.ycwl.basic.enums.StatisticEnum;
|
import com.ycwl.basic.enums.StatisticEnum;
|
||||||
import com.ycwl.basic.mapper.StatisticsMapper;
|
import com.ycwl.basic.mapper.StatisticsMapper;
|
||||||
import com.ycwl.basic.model.jwt.JwtInfo;
|
import com.ycwl.basic.model.jwt.JwtInfo;
|
||||||
@ -11,17 +13,22 @@ import com.ycwl.basic.model.mobile.statistic.resp.AppSta1VO;
|
|||||||
import com.ycwl.basic.model.mobile.statistic.resp.AppSta2VO;
|
import com.ycwl.basic.model.mobile.statistic.resp.AppSta2VO;
|
||||||
import com.ycwl.basic.model.mobile.statistic.resp.AppSta3VO;
|
import com.ycwl.basic.model.mobile.statistic.resp.AppSta3VO;
|
||||||
import com.ycwl.basic.model.mobile.statistic.resp.AppStatisticsFunnelVO;
|
import com.ycwl.basic.model.mobile.statistic.resp.AppStatisticsFunnelVO;
|
||||||
|
import com.ycwl.basic.model.pc.scenicDeviceStats.resp.ScenicDeviceStatsResp;
|
||||||
import com.ycwl.basic.service.mobile.AppStatisticsService;
|
import com.ycwl.basic.service.mobile.AppStatisticsService;
|
||||||
import com.ycwl.basic.utils.ApiResponse;
|
import com.ycwl.basic.utils.ApiResponse;
|
||||||
import com.ycwl.basic.utils.JwtTokenUtil;
|
import com.ycwl.basic.utils.JwtTokenUtil;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.data.redis.core.RedisTemplate;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.math.RoundingMode;
|
import java.math.RoundingMode;
|
||||||
import java.text.DecimalFormat;
|
import java.text.DecimalFormat;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @Author:longbinbin
|
* @Author:longbinbin
|
||||||
@ -56,11 +63,13 @@ public class AppStatisticsServiceImpl implements AppStatisticsService {
|
|||||||
standardToNewSpecificTime(query);
|
standardToNewSpecificTime(query);
|
||||||
//查询处理数据逻辑
|
//查询处理数据逻辑
|
||||||
oneStatisticsHandler(1,query,vo);
|
oneStatisticsHandler(1,query,vo);
|
||||||
//----------------------------------------------------
|
if (DateUtil.isIn(query.getStartTime(), DateUtil.tomorrow(), DateUtil.yesterday()) && DateUtil.isIn(query.getEndTime(), DateUtil.tomorrow(), DateUtil.yesterday())) {
|
||||||
//获取上一个周期的具体时间范围
|
//----------------------------------------------------
|
||||||
standardToPreviousSpecificTime(query);
|
//获取上一个周期的具体时间范围
|
||||||
//查询处理数据逻辑
|
standardToPreviousSpecificTime(query);
|
||||||
oneStatisticsHandler(2,query,vo);
|
//查询处理数据逻辑
|
||||||
|
oneStatisticsHandler(2,query,vo);
|
||||||
|
}
|
||||||
}else{
|
}else{
|
||||||
//自定义时间查询,只有当前数据,没有往期对比数据
|
//自定义时间查询,只有当前数据,没有往期对比数据
|
||||||
//查询处理数据逻辑
|
//查询处理数据逻辑
|
||||||
@ -82,11 +91,13 @@ public class AppStatisticsServiceImpl implements AppStatisticsService {
|
|||||||
standardToNewSpecificTime(query);
|
standardToNewSpecificTime(query);
|
||||||
//查询处理数据逻辑
|
//查询处理数据逻辑
|
||||||
twoStatisticsHandler(1,query,vo);
|
twoStatisticsHandler(1,query,vo);
|
||||||
//----------------------------------------------------
|
if (DateUtil.isIn(query.getStartTime(), DateUtil.tomorrow(), DateUtil.yesterday()) && DateUtil.isIn(query.getEndTime(), DateUtil.tomorrow(), DateUtil.yesterday())) {
|
||||||
//获取当前周期的具体时间范围
|
//----------------------------------------------------
|
||||||
standardToPreviousSpecificTime(query);
|
//获取当前周期的具体时间范围
|
||||||
//查询处理数据逻辑
|
standardToPreviousSpecificTime(query);
|
||||||
twoStatisticsHandler(2,query,vo);
|
//查询处理数据逻辑
|
||||||
|
twoStatisticsHandler(2, query, vo);
|
||||||
|
}
|
||||||
}else{
|
}else{
|
||||||
//自定义时间查询,只有当前数据,没有往期对比数据
|
//自定义时间查询,只有当前数据,没有往期对比数据
|
||||||
//查询处理数据逻辑
|
//查询处理数据逻辑
|
||||||
@ -108,11 +119,13 @@ public class AppStatisticsServiceImpl implements AppStatisticsService {
|
|||||||
standardToNewSpecificTime(query);
|
standardToNewSpecificTime(query);
|
||||||
//查询处理数据逻辑
|
//查询处理数据逻辑
|
||||||
freeStatisticsHandler(1,query,vo);
|
freeStatisticsHandler(1,query,vo);
|
||||||
//----------------------------------------------------
|
if (DateUtil.isIn(query.getStartTime(), DateUtil.tomorrow(), DateUtil.yesterday()) && DateUtil.isIn(query.getEndTime(), DateUtil.tomorrow(), DateUtil.yesterday())) {
|
||||||
//获取当前周期的具体时间范围
|
//----------------------------------------------------
|
||||||
standardToPreviousSpecificTime(query);
|
//获取当前周期的具体时间范围
|
||||||
//查询处理数据逻辑
|
standardToPreviousSpecificTime(query);
|
||||||
freeStatisticsHandler(2,query,vo);
|
//查询处理数据逻辑
|
||||||
|
freeStatisticsHandler(2, query, vo);
|
||||||
|
}
|
||||||
}else{
|
}else{
|
||||||
//自定义时间查询,只有当前数据,没有往期对比数据
|
//自定义时间查询,只有当前数据,没有往期对比数据
|
||||||
//查询处理数据逻辑
|
//查询处理数据逻辑
|
||||||
@ -121,8 +134,13 @@ public class AppStatisticsServiceImpl implements AppStatisticsService {
|
|||||||
return ApiResponse.success(vo);
|
return ApiResponse.success(vo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private RedisTemplate<String, String> redisTemplate;
|
||||||
|
private ReentrantLock lock = new ReentrantLock();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ApiResponse<AppStatisticsFunnelVO> userConversionFunnel(CommonQueryReq query) {
|
public ApiResponse<AppStatisticsFunnelVO> userConversionFunnel(CommonQueryReq query) {
|
||||||
|
String redisKey = "statistics:tmp_cache:"+query.getScenicId();
|
||||||
AppStatisticsFunnelVO vo = new AppStatisticsFunnelVO();
|
AppStatisticsFunnelVO vo = new AppStatisticsFunnelVO();
|
||||||
if(query.getEndTime()==null && query.getStartTime()==null){
|
if(query.getEndTime()==null && query.getStartTime()==null){
|
||||||
// 没有传时间,则代表用户没有自定义查询时间,使用standard来判断查询时间范围
|
// 没有传时间,则代表用户没有自定义查询时间,使用standard来判断查询时间范围
|
||||||
@ -133,89 +151,138 @@ public class AppStatisticsServiceImpl implements AppStatisticsService {
|
|||||||
//获取当前周期的具体时间范围
|
//获取当前周期的具体时间范围
|
||||||
standardToNewSpecificTime(query);
|
standardToNewSpecificTime(query);
|
||||||
}
|
}
|
||||||
|
if (!query.isRealtime()) {
|
||||||
|
if (!(DateUtil.isIn(query.getStartTime(), DateUtil.tomorrow(), DateUtil.yesterday()) && DateUtil.isIn(query.getEndTime(), DateUtil.tomorrow(), DateUtil.yesterday()))) {
|
||||||
|
// 查询缓存数据
|
||||||
|
List<AppStatisticsFunnelVO> list = statisticsMapper.listStatByScenic(query.getScenicId(), query.getStartTime(), query.getEndTime());
|
||||||
|
AppStatisticsFunnelVO resp = new AppStatisticsFunnelVO();
|
||||||
|
if (list != null && !list.isEmpty()) {
|
||||||
|
for (AppStatisticsFunnelVO item : list) {
|
||||||
|
// Integer fields
|
||||||
|
resp.setCameraShotOfMemberNum(addIntSafely(resp.getCameraShotOfMemberNum(), item.getCameraShotOfMemberNum()));
|
||||||
|
resp.setScanCodeVisitorOfMemberNum(addIntSafely(resp.getScanCodeVisitorOfMemberNum(), item.getScanCodeVisitorOfMemberNum()));
|
||||||
|
resp.setUploadFaceOfMemberNum(addIntSafely(resp.getUploadFaceOfMemberNum(), item.getUploadFaceOfMemberNum()));
|
||||||
|
resp.setPushOfMemberNum(addIntSafely(resp.getPushOfMemberNum(), item.getPushOfMemberNum()));
|
||||||
|
resp.setCompleteVideoOfMemberNum(addIntSafely(resp.getCompleteVideoOfMemberNum(), item.getCompleteVideoOfMemberNum()));
|
||||||
|
resp.setPreviewVideoOfMemberNum(addIntSafely(resp.getPreviewVideoOfMemberNum(), item.getPreviewVideoOfMemberNum()));
|
||||||
|
resp.setClickOnPayOfMemberNum(addIntSafely(resp.getClickOnPayOfMemberNum(), item.getClickOnPayOfMemberNum()));
|
||||||
|
resp.setPayOfMemberNum(addIntSafely(resp.getPayOfMemberNum(), item.getPayOfMemberNum()));
|
||||||
|
resp.setTotalVisitorOfMemberNum(addIntSafely(resp.getTotalVisitorOfMemberNum(), item.getTotalVisitorOfMemberNum()));
|
||||||
|
resp.setCompleteOfVideoNum(addIntSafely(resp.getCompleteOfVideoNum(), item.getCompleteOfVideoNum()));
|
||||||
|
resp.setPreviewOfVideoNum(addIntSafely(resp.getPreviewOfVideoNum(), item.getPreviewOfVideoNum()));
|
||||||
|
resp.setPayOfOrderNum(addIntSafely(resp.getPayOfOrderNum(), item.getPayOfOrderNum()));
|
||||||
|
resp.setRefundOfOrderNum(addIntSafely(resp.getRefundOfOrderNum(), item.getRefundOfOrderNum()));
|
||||||
|
|
||||||
|
// BigDecimal fields
|
||||||
|
resp.setPayOfOrderAmount(addBigDecimalSafely(resp.payOfOrderAmount(), item.payOfOrderAmount()));
|
||||||
//镜头检测游客数
|
resp.setRefundOfOrderAmount(addBigDecimalSafely(resp.refundOfOrderAmount(), item.refundOfOrderAmount()));
|
||||||
Integer cameraShotOfMemberNum=statisticsMapper.countCameraShotOfMember(query);
|
}
|
||||||
//扫码访问人数
|
}
|
||||||
// 扫小程序码或景区码进入访问的用户数,包括授权用户(使用OpenID进行精准统计)和未授权用户(使用 UUID统计访问)。但当用户授权时,获取OpenID并与UUID关联,删除本地UUID,避免重复记录。
|
return ApiResponse.success(resp);
|
||||||
Integer scanCodeVisitorOfMemberNum=statisticsMapper.countScanCodeOfMember(query);
|
}
|
||||||
//镜头检测游客数_扫码访问人数_转化率
|
|
||||||
// vo.setCsom_scaom(calculateConversionRate(scanCodeVisitorOfMemberNum,cameraShotOfMemberNum));
|
|
||||||
vo.setCsom_scaom("-");
|
|
||||||
//上传头像(人脸)人数
|
|
||||||
// 上传了人脸的用户数(包括本地临时ID和获取到OpenID的,同一设备微信获取到OpenID要覆盖掉之前生成的临时ID),上传多张人脸都只算一个人。
|
|
||||||
Integer uploadFaceOfMemberNum=statisticsMapper.countUploadFaceOfMember(query);
|
|
||||||
//扫码访问人数_上传头像人数_转化率
|
|
||||||
vo.setScaom_ufom(calculateConversionRate(uploadFaceOfMemberNum,scanCodeVisitorOfMemberNum));
|
|
||||||
//推送订阅人数
|
|
||||||
// 只要点了允许通知,哪怕只勾选1条订阅都算
|
|
||||||
Integer pushOfMemberNum =statisticsMapper.countPushOfMember(query);
|
|
||||||
//上传头像人数_推送订阅人数_转化率
|
|
||||||
vo.setUfom_pom((calculateConversionRate(pushOfMemberNum,uploadFaceOfMemberNum)));
|
|
||||||
//生成视频人数
|
|
||||||
// 生成过Vlog视频的用户ID数,要注意屏蔽掉以前没有片段也能生成的情况
|
|
||||||
Integer completeVideoOfMemberNum =statisticsMapper.countCompleteVideoOfMember(query);
|
|
||||||
//推送订阅人数_生成视频人数_转化率
|
|
||||||
vo.setPom_cvom((calculateConversionRate(completeVideoOfMemberNum,pushOfMemberNum)));
|
|
||||||
//预览视频人数
|
|
||||||
// 购买前播放了5秒的视频条数。
|
|
||||||
Integer previewVideoOfMemberNum =statisticsMapper.countPreviewVideoOfMember(query);
|
|
||||||
if (previewVideoOfMemberNum==null){
|
|
||||||
previewVideoOfMemberNum=0;
|
|
||||||
}
|
}
|
||||||
//生成视频人数_预览视频人数_转化率
|
if (!query.isRealtime()) {
|
||||||
vo.setCvom_pvom((calculateConversionRate(previewVideoOfMemberNum,completeVideoOfMemberNum)));
|
if (DateUtil.isIn(query.getStartTime(), DateUtil.tomorrow(), DateUtil.yesterday()) && DateUtil.isIn(query.getEndTime(), DateUtil.tomorrow(), DateUtil.yesterday())) {
|
||||||
//点击购买人数
|
// 缓存
|
||||||
// 点了立即购买按钮的用户ID就算,包括支付的和未支付的都算,只要点击了。
|
if (redisTemplate.hasKey(redisKey)) {
|
||||||
Integer clickOnPayOfMemberNum =statisticsMapper.countClickPayOfMember(query);
|
String s = redisTemplate.opsForValue().get(redisKey);
|
||||||
//预览视频人数_点击购买人数_转化率
|
JSONObject cacheObj = JSON.parseObject(s);
|
||||||
vo.setPvom_cpom((calculateConversionRate(clickOnPayOfMemberNum,previewVideoOfMemberNum)));
|
return ApiResponse.success(cacheObj.toJavaObject(AppStatisticsFunnelVO.class));
|
||||||
//支付订单人数
|
}
|
||||||
Integer payOfMemberNum =statisticsMapper.countPayOfMember(query);
|
}
|
||||||
//点击购买人数_支付订单人数_转化率
|
}
|
||||||
vo.setCpom_pom((calculateConversionRate(payOfMemberNum,clickOnPayOfMemberNum)));
|
|
||||||
//总访问人数
|
lock.lock();
|
||||||
// 通过任何途径访问到小程序的总人数,包括授权用户和未授权用户。
|
try {
|
||||||
Integer totalVisitorOfMemberNum =statisticsMapper.countTotalVisitorOfMember(query);
|
// 缓存
|
||||||
|
if (!query.isRealtime()) {
|
||||||
|
if (DateUtil.isIn(query.getStartTime(), DateUtil.tomorrow(), DateUtil.yesterday()) && DateUtil.isIn(query.getEndTime(), DateUtil.tomorrow(), DateUtil.yesterday())) {
|
||||||
|
// 缓存
|
||||||
|
if (redisTemplate.hasKey(redisKey)) {
|
||||||
|
String s = redisTemplate.opsForValue().get(redisKey);
|
||||||
|
JSONObject cacheObj = JSON.parseObject(s);
|
||||||
|
return ApiResponse.success(cacheObj.toJavaObject(AppStatisticsFunnelVO.class));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//镜头检测游客数
|
||||||
|
// Integer cameraShotOfMemberNum=statisticsMapper.countCameraShotOfMember(query);
|
||||||
|
//扫码访问人数
|
||||||
|
// 扫小程序码或景区码进入访问的用户数,包括授权用户(使用OpenID进行精准统计)和未授权用户(使用 UUID统计访问)。但当用户授权时,获取OpenID并与UUID关联,删除本地UUID,避免重复记录。
|
||||||
|
Integer scanCodeVisitorOfMemberNum=statisticsMapper.countScanCodeOfMember(query);
|
||||||
|
//上传头像(人脸)人数
|
||||||
|
// 上传了人脸的用户数(包括本地临时ID和获取到OpenID的,同一设备微信获取到OpenID要覆盖掉之前生成的临时ID),上传多张人脸都只算一个人。
|
||||||
|
Integer uploadFaceOfMemberNum=statisticsMapper.countUploadFaceOfMember(query);
|
||||||
|
//推送订阅人数
|
||||||
|
// 只要点了允许通知,哪怕只勾选1条订阅都算
|
||||||
|
Integer pushOfMemberNum =statisticsMapper.countPushOfMember(query);
|
||||||
|
//生成视频人数
|
||||||
|
// 生成过Vlog视频的用户ID数,要注意屏蔽掉以前没有片段也能生成的情况
|
||||||
|
Integer completeVideoOfMemberNum =statisticsMapper.countCompleteVideoOfMember(query);
|
||||||
|
//预览视频人数
|
||||||
|
// 购买前播放了5秒的视频条数。
|
||||||
|
Integer previewVideoOfMemberNum =statisticsMapper.countPreviewVideoOfMember(query);
|
||||||
|
if (previewVideoOfMemberNum==null){
|
||||||
|
previewVideoOfMemberNum=0;
|
||||||
|
}
|
||||||
|
//点击购买人数
|
||||||
|
// 点了立即购买按钮的用户ID就算,包括支付的和未支付的都算,只要点击了。
|
||||||
|
Integer clickOnPayOfMemberNum =statisticsMapper.countClickPayOfMember(query);
|
||||||
|
//支付订单人数
|
||||||
|
Integer payOfMemberNum =statisticsMapper.countPayOfMember(query);
|
||||||
|
//总访问人数
|
||||||
|
// 通过任何途径访问到小程序的总人数,包括授权用户和未授权用户。
|
||||||
|
Integer totalVisitorOfMemberNum =statisticsMapper.countTotalVisitorOfMember(query);
|
||||||
// Integer totalVisitorOfMemberNum =scanCodeVisitorOfMemberNum;
|
// Integer totalVisitorOfMemberNum =scanCodeVisitorOfMemberNum;
|
||||||
//生成视频条数
|
//生成视频条数
|
||||||
// 仅指代生成的Vlog条数,不包含录像原片。
|
// 仅指代生成的Vlog条数,不包含录像原片。
|
||||||
Integer completeOfVideoNum =statisticsMapper.countCompleteOfVideo(query);
|
Integer completeOfVideoNum =statisticsMapper.countCompleteOfVideo(query);
|
||||||
//预览视频条数
|
//预览视频条数
|
||||||
Integer previewOfVideoNum =statisticsMapper.countPreviewOfVideo(query);
|
Integer previewOfVideoNum =statisticsMapper.countPreviewOfVideo(query);
|
||||||
//支付订单数
|
//支付订单数
|
||||||
Integer payOfOrderNum =statisticsMapper.countPayOfOrder(query);
|
Integer payOfOrderNum =statisticsMapper.countPayOfOrder(query);
|
||||||
//支付订单金额
|
//支付订单金额
|
||||||
BigDecimal payOfOrderAmount =statisticsMapper.countOrderAmount(query);
|
BigDecimal payOfOrderAmount =statisticsMapper.countOrderAmount(query);
|
||||||
//退款订单数
|
//退款订单数
|
||||||
Integer refundOfOrderNum =statisticsMapper.countRefundOfOrder(query);
|
Integer refundOfOrderNum =statisticsMapper.countRefundOfOrder(query);
|
||||||
//退款订单金额
|
//退款订单金额
|
||||||
BigDecimal refundOfOrderAmount =statisticsMapper.countRefundAmount(query);
|
BigDecimal refundOfOrderAmount =statisticsMapper.countRefundAmount(query);
|
||||||
|
|
||||||
// vo.setCameraShotOfMemberNum(cameraShotOfMemberNum);
|
vo.setScanCodeVisitorOfMemberNum(scanCodeVisitorOfMemberNum);
|
||||||
vo.setCameraShotOfMemberNum("-");
|
vo.setUploadFaceOfMemberNum(uploadFaceOfMemberNum);
|
||||||
vo.setScanCodeVisitorOfMemberNum(scanCodeVisitorOfMemberNum);
|
vo.setPushOfMemberNum(pushOfMemberNum);
|
||||||
vo.setUploadFaceOfMemberNum(uploadFaceOfMemberNum);
|
vo.setCompleteVideoOfMemberNum(completeVideoOfMemberNum);
|
||||||
vo.setPushOfMemberNum(pushOfMemberNum);
|
vo.setPreviewVideoOfMemberNum(previewVideoOfMemberNum);
|
||||||
vo.setCompleteVideoOfMemberNum(completeVideoOfMemberNum);
|
vo.setClickOnPayOfMemberNum(clickOnPayOfMemberNum);
|
||||||
vo.setPreviewVideoOfMemberNum(previewVideoOfMemberNum);
|
vo.setPayOfMemberNum(payOfMemberNum);
|
||||||
vo.setClickOnPayOfMemberNum(clickOnPayOfMemberNum);
|
|
||||||
vo.setPayOfMemberNum(payOfMemberNum);
|
|
||||||
|
|
||||||
//转化率格式
|
vo.setTotalVisitorOfMemberNum(totalVisitorOfMemberNum);
|
||||||
DecimalFormat df = new DecimalFormat("0.0");
|
vo.setCompleteOfVideoNum(completeOfVideoNum);
|
||||||
|
vo.setPreviewOfVideoNum(previewOfVideoNum);
|
||||||
|
vo.setPayOfOrderNum(payOfOrderNum);
|
||||||
|
vo.setPayOfOrderAmount(payOfOrderAmount.setScale(2, RoundingMode.HALF_UP));
|
||||||
|
vo.setRefundOfOrderNum(refundOfOrderNum);
|
||||||
|
vo.setRefundOfOrderAmount(refundOfOrderAmount.setScale(2, RoundingMode.HALF_UP));
|
||||||
|
statisticsMapper.insertStat(query.getScenicId(), new Date(), vo);
|
||||||
|
redisTemplate.opsForValue().set(redisKey, JSON.toJSONString(vo), 60, TimeUnit.SECONDS);
|
||||||
|
return ApiResponse.success(vo);
|
||||||
|
} finally {
|
||||||
|
lock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
vo.setTotalVisitorOfMemberNum(totalVisitorOfMemberNum);
|
private BigDecimal addBigDecimalSafely(BigDecimal bd1, BigDecimal bd2) {
|
||||||
vo.setCompleteOfVideoNum(completeOfVideoNum);
|
if (bd1 == null) {
|
||||||
vo.setPreviewOfVideoNum(previewOfVideoNum);
|
bd1 = BigDecimal.ZERO;
|
||||||
vo.setPayOfOrderNum(payOfOrderNum);
|
}
|
||||||
vo.setPayOfOrderAmount(df.format(payOfOrderAmount.setScale(2, RoundingMode.HALF_UP)));
|
if (bd2 == null) {
|
||||||
vo.setRefundOfOrderNum(refundOfOrderNum);
|
bd2 = BigDecimal.ZERO;
|
||||||
vo.setRefundOfOrderAmount(df.format(refundOfOrderAmount.setScale(2, RoundingMode.HALF_UP)));
|
}
|
||||||
|
return bd1.add(bd2).setScale(2, RoundingMode.HALF_UP);
|
||||||
|
}
|
||||||
|
|
||||||
return ApiResponse.success(vo);
|
private int addIntSafely(Integer int1, Integer int2) {
|
||||||
|
return int1 == null ? 0 : int1 + (int2 == null ? 0 : int2);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -272,27 +339,22 @@ public class AppStatisticsServiceImpl implements AppStatisticsService {
|
|||||||
* @param vo
|
* @param vo
|
||||||
*/
|
*/
|
||||||
private void freeStatisticsHandler(Integer cycle,CommonQueryReq query,AppSta3VO vo){
|
private void freeStatisticsHandler(Integer cycle,CommonQueryReq query,AppSta3VO vo){
|
||||||
//查询扫码访问人数
|
ApiResponse<AppStatisticsFunnelVO> resp = userConversionFunnel(query);
|
||||||
int sceneNum=statisticsMapper.countScanCodeOfMember(query);
|
AppStatisticsFunnelVO data = resp.getData();
|
||||||
//查询推送订阅人数
|
|
||||||
int pushNum=statisticsMapper.countPushOfMember(query);
|
|
||||||
// 查询预览视频人数
|
|
||||||
Integer previewNum=statisticsMapper.countPreviewVideoOfMember(query);
|
|
||||||
|
|
||||||
if(cycle==1){
|
if(cycle==1){
|
||||||
//当前周期的扫码访问人数
|
//当前周期的扫码访问人数
|
||||||
vo.setNowScanCodeOfPeopleNum(sceneNum);
|
vo.setNowScanCodeOfPeopleNum(data.getScanCodeVisitorOfMemberNum());
|
||||||
//当前周期的推送订阅人数
|
//当前周期的推送订阅人数
|
||||||
vo.setNowPushOfPeopleNum(pushNum);
|
vo.setNowPushOfPeopleNum(data.getPushOfMemberNum());
|
||||||
//当前周期的预览视频人数
|
//当前周期的预览视频人数
|
||||||
vo.setNowPreviewVideoOfPeopleNum(previewNum);
|
vo.setNowPreviewVideoOfPeopleNum(data.getPreviewOfVideoNum());
|
||||||
}else if(cycle==2){
|
}else if(cycle==2){
|
||||||
//上一个周期的扫码访问人数
|
//上一个周期的扫码访问人数
|
||||||
vo.setPreviousScanCodeOfPeopleNum(sceneNum);
|
vo.setPreviousScanCodeOfPeopleNum(data.getScanCodeVisitorOfMemberNum());
|
||||||
//上一个周期的推送订阅人数
|
//上一个周期的推送订阅人数
|
||||||
vo.setPreviousPushOfPeopleNum(pushNum);
|
vo.setPreviousPushOfPeopleNum(data.getPushOfMemberNum());
|
||||||
//上一个周期的预览视频人数
|
//上一个周期的预览视频人数
|
||||||
vo.setPreviousPreviewVideoOfPeopleNum(previewNum);
|
vo.setPreviousPreviewVideoOfPeopleNum(data.getPreviewOfVideoNum());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -334,23 +396,25 @@ public class AppStatisticsServiceImpl implements AppStatisticsService {
|
|||||||
* @param vo
|
* @param vo
|
||||||
*/
|
*/
|
||||||
private void oneStatisticsHandler(Integer cycle,CommonQueryReq query,AppSta1VO vo){
|
private void oneStatisticsHandler(Integer cycle,CommonQueryReq query,AppSta1VO vo){
|
||||||
|
ApiResponse<AppStatisticsFunnelVO> resp = userConversionFunnel(query);
|
||||||
|
AppStatisticsFunnelVO data = resp.getData();
|
||||||
//订单金额格式
|
//订单金额格式
|
||||||
DecimalFormat orderAmountDf = new DecimalFormat("0.0");
|
DecimalFormat orderAmountDf = new DecimalFormat("0.0");
|
||||||
//转化率格式
|
//转化率格式
|
||||||
DecimalFormat df = new DecimalFormat("0.00");
|
DecimalFormat df = new DecimalFormat("0.00");
|
||||||
// 计算当前周期的支付订单金额
|
// 计算当前周期的支付订单金额
|
||||||
BigDecimal orderAmount=statisticsMapper.countOrderAmount(query).setScale(2, RoundingMode.HALF_UP);
|
String orderAmount=data.getPayOfOrderAmount();
|
||||||
//查询预览视频人数
|
//查询预览视频人数
|
||||||
int preview=statisticsMapper.countPreviewVideoOfMember(query);
|
int preview=data.getPreviewOfVideoNum();
|
||||||
//查询扫码人数
|
//查询扫码人数
|
||||||
int scanCode=statisticsMapper.countScanCodeOfMember(query);
|
int scanCode=data.getScanCodeVisitorOfMemberNum();
|
||||||
//查询付费人数
|
//查询付费人数
|
||||||
int pay=statisticsMapper.countPayOfMember(query);
|
int pay=data.getPayOfMemberNum();
|
||||||
int payCount=statisticsMapper.countPayOfOrder(query);
|
int payCount=data.getPayOfOrderNum();
|
||||||
|
|
||||||
if(cycle==1){
|
if(cycle==1){
|
||||||
// 支付过订单的金额,包含已退款的金额。
|
// 支付过订单的金额,包含已退款的金额。
|
||||||
vo.setNowOrderAmount(orderAmountDf.format(orderAmount));
|
vo.setNowOrderAmount(orderAmount);
|
||||||
// 订单数÷预览人数。假设一共5个人预览,产生了3个订单,其实是2个人支付的(其中1人购买2单),预览-支付转化率是3÷5,而不是2÷5。
|
// 订单数÷预览人数。假设一共5个人预览,产生了3个订单,其实是2个人支付的(其中1人购买2单),预览-支付转化率是3÷5,而不是2÷5。
|
||||||
if(preview==0){
|
if(preview==0){
|
||||||
vo.setNowPreviewPay("0.00");
|
vo.setNowPreviewPay("0.00");
|
||||||
@ -368,7 +432,7 @@ public class AppStatisticsServiceImpl implements AppStatisticsService {
|
|||||||
}else if(cycle==2){
|
}else if(cycle==2){
|
||||||
//上一个周期的支付订单金额
|
//上一个周期的支付订单金额
|
||||||
// 支付过订单的金额,包含已退款的金额。
|
// 支付过订单的金额,包含已退款的金额。
|
||||||
vo.setPreviousOrderAmount(orderAmountDf.format(orderAmount));
|
vo.setPreviousOrderAmount(orderAmount);
|
||||||
// 订单数÷预览人数。假设一共5个人预览,产生了3个订单,其实是2个人支付的(其中1人购买2单),预览-支付转化率是3÷5,而不是2÷5。
|
// 订单数÷预览人数。假设一共5个人预览,产生了3个订单,其实是2个人支付的(其中1人购买2单),预览-支付转化率是3÷5,而不是2÷5。
|
||||||
if(preview==0){
|
if(preview==0){
|
||||||
vo.setPreviousPreviewPay("0.00");
|
vo.setPreviousPreviewPay("0.00");
|
||||||
|
@ -27,7 +27,7 @@ public class DeviceStatsServiceImpl implements DeviceStatsService {
|
|||||||
end = DateUtil.endOfDay(new Date());
|
end = DateUtil.endOfDay(new Date());
|
||||||
}
|
}
|
||||||
ScenicDeviceStatsListResp resp = new ScenicDeviceStatsListResp();
|
ScenicDeviceStatsListResp resp = new ScenicDeviceStatsListResp();
|
||||||
if (DateUtil.isIn(start, DateUtil.tomorrow(), DateUtil.yesterday()) && DateUtil.isIn(start, DateUtil.tomorrow(), DateUtil.yesterday())) {
|
if (DateUtil.isIn(start, DateUtil.tomorrow(), DateUtil.yesterday()) && DateUtil.isIn(end, DateUtil.tomorrow(), DateUtil.yesterday())) {
|
||||||
resp.setRealtime(true);
|
resp.setRealtime(true);
|
||||||
List<ScenicDeviceStatsResp> data = mapper.countRealtimeStatsByScenicId(scenicId, start, end);
|
List<ScenicDeviceStatsResp> data = mapper.countRealtimeStatsByScenicId(scenicId, start, end);
|
||||||
resp.setData(data);
|
resp.setData(data);
|
||||||
|
@ -2,7 +2,15 @@ package com.ycwl.basic.task;
|
|||||||
|
|
||||||
import cn.hutool.core.date.DateUtil;
|
import cn.hutool.core.date.DateUtil;
|
||||||
import com.ycwl.basic.mapper.ScenicDeviceStatsMapper;
|
import com.ycwl.basic.mapper.ScenicDeviceStatsMapper;
|
||||||
|
import com.ycwl.basic.mapper.ScenicMapper;
|
||||||
|
import com.ycwl.basic.mapper.StatisticsMapper;
|
||||||
|
import com.ycwl.basic.model.mobile.statistic.req.CommonQueryReq;
|
||||||
|
import com.ycwl.basic.model.mobile.statistic.resp.AppStatisticsFunnelVO;
|
||||||
|
import com.ycwl.basic.model.pc.scenic.req.ScenicReqQuery;
|
||||||
|
import com.ycwl.basic.model.pc.scenic.resp.ScenicRespVO;
|
||||||
import com.ycwl.basic.model.pc.scenicDeviceStats.entity.ScenicDeviceStatsEntity;
|
import com.ycwl.basic.model.pc.scenicDeviceStats.entity.ScenicDeviceStatsEntity;
|
||||||
|
import com.ycwl.basic.service.mobile.AppStatisticsService;
|
||||||
|
import com.ycwl.basic.utils.ApiResponse;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.scheduling.annotation.EnableScheduling;
|
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||||
import org.springframework.scheduling.annotation.Scheduled;
|
import org.springframework.scheduling.annotation.Scheduled;
|
||||||
@ -13,9 +21,15 @@ import java.util.List;
|
|||||||
|
|
||||||
@Component
|
@Component
|
||||||
@EnableScheduling
|
@EnableScheduling
|
||||||
public class ScenicDeviceStatsTask {
|
public class ScenicStatsTask {
|
||||||
@Autowired
|
@Autowired
|
||||||
private ScenicDeviceStatsMapper mapper;
|
private ScenicDeviceStatsMapper mapper;
|
||||||
|
@Autowired
|
||||||
|
private StatisticsMapper statisticsMapper;
|
||||||
|
@Autowired
|
||||||
|
private AppStatisticsService statisticsService;
|
||||||
|
@Autowired
|
||||||
|
private ScenicMapper scenicMapper;
|
||||||
@Scheduled(cron = "0 10 0 * * *")
|
@Scheduled(cron = "0 10 0 * * *")
|
||||||
public void countDeviceStats() {
|
public void countDeviceStats() {
|
||||||
Date yesterdayStart = DateUtil.beginOfDay(DateUtil.yesterday());
|
Date yesterdayStart = DateUtil.beginOfDay(DateUtil.yesterday());
|
||||||
@ -38,4 +52,20 @@ public class ScenicDeviceStatsTask {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@Scheduled(cron = "0 20 0 * * *")
|
||||||
|
public void countScenicStats() {
|
||||||
|
Date yesterdayStart = DateUtil.beginOfDay(DateUtil.yesterday());
|
||||||
|
Date yesterdayEnd = DateUtil.endOfDay(yesterdayStart);
|
||||||
|
List<ScenicRespVO> list = scenicMapper.list(new ScenicReqQuery());
|
||||||
|
list.forEach((scenic) -> {
|
||||||
|
CommonQueryReq query = new CommonQueryReq();
|
||||||
|
query.setScenicId(scenic.getId());
|
||||||
|
query.setStartTime(yesterdayStart);
|
||||||
|
query.setEndTime(yesterdayEnd);
|
||||||
|
query.setRealtime(true);
|
||||||
|
ApiResponse<AppStatisticsFunnelVO> resp = statisticsService.userConversionFunnel(query);
|
||||||
|
AppStatisticsFunnelVO data = resp.getData();
|
||||||
|
statisticsMapper.insertStat(scenic.getId(), yesterdayStart, data);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
@ -173,7 +173,8 @@
|
|||||||
where s.id = #{id}
|
where s.id = #{id}
|
||||||
</select>
|
</select>
|
||||||
<select id="appList" resultType="com.ycwl.basic.model.mobile.scenic.ScenicAppVO">
|
<select id="appList" resultType="com.ycwl.basic.model.mobile.scenic.ScenicAppVO">
|
||||||
select s.id, `name`, `phone`, introduction,cover_url, longitude, latitude, radius, province, city, area, address
|
select s.id, `name`, `phone`, introduction, cover_url, longitude, latitude, radius, province, city, area, address,
|
||||||
|
(SELECT COUNT(1) FROM device WHERE scenic_id = s.id AND status = 1) as deviceNum
|
||||||
from scenic s
|
from scenic s
|
||||||
where
|
where
|
||||||
`status` = 1
|
`status` = 1
|
||||||
@ -218,13 +219,15 @@
|
|||||||
ifnull(
|
ifnull(
|
||||||
cast(
|
cast(
|
||||||
ST_Distance_Sphere(
|
ST_Distance_Sphere(
|
||||||
Point(longitude, latitude), Point(#{params.longitude}, #{params.latitude})
|
Point(longitude, latitude), Point(#{longitude}, #{latitude})
|
||||||
) AS
|
) AS
|
||||||
DECIMAL(10, 2)
|
DECIMAL(10, 2)
|
||||||
), 0
|
), 0
|
||||||
) AS distance
|
) AS distance
|
||||||
from scenic s
|
from scenic s
|
||||||
where `status` = 1
|
where `status` = 1
|
||||||
|
and `latitude` is not null
|
||||||
|
and `longitude` is not null
|
||||||
ORDER BY distance ASC
|
ORDER BY distance ASC
|
||||||
</select>
|
</select>
|
||||||
<select id="getConfig" resultType="com.ycwl.basic.model.pc.scenic.entity.ScenicConfigEntity">
|
<select id="getConfig" resultType="com.ycwl.basic.model.pc.scenic.entity.ScenicConfigEntity">
|
||||||
|
@ -312,4 +312,15 @@
|
|||||||
order by r.create_time desc
|
order by r.create_time desc
|
||||||
limit 1
|
limit 1
|
||||||
</select>
|
</select>
|
||||||
|
<select id="listStatByScenic" resultType="com.ycwl.basic.model.mobile.statistic.resp.AppStatisticsFunnelVO">
|
||||||
|
SELECT cs1 AS cameraShotOfMemberNum, v1 AS totalVisitorOfMemberNum, sv1 AS scanCodeVisitorOfMemberNum, u1 AS uploadFaceOfMemberNum, m1 AS pushOfMemberNum, gv1 AS completeVideoOfMemberNum, gv2 AS completeOfVideoNum, pv1 AS previewVideoOfMemberNum, pv2 AS previewOfVideoNum, cp1 AS clickOnPayOfMemberNum, o1 AS payOfMemberNum, o2 AS payOfOrderNum, o3 AS payOfOrderAmount, ro2 AS refundOfOrderNum, ro3 AS refundOfOrderAmount
|
||||||
|
FROM scenic_stats
|
||||||
|
WHERE scenic_id = #{scenicId}
|
||||||
|
AND date BETWEEN #{startTime} AND #{endTime}
|
||||||
|
</select>
|
||||||
|
<insert id="insertStat">
|
||||||
|
REPLACE INTO scenic_stats (scenic_id, date, cs1, v1, sv1, u1, m1, gv1, gv2, pv1, pv2, cp1, o1, o2, o3, ro2, ro3)
|
||||||
|
VALUES (#{scenicId}, #{date}, #{data.cameraShotOfMemberNum}, #{data.totalVisitorOfMemberNum}, #{data.scanCodeVisitorOfMemberNum}, #{data.uploadFaceOfMemberNum}, #{data.pushOfMemberNum}, #{data.completeVideoOfMemberNum}, #{data.completeOfVideoNum}, #{data.previewVideoOfMemberNum}, #{data.previewOfVideoNum}, #{data.clickOnPayOfMemberNum}, #{data.payOfMemberNum}, #{data.payOfOrderNum}, #{data.payOfOrderAmount}, #{data.refundOfOrderNum}, #{data.refundOfOrderAmount})
|
||||||
|
</insert>
|
||||||
|
|
||||||
</mapper>
|
</mapper>
|
@ -1,24 +0,0 @@
|
|||||||
package com.ycwl.basic.task;
|
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.junit.Test;
|
|
||||||
import org.junit.runner.RunWith;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.boot.test.context.SpringBootTest;
|
|
||||||
import org.springframework.test.context.junit4.SpringRunner;
|
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.*;
|
|
||||||
|
|
||||||
|
|
||||||
@Slf4j
|
|
||||||
@SpringBootTest
|
|
||||||
@RunWith(SpringRunner.class)
|
|
||||||
public class ScenicDeviceStatsTaskTest {
|
|
||||||
@Autowired
|
|
||||||
private ScenicDeviceStatsTask task;
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testA() {
|
|
||||||
task.countDeviceStats();
|
|
||||||
}
|
|
||||||
}
|
|
60
src/test/java/com/ycwl/basic/task/ScenicStatsTaskTest.java
Normal file
60
src/test/java/com/ycwl/basic/task/ScenicStatsTaskTest.java
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
package com.ycwl.basic.task;
|
||||||
|
|
||||||
|
import cn.hutool.core.date.DateUtil;
|
||||||
|
import com.ycwl.basic.mapper.ScenicMapper;
|
||||||
|
import com.ycwl.basic.mapper.StatisticsMapper;
|
||||||
|
import com.ycwl.basic.model.mobile.statistic.req.CommonQueryReq;
|
||||||
|
import com.ycwl.basic.model.mobile.statistic.resp.AppStatisticsFunnelVO;
|
||||||
|
import com.ycwl.basic.model.pc.scenic.req.ScenicReqQuery;
|
||||||
|
import com.ycwl.basic.model.pc.scenic.resp.ScenicRespVO;
|
||||||
|
import com.ycwl.basic.service.mobile.AppStatisticsService;
|
||||||
|
import com.ycwl.basic.utils.ApiResponse;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
|
import org.springframework.test.context.junit4.SpringRunner;
|
||||||
|
|
||||||
|
import java.util.Calendar;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@SpringBootTest
|
||||||
|
@RunWith(SpringRunner.class)
|
||||||
|
public class ScenicStatsTaskTest {
|
||||||
|
@Autowired
|
||||||
|
private ScenicStatsTask task;
|
||||||
|
@Autowired
|
||||||
|
private ScenicMapper scenicMapper;
|
||||||
|
@Autowired
|
||||||
|
private AppStatisticsService statisticsService;
|
||||||
|
@Autowired
|
||||||
|
private StatisticsMapper statisticsMapper;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testA() {
|
||||||
|
task.countDeviceStats();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testB() {
|
||||||
|
Calendar calendar = Calendar.getInstance();
|
||||||
|
calendar.set(2025, Calendar.MAY, 1);
|
||||||
|
List<ScenicRespVO> list = scenicMapper.list(new ScenicReqQuery());
|
||||||
|
while (calendar.getTime().getTime() < System.currentTimeMillis()) {
|
||||||
|
System.out.println(calendar.getTime());
|
||||||
|
list.forEach((scenic) -> {
|
||||||
|
CommonQueryReq query = new CommonQueryReq();
|
||||||
|
query.setScenicId(scenic.getId());
|
||||||
|
query.setStartTime(DateUtil.beginOfDay(calendar.getTime()));
|
||||||
|
query.setEndTime(DateUtil.endOfDay(calendar.getTime()));
|
||||||
|
ApiResponse<AppStatisticsFunnelVO> resp = statisticsService.userConversionFunnel(query);
|
||||||
|
AppStatisticsFunnelVO data = resp.getData();
|
||||||
|
statisticsMapper.insertStat(scenic.getId(), DateUtil.beginOfDay(calendar.getTime()), data);
|
||||||
|
});
|
||||||
|
calendar.add(Calendar.DAY_OF_MONTH, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user