|
@@ -1,19 +1,36 @@
|
|
package cn.com.ctop.kuaishou.modules.batch.controller;
|
|
package cn.com.ctop.kuaishou.modules.batch.controller;
|
|
|
|
|
|
import cn.com.ctop.common.module.entity.CtopOauthToken;
|
|
import cn.com.ctop.common.module.entity.CtopOauthToken;
|
|
|
|
+import cn.com.ctop.common.module.entity.UserAllocation;
|
|
|
|
+import cn.com.ctop.common.module.material.entity.MaterialVideoAuthor;
|
|
import cn.com.ctop.common.module.service.ICtopOauthTokenService;
|
|
import cn.com.ctop.common.module.service.ICtopOauthTokenService;
|
|
import cn.com.ctop.common.module.utils.Check;
|
|
import cn.com.ctop.common.module.utils.Check;
|
|
|
|
+import cn.com.ctop.kuaishou.modules.batch.service.IKuaishouInterfaceService;
|
|
import cn.com.ctop.kuaishou.modules.batch.service.IKuaishouRealTimeDataService;
|
|
import cn.com.ctop.kuaishou.modules.batch.service.IKuaishouRealTimeDataService;
|
|
|
|
+import cn.com.ctop.kuaishou.modules.report.entity.KuaishouReportHourlyGroup;
|
|
|
|
+import cn.com.ctop.kuaishou.modules.report.service.IKuaishouReportHourlyGroupService;
|
|
|
|
+import cn.com.ctop.kuaishou.modules.utils.LinkUtils;
|
|
import com.alibaba.fastjson.JSONArray;
|
|
import com.alibaba.fastjson.JSONArray;
|
|
import com.alibaba.fastjson.JSONObject;
|
|
import com.alibaba.fastjson.JSONObject;
|
|
|
|
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
|
|
|
+import com.baomidou.mybatisplus.core.metadata.IPage;
|
|
|
|
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
|
|
|
+import com.google.gson.JsonObject;
|
|
import io.swagger.annotations.Api;
|
|
import io.swagger.annotations.Api;
|
|
import lombok.extern.slf4j.Slf4j;
|
|
import lombok.extern.slf4j.Slf4j;
|
|
|
|
+import org.checkerframework.checker.units.qual.A;
|
|
import org.jeecg.common.api.vo.Result;
|
|
import org.jeecg.common.api.vo.Result;
|
|
|
|
+import org.jeecg.common.util.DateUtils;
|
|
import org.springframework.beans.factory.annotation.Autowired;
|
|
import org.springframework.beans.factory.annotation.Autowired;
|
|
-import org.springframework.web.bind.annotation.PostMapping;
|
|
|
|
-import org.springframework.web.bind.annotation.RequestBody;
|
|
|
|
-import org.springframework.web.bind.annotation.RequestMapping;
|
|
|
|
-import org.springframework.web.bind.annotation.RestController;
|
|
|
|
|
|
+import org.springframework.web.bind.annotation.*;
|
|
|
|
+
|
|
|
|
+import java.lang.reflect.Field;
|
|
|
|
+import java.math.BigDecimal;
|
|
|
|
+import java.text.DecimalFormat;
|
|
|
|
+import java.util.ArrayList;
|
|
|
|
+import java.util.Date;
|
|
|
|
+import java.util.List;
|
|
|
|
+import java.util.Map;
|
|
|
|
|
|
/**
|
|
/**
|
|
* @Description: 广告组-app信息
|
|
* @Description: 广告组-app信息
|
|
@@ -30,7 +47,24 @@ public class KuaiShouRealTimeController {
|
|
@Autowired
|
|
@Autowired
|
|
private ICtopOauthTokenService oauthTokenService;
|
|
private ICtopOauthTokenService oauthTokenService;
|
|
|
|
|
|
|
|
+ @Autowired
|
|
|
|
+ private ICtopOauthTokenService tokenService;
|
|
|
|
+
|
|
|
|
+ @Autowired
|
|
|
|
+ IKuaishouReportHourlyGroupService kuaishouReportHourlyGroupService;
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ @Autowired
|
|
|
|
+ IKuaishouInterfaceService kuaishouInterfaceService;
|
|
|
|
+
|
|
|
|
+
|
|
|
|
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 快手- 获取实时数据 计划
|
|
|
|
+ * @param requestJson
|
|
|
|
+ * @return
|
|
|
|
+ */
|
|
@PostMapping(value = "/getCampaignDate")
|
|
@PostMapping(value = "/getCampaignDate")
|
|
public Result<JSONArray> getCampaignDate(@RequestBody JSONObject requestJson) {
|
|
public Result<JSONArray> getCampaignDate(@RequestBody JSONObject requestJson) {
|
|
Result<JSONArray> result = new Result<>();
|
|
Result<JSONArray> result = new Result<>();
|
|
@@ -64,6 +98,13 @@ public class KuaiShouRealTimeController {
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 快手- 获取实时数据 组
|
|
|
|
+ * @param requestJson
|
|
|
|
+ * @return
|
|
|
|
+ */
|
|
@PostMapping(value = "/getUnitDate")
|
|
@PostMapping(value = "/getUnitDate")
|
|
public Result<JSONArray> getUnitDate(@RequestBody JSONObject requestJson) {
|
|
public Result<JSONArray> getUnitDate(@RequestBody JSONObject requestJson) {
|
|
Result<JSONArray> result = new Result<>();
|
|
Result<JSONArray> result = new Result<>();
|
|
@@ -77,9 +118,9 @@ public class KuaiShouRealTimeController {
|
|
throw new Exception("未获取到账户信息");
|
|
throw new Exception("未获取到账户信息");
|
|
}
|
|
}
|
|
Long unitId = requestJson.getLong("unitId");
|
|
Long unitId = requestJson.getLong("unitId");
|
|
- if (Check.isNull(unitId)) {
|
|
|
|
|
|
+ /*if (Check.isNull(unitId)) {
|
|
throw new Exception("请传入组id");
|
|
throw new Exception("请传入组id");
|
|
- }
|
|
|
|
|
|
+ }*/
|
|
String startDate = requestJson.getString("startDate");
|
|
String startDate = requestJson.getString("startDate");
|
|
String endDate = requestJson.getString("endDate");
|
|
String endDate = requestJson.getString("endDate");
|
|
if (Check.isNull(startDate) || Check.isNull(endDate)) {
|
|
if (Check.isNull(startDate) || Check.isNull(endDate)) {
|
|
@@ -96,4 +137,233 @@ public class KuaiShouRealTimeController {
|
|
return result;
|
|
return result;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 盯盘-快手 组实时数据信息
|
|
|
|
+ * @param accountId
|
|
|
|
+ * @param pageNum
|
|
|
|
+ * @param pageSize
|
|
|
|
+ * @return
|
|
|
|
+ */
|
|
|
|
+ @GetMapping(value = "/getUnitDateInfo")
|
|
|
|
+ public Result getUnitDate(@RequestParam("accountId") Long accountId,
|
|
|
|
+ @RequestParam(value = "pageNum",defaultValue = "1") Integer pageNum,
|
|
|
|
+ @RequestParam(value = "pageSize",defaultValue = "10") Integer pageSize) {
|
|
|
|
+
|
|
|
|
+ DecimalFormat df = new DecimalFormat("#.000");
|
|
|
|
+
|
|
|
|
+ String nowDate = DateUtils.getNowDate("yyyy-MM-dd");
|
|
|
|
+ CtopOauthToken token = tokenService.getTokenByAccountId(accountId);
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ List<KuaishouReportHourlyGroup> unitList = new ArrayList<>();
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ //优化目标
|
|
|
|
+ Integer conver = 0;
|
|
|
|
+ //获取广告组的出价
|
|
|
|
+ Map unitPrice = kuaishouInterfaceService.getKuaishouUnitList(token, null,new Date(), new Date() , 1,pageNum,pageSize);
|
|
|
|
+
|
|
|
|
+ JSONArray array = JSONArray.parseArray(unitPrice.get("details").toString());
|
|
|
|
+
|
|
|
|
+ for (Object obj : array) {
|
|
|
|
+
|
|
|
|
+ KuaishouReportHourlyGroup unitInfo = new KuaishouReportHourlyGroup();
|
|
|
|
+ //获取组id
|
|
|
|
+ List<Long> unitIdList = new ArrayList<>();
|
|
|
|
+ JSONObject vo = JSONObject.parseObject(obj.toString());
|
|
|
|
+ unitIdList.add(vo.getLong("unit_id"));
|
|
|
|
+
|
|
|
|
+ //广告主 当天 实时 组 数据信息
|
|
|
|
+ JSONArray unitData = realTimeDataService.getUnitDatePage(accountId, unitIdList, token.getAccessToken(), nowDate, nowDate, pageNum, pageSize);
|
|
|
|
+ List<KuaishouReportHourlyGroup> k = JSONArray.parseArray(unitData.toString(),KuaishouReportHourlyGroup.class);
|
|
|
|
+ if (!Check.isNull(k)){
|
|
|
|
+ unitInfo = k.get(0);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ unitInfo.setTotalCount(Integer.valueOf(unitPrice.get("totalCount").toString()));
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ unitInfo.setUnitName(vo.getString("unit_name"));
|
|
|
|
+
|
|
|
|
+ //出价
|
|
|
|
+ unitInfo.setBid(vo.getLong("bid"));
|
|
|
|
+ unitInfo.setCpaBid(vo.getLong("cpa_bid"));
|
|
|
|
+ unitInfo.setBidType(vo.getInteger("bid_type"));
|
|
|
|
+ //优化目标
|
|
|
|
+ conver = vo.getInteger("ocpx_action_type");
|
|
|
|
+ unitInfo.setConverType(conver);
|
|
|
|
+ //计划id
|
|
|
|
+ unitInfo.setCampaignId(vo.getLong("campaign_id"));
|
|
|
|
+ //组id
|
|
|
|
+ unitInfo.setUnitId(vo.getLong("unit_id"));
|
|
|
|
+ unitInfo.setUnitName(vo.getString("unit_name"));
|
|
|
|
+
|
|
|
|
+ //投放状态 1:投放中;2:暂停 3:删除
|
|
|
|
+ unitInfo.setPutStatus(vo.getInteger("put_status"));
|
|
|
|
+
|
|
|
|
+ //激活成本 = 花费 / 激活数
|
|
|
|
+ String activationCost = "0";
|
|
|
|
+
|
|
|
|
+ if (!Check.isNull(k)){
|
|
|
|
+ if (unitInfo.getCharge().doubleValue() != new Double(0) && unitInfo.getActivation() != 0l) {
|
|
|
|
+ Double activation_cost = unitInfo.getCharge().doubleValue() / unitInfo.getActivation();
|
|
|
|
+ activationCost = df.format(activation_cost);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ unitInfo.setActivationCost(activationCost);
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ //优化目标: 激活, 付费, 行为, 表单提交, 注册, 唤起应用, 关键行为
|
|
|
|
+ //对应转化数 激活数,付费数,行为数,表单提交数,注册数,唤起应用次数,关键行为数
|
|
|
|
+ //优化目标id 来源---ctop_kuaishou_ocpx_action_type_config
|
|
|
|
+ //激活
|
|
|
|
+ if (conver == 180) {
|
|
|
|
+ unitInfo.setConverNum(unitInfo.getActivation().intValue());
|
|
|
|
+ }
|
|
|
|
+ //付费
|
|
|
|
+ if (conver == 190) {
|
|
|
|
+ unitInfo.setConverNum(unitInfo.getEventPay().intValue());
|
|
|
|
+ }
|
|
|
|
+ //行为
|
|
|
|
+ if (conver == 2) {
|
|
|
|
+ unitInfo.setConverNum(unitInfo.getBclick().intValue());
|
|
|
|
+ }
|
|
|
|
+ //表单提交
|
|
|
|
+ if (conver == 53) {
|
|
|
|
+ unitInfo.setConverNum(unitInfo.getFormCount().intValue());
|
|
|
|
+ }
|
|
|
|
+ //注册
|
|
|
|
+ if (conver == 396) {
|
|
|
|
+ unitInfo.setConverNum(unitInfo.getEventRegister().intValue());
|
|
|
|
+ }
|
|
|
|
+ //唤起应用
|
|
|
|
+ if (conver == 324) {
|
|
|
|
+ unitInfo.setConverNum(unitInfo.getEventAppInvoked().intValue());
|
|
|
|
+ }
|
|
|
|
+ //关键行为
|
|
|
|
+ if (conver == 773) {
|
|
|
|
+ unitInfo.setConverNum(unitInfo.getKeyAction().intValue());
|
|
|
|
+ }
|
|
|
|
+ //转化成本 = 花费 / 转化数
|
|
|
|
+ unitInfo.setConverCost(Check.isNull(unitInfo.getCharge()) || Check.isNull(unitInfo.getConverNum()) ? 0 : unitInfo.getCharge().doubleValue() / unitInfo.getConverNum().doubleValue());
|
|
|
|
+ if (unitInfo.getConverCost().isNaN() || unitInfo.getConverCost().isInfinite()) {
|
|
|
|
+ unitInfo.setConverCost(new Double(0));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ //操作建议
|
|
|
|
+ //消耗
|
|
|
|
+ Double charge = unitInfo.getCharge().doubleValue();
|
|
|
|
+ //出价 单位:厘
|
|
|
|
+ long bid = new Long("1000");
|
|
|
|
+ //2:CPC
|
|
|
|
+ if (unitInfo.getBidType() == 2){
|
|
|
|
+ bid = unitInfo.getBid();
|
|
|
|
+ //10:OCPM
|
|
|
|
+ }else if(unitInfo.getBidType() == 10){
|
|
|
|
+ bid = unitInfo.getCpaBid();
|
|
|
|
+ }
|
|
|
|
+ Double price = new Double(bid/1000).doubleValue();
|
|
|
|
+
|
|
|
|
+ //转化数量
|
|
|
|
+ Integer converNum = unitInfo.getConverNum();
|
|
|
|
+ //转化成本
|
|
|
|
+ Double converCost = unitInfo.getConverCost();
|
|
|
|
+
|
|
|
|
+ //1. 转化成本大于出价×120%,消耗大于500元:
|
|
|
|
+ if ((converCost > price * 1.2) && (charge > 500)) {
|
|
|
|
+ unitInfo.setOperationAgree("高成本 | 有消耗");
|
|
|
|
+ unitInfo.setOperationAgreeContent("建议限制预算");
|
|
|
|
+ unitInfo.setOperationAgreeInfo("当前广告组转化成本偏高且消耗大于500,建议限制预算;");
|
|
|
|
+ }
|
|
|
|
+ //2. 转化成本大于出价×120%,转化数大于10小于等于50:
|
|
|
|
+ if (converCost > price * 1.2 && LinkUtils.isInTheInterval(String.valueOf(converNum), "(10,50)")) {
|
|
|
|
+ unitInfo.setOperationAgree("高成本 | 有转化");
|
|
|
|
+ unitInfo.setOperationAgreeContent("建议限制预算");
|
|
|
|
+ unitInfo.setOperationAgreeInfo("当前广告组成本大于出价×120%且转化数介于10-50之间;");
|
|
|
|
+ }
|
|
|
|
+ //3. 转化成本大于出价×120%,转化数大于50
|
|
|
|
+ if (converCost > price * 1.2 && LinkUtils.isInTheInterval(String.valueOf(converNum), "(50,∞)")) {
|
|
|
|
+ unitInfo.setOperationAgree("高成本 | 有转化");
|
|
|
|
+ unitInfo.setOperationAgreeContent("建议降低出价;");
|
|
|
|
+ unitInfo.setOperationAgreeInfo("当前转化成本大于出价×120%,转化数大于50,建议降低出价;");
|
|
|
|
+ }
|
|
|
|
+ //4. 转化成本小于等于出价×120%,转化数大于10小于等于50
|
|
|
|
+ if (converCost <= price * 1.2 && LinkUtils.isInTheInterval(String.valueOf(converNum), "(10,50]")) {
|
|
|
|
+ unitInfo.setOperationAgree("成本合理 | 有转化");
|
|
|
|
+ unitInfo.setOperationAgreeContent("建议复制推广组或放开预算");
|
|
|
|
+ unitInfo.setOperationAgreeInfo("当前转化成本小于等于出价×120%,转化数大于10小于等于50,建议复制推广组或放开预算;");
|
|
|
|
+ }
|
|
|
|
+ //5. 消耗大于0小于等于100,转化数大于0小于等于10:
|
|
|
|
+ if (LinkUtils.isInTheInterval(String.valueOf(charge), "(0,100]") && LinkUtils.isInTheInterval(String.valueOf(converNum), "(0,10]")) {
|
|
|
|
+ unitInfo.setOperationAgree("消耗少 | 转化少");
|
|
|
|
+ unitInfo.setOperationAgreeContent("建议启用加速探索");
|
|
|
|
+ unitInfo.setOperationAgreeInfo("当前广告组消耗大于0小于等于100,转化数大于0小于等于10,建议加速探索;");
|
|
|
|
+ }
|
|
|
|
+ //6. 消耗大于等于500,转化数等于0:
|
|
|
|
+ if (charge >= 500 && converNum == 0) {
|
|
|
|
+ unitInfo.setOperationAgree("有消耗 | 无转化");
|
|
|
|
+ unitInfo.setOperationAgreeContent("建议暂停广告组");
|
|
|
|
+ unitInfo.setOperationAgreeInfo("当前广告组消耗大于等于500且转化数等于0,建议暂停推广组;");
|
|
|
|
+ }
|
|
|
|
+ //7. 消耗大于100小于等于500
|
|
|
|
+ if (LinkUtils.isInTheInterval(String.valueOf(charge), "(100,500]")) {
|
|
|
|
+ unitInfo.setOperationAgree("有一定消耗");
|
|
|
|
+ unitInfo.setOperationAgreeContent("建议继续观察");
|
|
|
|
+ unitInfo.setOperationAgreeInfo("当前广告组消耗大于100小于等于500,建议继续观察;");
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+ unitInfo.setOperationAgree("暂无");
|
|
|
|
+ unitInfo.setOperationAgreeContent("暂无");
|
|
|
|
+ unitInfo.setOperationAgreeInfo("暂无");
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ setFeidValueNotNull(unitInfo);
|
|
|
|
+
|
|
|
|
+ unitList.add(unitInfo);
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+ return Result.ok(unitList);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ private void setFeidValueNotNull (Object obj){
|
|
|
|
+ try {
|
|
|
|
+ for (Field field: obj.getClass().getDeclaredFields()) {
|
|
|
|
+ field.setAccessible(true);
|
|
|
|
+ if (field.get(obj) == null){
|
|
|
|
+ if (field.getGenericType().toString().equals("class java.lang.String")) {
|
|
|
|
+ field.set(obj, "0");
|
|
|
|
+ }else if (field.getGenericType().toString().equals("class java.lang.Integer")) {
|
|
|
|
+ field.set(obj, 0);
|
|
|
|
+ }else if (field.getGenericType().toString().equals("class java.lang.Double")) {
|
|
|
|
+ field.set(obj, 0.0);
|
|
|
|
+ }else if (field.getGenericType().toString().equals("class java.lang.Long")) {
|
|
|
|
+ field.set(obj, 0L);
|
|
|
|
+ }else if(field.getGenericType().toString().equals("class java.math.BigDecimal")){
|
|
|
|
+ field.set(obj, new BigDecimal(0));
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ }catch (Exception e){
|
|
|
|
+ e.printStackTrace();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
}
|
|
}
|