瀏覽代碼

快手-盯盘-组实时数据

yangzian 3 年之前
父節點
當前提交
53274c96da

+ 10 - 0
jeecg-boot-material-view/src/main/java/org/jeecg/ctop/material/controller/KuaiShouMaterialStareController.java

@@ -282,6 +282,16 @@ public class KuaiShouMaterialStareController {
     }
 
 
+    @GetMapping("/realTime/getUnitDateInfo")
+    public Result<JSONObject> kuaiShouOperateDateTotalPersonal(@RequestParam(name="accountId") long accountId,
+                                                               @RequestParam(name="pageNum") Integer pageNum,
+                                                               @RequestParam(name="pageSize") Integer pageSize) {
+
+        return materialStareService.kuaiShouRealTimeUnitDateInfo(accountId, pageNum, pageSize);
+    }
+
+
+
 
     /**
      * 获取用户下级的项目以及账户信息

+ 3 - 0
jeecg-boot-material-view/src/main/java/org/jeecg/ctop/material/mapper/MaterialStareMapper.java

@@ -75,6 +75,9 @@ public interface MaterialStareMapper {
     //快手 账户饼图图-分性别
     List<KuaiShouAccountPieVo> getKuaiShouAccountPieGender(@Param("accountId")Long accountId, @Param("startDate")Long startDate, @Param("endDate")Long endDate,@Param("type")String type);
 
+    //快手组实时数据查询-当天创建的组+当天有消耗的组
+    List<JSONObject> kuaiShouRealTimeUnitDateInfo(@Param("accountId")Long accountId, @Param("nowDate")Long nowDate);
+
 
     //快手 账户 框返 激励 消耗
     JSONObject getKuaiShouAccountCharged(@Param("startDate")Long startDate, @Param("endDate")Long endDate,@Param("list")Set<String> operatorUserIds);

+ 73 - 0
jeecg-boot-material-view/src/main/java/org/jeecg/ctop/material/mapper/xml/MaterialStareMapper.xml

@@ -963,6 +963,79 @@
     </select>
 
 
+    <!-- 快手组实时数据查询-当天创建的组+当天有消耗的组 -->
+    <select id="kuaiShouRealTimeUnitDateInfo" resultType="com.alibaba.fastjson.JSONObject">
+
+    SELECT t.*,
+           l.bid_type bidType,
+           l.bid,
+           l.cpa_bid cpaBid,
+           l.put_status putStatus
+    from (
+        SELECT IFNULL(a.advertiser_id,b.dAccountId) accountId,
+               IFNULL(a.uid,b.dunit_id) unit_id,
+                a.*,b.*
+        from (
+            SELECT
+            ad.advertiser_id as advertiser_id,
+            ad.unit_id uid,
+            ad.ocpx_action_type
+            FROM
+            media_api.kuaishou_ad_unit_list ad
+            WHERE
+            ad.advertiser_id = #{accountId}
+            AND DATE_FORMAT( ad.create_time, "%Y%m%d" ) = #{nowDate}
+            ) a RIGHT JOIN
+            (
+            SELECT
+            d.advertiser_id dAccountId,
+            d.campaign_id campaignId,
+            d.campaign_name campaignName,
+            d.unit_id dunit_id,
+            d.unit_name unitName,
+            IFNULL( SUM( d.charge ), 0 ) AS charge,
+            IFNULL( SUM( d.activation ), 0 ) AS activation,
+            IFNULL( ROUND( SUM( d.charge ) / SUM( d.activation ), 2 ), 0 ) AS activationPrice,
+            IFNULL( ROUND( SUM( d.charge ) / SUM( d.activation ), 2 ), 0 ) AS activationCost,
+            IF(SUM( d.event_next_day_stay ) / SUM( d.activation ) > 0.0001,CONCAT( ROUND( SUM( d.event_next_day_stay ) / SUM( d.activation ) * 100, 2 ), '%' ),0 ) AS `leave`,
+            IFNULL( SUM( d.event_pay ), 0 ) AS eventPay,
+            IFNULL( ROUND( SUM( d.charge ) / SUM( d.event_pay ), 2 ), 0 ) AS eventPayCost,
+            IF(SUM( d.event_pay ) / (SUM( d.activation ) + SUM( d.form_count )) > 0.0001,CONCAT(ROUND( SUM( d.event_pay ) / ( SUM( d.activation ) + SUM( d.form_count )) * 100, 2),'%'),0 ) AS eventPayRate,
+            IFNULL( SUM( d.event_new_user_pay ), 0 ) AS eventNewUserPay,
+            IFNULL( ROUND( SUM( d.charge ) / SUM( d.event_new_user_pay ), 2 ), 0 ) AS eventNewUserPayCost,
+            IFNULL( ROUND( SUM( d.event_new_user_pay ) / ( SUM( d.activation ) + SUM( d.form_count )), 2 ), 0 ) AS eventNewUserPayRate,
+            IFNULL( SUM( d.event_app_invoked ), 0 ) AS eventAppInvoked,
+            IFNULL( ROUND( SUM( d.charge ) / SUM( d.event_app_invoked ), 2 ), 0 ) AS eventAppInvokedCost,
+            IFNULL( SUM( d.event_register ), 0 ) AS eventRegister,
+            IFNULL( ROUND( SUM( d.charge ) / SUM( d.event_register ), 2 ), 0 ) AS eventRegisterCost,
+            IFNULL( SUM( d.key_action ), 0 ) AS keyAction,
+            IFNULL( ROUND( SUM( d.charge ) / SUM( d.key_action ), 2 ), 0 ) AS keyActionCost,
+            IF(SUM( d.key_action )/ SUM( d.activation ) > 0.0001,CONCAT( ROUND( SUM( d.key_action )/ SUM( d.activation ) * 100, 2 ), '%' ),0) AS keyActionRate,
+            IFNULL( SUM( d.event_pay_purchase_amount_first_day ), 0 ) AS eventPayPurchaseAmountFirstDay,
+            IFNULL( SUM( d.event_pay_first_day_roi ), 0 ) AS eventPayFirstDayRoi,
+            IFNULL( SUM( d.form_count ), 0 ) AS formCount,
+            IFNULL( ROUND( SUM( d.charge ) / SUM( d.form_count ), 2 ), 0 ) AS formCountPrice,
+            SUM(d.bclick) bClick
+            FROM
+            media_api.kuaishou_unit_report_hourly d
+            WHERE
+            d.advertiser_id = #{accountId}
+            AND d.stat_date = #{nowDate}
+            GROUP BY
+            d.unit_id
+            ) b
+        on a.uid = b.dunit_id
+        ) t
+        LEFT JOIN media_api.kuaishou_ad_unit_list l
+        on l.unit_id = t.unit_id
+        WHERE l.advertiser_id = #{accountId}
+
+
+
+    </select>
+
+
+
 
 
 

+ 3 - 0
jeecg-boot-material-view/src/main/java/org/jeecg/ctop/material/service/MaterialStareService.java

@@ -37,6 +37,9 @@ public interface MaterialStareService {
     Result getKuaiShouAccountPieChar(long accountId,String startTime, String endTime,String type);
 
 
+    Result kuaiShouRealTimeUnitDateInfo(long accountId,Integer pageNum,Integer pageSize);
+
+
     Result getCompanyAllSubordinateByUserId(String userId);
 
 

+ 129 - 0
jeecg-boot-material-view/src/main/java/org/jeecg/ctop/material/service/impl/MaterialStareServiceImpl.java

@@ -19,6 +19,7 @@ import org.jeecg.ctop.material.entity.vo.KuaiShouOperateVo;
 import org.jeecg.ctop.material.mapper.MaterialStareMapper;
 import org.jeecg.ctop.material.service.MaterialStareService;
 import org.jeecg.ctop.material.utils.FeidNotNullUtils;
+import org.jeecg.ctop.material.utils.LinkUtil;
 import org.springframework.stereotype.Service;
 
 import javax.annotation.Resource;
@@ -701,6 +702,134 @@ public class MaterialStareServiceImpl implements MaterialStareService {
         return Result.successMsg("查询饼图数据成功。",resultMap);
     }
 
+    @Override
+    public Result kuaiShouRealTimeUnitDateInfo(long accountId, Integer pageNum, Integer pageSize) {
+
+        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
+        // ==>> 20220202
+        String now = sdf.format(new Date());
+        long nowDate = Long.valueOf(now);
+
+        PageHelper.startPage(pageNum,pageSize);
+        List<JSONObject> ListUnit = materialStareMapper.kuaiShouRealTimeUnitDateInfo(accountId,nowDate);
+        for (JSONObject unitVo : ListUnit) {
+
+            //优化目标
+           Integer conver = Check.isNull(unitVo.getInteger("ocpx_action_type")) ? 0 : unitVo.getInteger("ocpx_action_type");
+
+            //优化目标: 激活,  付费,  行为,  表单提交,  注册,  唤起应用,  关键行为
+            //对应转化数 激活数,付费数,行为数,表单提交数,注册数,唤起应用次数,关键行为数
+            //优化目标id 来源---ctop_kuaishou_ocpx_action_type_config
+            unitVo.put("converNum",0);//默认
+            //激活
+            if (conver == 180) {
+                unitVo.put("converNum",unitVo.getInteger("activation"));
+            }
+            //付费
+            if (conver == 190) {
+                unitVo.put("converNum",unitVo.getInteger("eventPay"));
+            }
+            //行为
+            if (conver == 2) {
+                unitVo.put("converNum",unitVo.getInteger("bClick"));
+            }
+            //表单提交
+            if (conver == 53) {
+                unitVo.put("converNum",unitVo.getInteger("formCount"));
+            }
+            //注册
+            if (conver == 396) {
+                unitVo.put("converNum",unitVo.getInteger("eventRegister"));
+            }
+            //唤起应用
+            if (conver == 324) {
+                unitVo.put("converNum",unitVo.getInteger("eventAppInvoked"));
+            }
+            //关键行为
+            if (conver == 773) {
+                unitVo.put("converNum",unitVo.getInteger("keyAction"));
+            }
+
+            //转化成本 = 花费 / 转化数
+            double converCost = unitVo.getInteger("converNum") == 0 ? 0 : unitVo.getDouble("charge") / unitVo.getInteger("converNum");
+            unitVo.put("converCost",converCost);
+
+
+            //操作建议
+
+            //消耗
+            Double charge = unitVo.getDoubleValue("charge");
+
+            //出价 单位:厘
+            long bid = new Long("1000");
+            //2:CPC
+            if (unitVo.getInteger("bidType") == 2){
+                bid = unitVo.getLong("bid");
+            //10:OCPM
+            }else if(unitVo.getInteger("bidType") == 10){
+                bid = unitVo.getLong("cpaBid");
+            }
+            Double price = new Double(bid/1000).doubleValue();
+
+            //转化数量
+            Integer converNum = unitVo.getInteger("converNum");
+
+            unitVo.put("operationAgree","暂无");
+            unitVo.put("operationContent","暂无");
+            unitVo.put("operationAgreeInfo","暂无");
+
+            //1. 转化成本大于出价×120%,消耗大于500元:
+            if ((converCost > price * 1.2) && (charge > 500)) {
+                unitVo.put("operationAgree","高成本 | 有消耗");
+                unitVo.put("operationContent","建议限制预算");
+                unitVo.put("operationAgreeInfo","当前广告组转化成本偏高且消耗大于500,建议限制预算;");
+            }
+            //2.  转化成本大于出价×120%,转化数大于10小于等于50:
+            if (converCost > price * 1.2 && LinkUtil.isInTheInterval(String.valueOf(converNum), "(10,50)")) {
+
+                unitVo.put("operationAgree","高成本 | 有转化");
+                unitVo.put("operationContent","建议限制预算");
+                unitVo.put("operationAgreeInfo","当前广告组成本大于出价×120%且转化数介于10-50之间;");
+            }
+            //3. 转化成本大于出价×120%,转化数大于50
+            if (converCost > price * 1.2 && LinkUtil.isInTheInterval(String.valueOf(converNum), "(50,∞)")) {
+                unitVo.put("operationAgree","高成本 | 有转化");
+                unitVo.put("operationContent","建议降低出价");
+                unitVo.put("operationAgreeInfo","当前转化成本大于出价×120%,转化数大于50,建议降低出价;");
+            }
+            //4.  转化成本小于等于出价×120%,转化数大于10小于等于50
+            if (converCost <= price * 1.2 && LinkUtil.isInTheInterval(String.valueOf(converNum), "(10,50]")) {
+                unitVo.put("operationAgree","成本合理 | 有转化");
+                unitVo.put("operationContent","建议复制推广组或放开预算");
+                unitVo.put("operationAgreeInfo","当前转化成本小于等于出价×120%,转化数大于10小于等于50,建议复制推广组或放开预算;");
+            }
+            //5.  消耗大于0小于等于100,转化数大于0小于等于10:
+            if (LinkUtil.isInTheInterval(String.valueOf(charge), "(0,100]") && LinkUtil.isInTheInterval(String.valueOf(converNum), "(0,10]")) {
+                unitVo.put("operationAgree","消耗少 | 转化少");
+                unitVo.put("operationContent","建议启用加速探索");
+                unitVo.put("operationAgreeInfo","当前广告组消耗大于0小于等于100,转化数大于0小于等于10,建议加速探索;");
+            }
+            //6.  消耗大于等于500,转化数等于0:
+            if (charge >= 500 && converNum == 0) {
+                unitVo.put("operationAgree","有消耗 | 无转化");
+                unitVo.put("operationContent","建议暂停广告组");
+                unitVo.put("operationAgreeInfo","当前广告组消耗大于等于500且转化数等于0,建议暂停推广组;");
+            }
+            //7.   消耗大于100小于等于500
+            if (LinkUtil.isInTheInterval(String.valueOf(charge), "(100,500]")) {
+                unitVo.put("operationAgree","有一定消耗");
+                unitVo.put("operationContent","建议继续观察");
+                unitVo.put("operationAgreeInfo","当前广告组消耗大于100小于等于500,建议继续观察;");
+            }
+        }
+
+
+
+        PageInfo<JSONObject> pageInfo = new PageInfo<>(ListUnit);
+        return Result.successMsg("查询快手组当天实时数据成功。",pageInfo);
+
+    }
+
 
 //===========================================查询下级员工========================
 

+ 129 - 0
jeecg-boot-material-view/src/main/java/org/jeecg/ctop/material/utils/LinkUtil.java

@@ -0,0 +1,129 @@
+package org.jeecg.ctop.material.utils;
+
+import javax.script.ScriptEngine;
+import javax.script.ScriptEngineManager;
+
+/**
+ * zian Y
+ * 2022/3/24
+ **/
+public class LinkUtil {
+
+
+
+    /**
+     * 判断data_value是否在interval区间范围内
+     * @param data_value 数值类型的
+     * @param interval 正常的数学区间,包括无穷大等,如:(1,3)、>5%、(-∞,6]、(125%,135%)U(70%,80%)
+     * @return true:表示data_value在区间interval范围内,false:表示data_value不在区间interval范围内
+     */
+    public static boolean isInTheInterval(String data_value,String interval) {
+        //将区间和data_value转化为可计算的表达式
+        String formula = getFormulaByAllInterval(data_value,interval,"||");
+        ScriptEngine jse = new ScriptEngineManager().getEngineByName("JavaScript");
+        try {
+            //计算表达式
+            return (Boolean) jse.eval(formula);
+        } catch (Exception t) {
+            return false;
+        }
+    }
+
+
+
+    /**
+     * 将所有阀值区间转化为公式:如
+     * [75,80) =》 date_value < 80 && date_value >= 75
+     * (125%,135%)U(70%,80%) =》 (date_value < 1.35 && date_value > 1.25) || (date_value < 0.8 && date_value > 0.7)
+     * @param date_value
+     * @param interval 形式如:(125%,135%)U(70%,80%)
+     * @param connector 连接符 如:") || ("
+     */
+    private static String getFormulaByAllInterval(String date_value, String interval, String connector) {
+        StringBuffer buff = new StringBuffer();
+        for(String limit:interval.split("U")){//如:(125%,135%)U (70%,80%)
+            buff.append("(").append(getFormulaByInterval(date_value, limit," && ")).append(")").append(connector);
+        }
+        String allLimitInvel = buff.toString();
+        int index = allLimitInvel.lastIndexOf(connector);
+        allLimitInvel = allLimitInvel.substring(0,index);
+        return allLimitInvel;
+    }
+
+    /**
+     * 将整个阀值区间转化为公式:如
+     * 145) =》 date_value < 145
+     * [75,80) =》 date_value < 80 && date_value >= 75
+     * @param date_value
+     * @param interval 形式如:145)、[75,80)
+     * @param connector 连接符 如:&&
+     */
+    private static String getFormulaByInterval(String date_value, String interval, String connector) {
+        StringBuffer buff = new StringBuffer();
+        for(String halfInterval:interval.split(",")){//如:[75,80)、≥80
+            buff.append(getFormulaByHalfInterval(halfInterval, date_value)).append(connector);
+        }
+        String limitInvel = buff.toString();
+        int index = limitInvel.lastIndexOf(connector);
+        limitInvel = limitInvel.substring(0,index);
+        return limitInvel;
+    }
+
+
+    /**
+     * 将半个阀值区间转化为公式:如
+     * 145) =》 date_value < 145
+     * ≥80% =》 date_value >= 0.8
+     * [130 =》 date_value >= 130
+     * <80% =》 date_value < 0.8
+     * @param halfInterval 形式如:145)、≥80%、[130、<80%
+     * @param date_value
+     * @return date_value < 145
+     */
+    private static String getFormulaByHalfInterval(String halfInterval, String date_value) {
+        halfInterval = halfInterval.trim();
+        if(halfInterval.contains("∞")){//包含无穷大则不需要公式
+            return "1 == 1";
+        }
+        StringBuffer formula = new StringBuffer();
+        String data = "";
+        String opera = "";
+        if(halfInterval.matches("^([<>≤≥\\[\\(]{1}(-?\\d+.?\\d*\\%?))$")){//表示判断方向(如>)在前面 如:≥80%
+            opera = halfInterval.substring(0,1);
+            data = halfInterval.substring(1);
+        }else{//[130、145)
+            opera = halfInterval.substring(halfInterval.length()-1);
+            data = halfInterval.substring(0,halfInterval.length()-1);
+        }
+        double value = dealPercent(data);
+        formula.append(date_value).append(" ").append(opera).append(" ").append(value);
+        String a = formula.toString();
+        //转化特定字符
+        return a.replace("[", ">=").replace("(", ">").replace("]", "<=").replace(")", "<").replace("≤", "<=").replace("≥", ">=");
+    }
+
+
+    /**
+     * 去除百分号,转为小数
+     * @param str 可能含百分号的数字
+     * @return
+     */
+    private static double dealPercent(String str){
+        double d = 0.0;
+        if(str.contains("%")){
+            str = str.substring(0,str.length()-1);
+            d = Double.parseDouble(str)/100;
+        }else{
+            d = Double.parseDouble(str);
+        }
+        return d;
+    }
+
+
+    public static void main(String[] args) {
+
+        System.out.println(LinkUtil.isInTheInterval("7", "(-1,9]"));
+    }
+
+
+}