|
@@ -0,0 +1,794 @@
|
|
|
|
+package cn.com.ctop.kuaishou.modules.dimension.service.impl;
|
|
|
|
+
|
|
|
|
+import cn.com.ctop.common.module.entity.CtopOauthToken;
|
|
|
|
+import cn.com.ctop.common.module.service.ICtopOauthTokenService;
|
|
|
|
+import cn.com.ctop.common.module.utils.Check;
|
|
|
|
+import cn.com.ctop.kuaishou.modules.ai.enums.KuaishouCreativeAdsenceTypeEnum;
|
|
|
|
+import cn.com.ctop.kuaishou.modules.batch.entity.KuaiShouAppList;
|
|
|
|
+import cn.com.ctop.kuaishou.modules.batch.entity.KuaiShouVideoGet;
|
|
|
|
+import cn.com.ctop.kuaishou.modules.batch.service.IKuaiShouAppListService;
|
|
|
|
+import cn.com.ctop.kuaishou.modules.batch.service.IKuaiShouVideoGetService;
|
|
|
|
+import cn.com.ctop.kuaishou.modules.batch.service.IKuaishouInterfaceService;
|
|
|
|
+import cn.com.ctop.kuaishou.modules.dimension.entity.*;
|
|
|
|
+import cn.com.ctop.kuaishou.modules.dimension.mapper.KuaiShouDimensionStrategyMapper;
|
|
|
|
+import cn.com.ctop.kuaishou.modules.dimension.service.*;
|
|
|
|
+import com.alibaba.fastjson.JSON;
|
|
|
|
+import com.alibaba.fastjson.JSONArray;
|
|
|
|
+import com.alibaba.fastjson.JSONObject;
|
|
|
|
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
|
|
|
+import com.google.common.collect.Lists;
|
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
|
+import org.jeecg.common.util.DateUtils;
|
|
|
|
+import org.jeecg.common.util.RedisUtil;
|
|
|
|
+import org.springframework.beans.factory.annotation.Autowired;
|
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
|
+
|
|
|
|
+import java.math.BigDecimal;
|
|
|
|
+import java.util.*;
|
|
|
|
+import java.util.concurrent.ExecutorService;
|
|
|
|
+import java.util.concurrent.Executors;
|
|
|
|
+
|
|
|
|
+/**
|
|
|
|
+ * 多维度测试策略表
|
|
|
|
+ *
|
|
|
|
+ * @author jeecg-boot
|
|
|
|
+ * 2021-07-19
|
|
|
|
+ * @version V1.0
|
|
|
|
+ */
|
|
|
|
+@Slf4j
|
|
|
|
+@Service
|
|
|
|
+public class KuaiShouDimensionStrategyServiceImpl extends ServiceImpl<KuaiShouDimensionStrategyMapper, KuaiShouDimensionStrategy> implements IKuaiShouDimensionStrategyService {
|
|
|
|
+
|
|
|
|
+ @Autowired
|
|
|
|
+ private KuaiShouDimensionStrategyMapper dimensionStrategyMapper;
|
|
|
|
+ @Autowired
|
|
|
|
+ private IKuaiShouDimensionAccountService dimensionAccountService;
|
|
|
|
+ @Autowired
|
|
|
|
+ private IKuaiShouDimensionVariableService dimensionVariableService;
|
|
|
|
+ @Autowired
|
|
|
|
+ private ICtopOauthTokenService oauthTokenService;
|
|
|
|
+ @Autowired
|
|
|
|
+ private IKuaishouInterfaceService kuaishouInterfaceService;
|
|
|
|
+ @Autowired
|
|
|
|
+ private IKuaiShouDimensionRegionDetailService dimensionRegionDetailService;
|
|
|
|
+ @Autowired
|
|
|
|
+ private IKuaiShouDimensionUnitService dimensionUnitService;
|
|
|
|
+ @Autowired
|
|
|
|
+ private IKuaiShouAppListService appListService;
|
|
|
|
+ @Autowired
|
|
|
|
+ private IKuaiShouVideoGetService videoGetService;
|
|
|
|
+ @Autowired
|
|
|
|
+ private IKuaiShouDimensionCreativeService dimensionCreativeService;
|
|
|
|
+ @Autowired
|
|
|
|
+ private IKuaiShouDimensionCampaignService dimensionCampaignService;
|
|
|
|
+ @Autowired
|
|
|
|
+ private IKuaiShouDimensionAgeConfigService dimensionAgeConfigService;
|
|
|
|
+
|
|
|
|
+ @Autowired
|
|
|
|
+ private RedisUtil redisUtil;
|
|
|
|
+ private static Map<String, JSONArray> regionMap = new HashMap();
|
|
|
|
+ private static Map<String, String> regionNameMap = new HashMap();
|
|
|
|
+ private static Map<String, JSONArray> ageMap = new HashMap();
|
|
|
|
+ private static Map<String, String> ageNameMap = new HashMap();
|
|
|
|
+ private static String in_use_key = "dimension_in_use_campaign_id_";
|
|
|
|
+ private static String account_count_key = "now_date_account_create_campaign_count_";
|
|
|
|
+ private static String campaign_relation_unit = "campaign_relation_unit_";
|
|
|
|
+ static ExecutorService addUnitService = Executors.newFixedThreadPool(5);
|
|
|
|
+ static ExecutorService addCreativeService = Executors.newFixedThreadPool(5);
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 多维度测试策略信息入库
|
|
|
|
+ *
|
|
|
|
+ * @param strategyJson
|
|
|
|
+ */
|
|
|
|
+ @Override
|
|
|
|
+ public void insertStrategy(String userId, JSONObject strategyJson) {
|
|
|
|
+
|
|
|
|
+ KuaiShouDimensionStrategy dimensionStrategy = new KuaiShouDimensionStrategy();
|
|
|
|
+
|
|
|
|
+ dimensionStrategy.setUserId(userId);
|
|
|
|
+ Long id = strategyJson.getLong("id"); // 主键id
|
|
|
|
+ if (!Check.isNull(id)) {
|
|
|
|
+ dimensionStrategy.setId(id);
|
|
|
|
+ }
|
|
|
|
+ String strategyName = strategyJson.getString("strategyName"); // 策略名称
|
|
|
|
+ if (!Check.isNull(strategyName)) {
|
|
|
|
+ dimensionStrategy.setStrategyName(strategyName);
|
|
|
|
+ }
|
|
|
|
+ Integer strategyStatus = strategyJson.getInteger("strategyStatus"); // 策略状态
|
|
|
|
+ if (!Check.isNull(strategyStatus)) {
|
|
|
|
+ dimensionStrategy.setStrategyStatus(strategyStatus);
|
|
|
|
+ }
|
|
|
|
+ Integer campaignType = strategyJson.getInteger("campaignType"); // 计划类型
|
|
|
|
+ if (!Check.isNull(campaignType)) {
|
|
|
|
+ dimensionStrategy.setCampaignType(campaignType);
|
|
|
|
+ }
|
|
|
|
+ String campaignName = strategyJson.getString("campaignName"); // 计划名称
|
|
|
|
+ if (!Check.isNull(campaignName)) {
|
|
|
|
+ dimensionStrategy.setCampaignName(campaignName);
|
|
|
|
+ }
|
|
|
|
+ Long campaignDayBudget = strategyJson.getLong("campaignDayBudget"); // 计划预算
|
|
|
|
+ if (campaignDayBudget != null) {
|
|
|
|
+ dimensionStrategy.setCampaignDayBudget(campaignDayBudget);
|
|
|
|
+ }
|
|
|
|
+ String unitName = strategyJson.getString("unitName"); // 组名称
|
|
|
|
+ if (!Check.isNull(unitName)) {
|
|
|
|
+ dimensionStrategy.setUnitName(unitName);
|
|
|
|
+ }
|
|
|
|
+ Long unitDayBudget = strategyJson.getLong("unitDayBudget"); // 组预算
|
|
|
|
+ if (unitDayBudget != null) {
|
|
|
|
+ dimensionStrategy.setUnitDayBudget(unitDayBudget);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ Integer network = strategyJson.getInteger("network"); // 网络环境
|
|
|
|
+ if (!Check.isNull(network)) {
|
|
|
|
+ dimensionStrategy.setNetwork(network);
|
|
|
|
+ }
|
|
|
|
+ String fansStar = strategyJson.getString("fansStar"); // 网红粉丝
|
|
|
|
+ if (!Check.isNull(fansStar)) {
|
|
|
|
+ dimensionStrategy.setFansStar(fansStar);
|
|
|
|
+ }
|
|
|
|
+ Integer filterConvertedLevel = strategyJson.getInteger("filterConvertedLevel"); // 过滤转化人群
|
|
|
|
+ if (!Check.isNull(filterConvertedLevel)) {
|
|
|
|
+ dimensionStrategy.setFilterConvertedLevel(filterConvertedLevel);
|
|
|
|
+ }
|
|
|
|
+ String deviceBrand = strategyJson.getString("deviceBrand"); // 设备品牌
|
|
|
|
+ if (!Check.isNull(deviceBrand)) {
|
|
|
|
+ dimensionStrategy.setDeviceBrand(deviceBrand);
|
|
|
|
+ }
|
|
|
|
+ String devicePrice = strategyJson.getString("devicePrice"); // 设备价格
|
|
|
|
+ if (!Check.isNull(devicePrice)) {
|
|
|
|
+ dimensionStrategy.setDevicePrice(devicePrice);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ Integer bidType = strategyJson.getInteger("bidType"); // 优化目标
|
|
|
|
+ if (!Check.isNull(bidType)) {
|
|
|
|
+ dimensionStrategy.setBidType(bidType);
|
|
|
|
+ }
|
|
|
|
+ Integer ocpxActionType = strategyJson.getInteger("ocpxActionType"); // 转化目标
|
|
|
|
+ if (!Check.isNull(ocpxActionType)) {
|
|
|
|
+ dimensionStrategy.setOcpxActionType(ocpxActionType);
|
|
|
|
+ }
|
|
|
|
+ Integer deepConversionType = strategyJson.getInteger("deepConversionType"); // 深度转化目标
|
|
|
|
+ if (Check.isNull(deepConversionType)) {
|
|
|
|
+ dimensionStrategy.setDeepConversionType(deepConversionType);
|
|
|
|
+ }
|
|
|
|
+ Long bid = strategyJson.getLong("bid"); // 出价
|
|
|
|
+ if (!Check.isNull(bid)) {
|
|
|
|
+ dimensionStrategy.setBid(bid);
|
|
|
|
+ }
|
|
|
|
+ String cpaBid = strategyJson.getString("cpaBid"); // cpa_bid出价
|
|
|
|
+ if (!Check.isNull(cpaBid)) {
|
|
|
|
+ dimensionStrategy.setCpaBid(cpaBid);
|
|
|
|
+ }
|
|
|
|
+ Long deepConversionBid = strategyJson.getLong("deepConversionBid"); // 深度转化出价
|
|
|
|
+ if (!Check.isNull(deepConversionBid)) {
|
|
|
|
+ dimensionStrategy.setDeepConversionBid(deepConversionBid);
|
|
|
|
+ }
|
|
|
|
+ JSONArray sceneId = strategyJson.getJSONArray("sceneId"); // 资源位置
|
|
|
|
+ if (!Check.isNull(sceneId)) {
|
|
|
|
+ dimensionStrategy.setSceneId(sceneId.toJSONString());
|
|
|
|
+ }
|
|
|
|
+ JSONArray actionBarText = strategyJson.getJSONArray("actionBarText"); // 行动号召按钮
|
|
|
|
+ if (!Check.isNull(actionBarText)) {
|
|
|
|
+ dimensionStrategy.setActionBarText(actionBarText.toJSONString());
|
|
|
|
+ }
|
|
|
|
+ JSONArray description = strategyJson.getJSONArray("description"); // 广告语
|
|
|
|
+ if (!Check.isNull(description)) {
|
|
|
|
+ dimensionStrategy.setDescription(description.toJSONString());
|
|
|
|
+ }
|
|
|
|
+ Integer unitNum = strategyJson.getInteger("unitNum"); // 计划下组数量
|
|
|
|
+ if (!Check.isNull(unitNum)) {
|
|
|
|
+ dimensionStrategy.setUnitNum(unitNum);
|
|
|
|
+ }
|
|
|
|
+ Integer materialNum = strategyJson.getInteger("materialNum"); // 组下素材量
|
|
|
|
+ if (!Check.isNull(materialNum)) {
|
|
|
|
+ dimensionStrategy.setMaterialNum(materialNum);
|
|
|
|
+ }
|
|
|
|
+ Integer useAppMarket = strategyJson.getInteger("useAppMarket"); // 优先从应用商店下载
|
|
|
|
+ if (!Check.isNull(useAppMarket)) {
|
|
|
|
+ dimensionStrategy.setUseAppMarket(useAppMarket);
|
|
|
|
+ }
|
|
|
|
+ String appStore = strategyJson.getString("appStore"); // 应用商店列表
|
|
|
|
+ if (!Check.isNull(appStore)) {
|
|
|
|
+ dimensionStrategy.setAppStore(appStore);
|
|
|
|
+ }
|
|
|
|
+ Integer unitType = strategyJson.getInteger("unitType"); // 创意制作方式
|
|
|
|
+ if (!Check.isNull(unitType)) {
|
|
|
|
+ dimensionStrategy.setUnitType(unitType);
|
|
|
|
+ }
|
|
|
|
+ Integer showMode = strategyJson.getInteger("showMode"); // 创意展现方式
|
|
|
|
+ if (!Check.isNull(showMode)) {
|
|
|
|
+ dimensionStrategy.setShowMode(showMode);
|
|
|
|
+ }
|
|
|
|
+ Integer speed = strategyJson.getInteger("speed"); // 投放方式
|
|
|
|
+ if (!Check.isNull(speed)) {
|
|
|
|
+ dimensionStrategy.setSpeed(speed);
|
|
|
|
+ }
|
|
|
|
+ if (Check.isNull(id)) {
|
|
|
|
+ int insert = dimensionStrategyMapper.insert(dimensionStrategy);
|
|
|
|
+ if (insert > 0) {
|
|
|
|
+ log.info("素材多维度策略信息入库完成,id:{}", dimensionStrategy.getId());
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ int i = dimensionStrategyMapper.updateById(dimensionStrategy);
|
|
|
|
+ if (i > 0) {
|
|
|
|
+ log.info("素材多维度策略信息修改完成,id:{}", dimensionStrategy.getId());
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ JSONArray appInfoArray = strategyJson.getJSONArray("appInfoArray");
|
|
|
|
+ JSONArray creativeArray = strategyJson.getJSONArray("creativeArray");
|
|
|
|
+ JSONArray crowdArray = strategyJson.getJSONArray("crowdArray");
|
|
|
|
+ if (!Check.isNull(appInfoArray)) {
|
|
|
|
+ dimensionAccountService.insertAccountIds(dimensionStrategy.getId(), appInfoArray, creativeArray, crowdArray);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public JSONObject create(Long id, JSONArray materialArray) {
|
|
|
|
+ JSONObject returnJson = new JSONObject();
|
|
|
|
+ try {
|
|
|
|
+ KuaiShouDimensionStrategy strategy = this.getById(id);
|
|
|
|
+ if (Check.isNull(strategy)) {
|
|
|
|
+ throw new Exception("未获取到策略信息");
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ JSONArray dimensionVariableList = dimensionVariableService.getDimensionVariableList(id); // 获取变量排列组合
|
|
|
|
+ if (Check.isNull(dimensionVariableList)) {
|
|
|
|
+ throw new Exception("变量排列组合信息为空");
|
|
|
|
+ }
|
|
|
|
+ List<KuaiShouDimensionAccount> accountList = dimensionAccountService.getListByStrategyId(id, 0); // 获取在投账户列表
|
|
|
|
+ if (Check.isNull(accountList)) {
|
|
|
|
+ throw new Exception("账户关联账户列表信息为空");
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ String unitName = strategy.getUnitName(); // 组名称
|
|
|
|
+ Long unitDayBudget = strategy.getUnitDayBudget(); // 组预算
|
|
|
|
+ Integer useAppMarket = strategy.getUseAppMarket(); // 优先从应用商店下载
|
|
|
|
+ JSONArray appStore = JSONArray.parseArray(strategy.getAppStore()); // 应用商店
|
|
|
|
+
|
|
|
|
+ Integer network = strategy.getNetwork(); // 网络环境
|
|
|
|
+ JSONArray fansStar = JSONArray.parseArray(strategy.getFansStar()); // 网红粉丝
|
|
|
|
+ Integer filterConvertedLevel = strategy.getFilterConvertedLevel(); // 过滤已转化
|
|
|
|
+ JSONArray deviceBrand = JSONArray.parseArray(strategy.getDeviceBrand()); // 设备品牌
|
|
|
|
+ JSONArray devicePrice = JSONArray.parseArray(strategy.getDevicePrice()); // 设备价格
|
|
|
|
+ Integer bidType = strategy.getBidType(); // 优化目标类型
|
|
|
|
+ Integer ocpxActionType = strategy.getOcpxActionType(); // 转化目标
|
|
|
|
+ Integer deepConversionType = strategy.getDeepConversionType(); // 深度转化目标
|
|
|
|
+ Long bid = strategy.getBid(); // 出价
|
|
|
|
+ String cpaBid = strategy.getCpaBid(); // 转化出价
|
|
|
|
+ Long deepConversionBid = strategy.getDeepConversionBid(); // 深度转化出价
|
|
|
|
+ JSONArray sceneId = JSONArray.parseArray(strategy.getSceneId()); // 资源位置
|
|
|
|
+ JSONArray actionBarText = JSONArray.parseArray(strategy.getActionBarText()); // 行动号召按钮
|
|
|
|
+ JSONArray description = JSONArray.parseArray(strategy.getDescription()); // 广告语
|
|
|
|
+ Integer unitType = strategy.getUnitType(); // 创意制作方式
|
|
|
|
+ Integer speed = strategy.getSpeed(); // 创意制作方式
|
|
|
|
+ Integer showMode = strategy.getShowMode(); // 创意制作方式
|
|
|
|
+ Integer accountIndex = 0;
|
|
|
|
+ Integer actionBarTextIndex = 0;
|
|
|
|
+ Integer descriptionIndex = 0;
|
|
|
|
+ int accountMaxIndex = accountList.size() - 1;
|
|
|
|
+ int actionBarTextMaxIndex = actionBarText.size() - 1;
|
|
|
|
+ int descriptionMaxIndex = description.size() - 1;
|
|
|
|
+ List<List<Object>> materials = Lists.partition(materialArray, strategy.getMaterialNum()); // 将素材切割
|
|
|
|
+ for (int i = 0; i < materials.size(); i++) {
|
|
|
|
+ JSONArray videoArray = JSONArray.parseArray(materials.get(i).toString());
|
|
|
|
+ for (int j = 0; j < dimensionVariableList.size(); j++) {
|
|
|
|
+ JSONObject variableJson = dimensionVariableList.getJSONObject(j);
|
|
|
|
+ if (accountIndex > accountMaxIndex) {
|
|
|
|
+ accountIndex = 0;
|
|
|
|
+ }
|
|
|
|
+ KuaiShouDimensionAccount account = getAccountInfo(accountIndex, accountList);
|
|
|
|
+ accountIndex++;
|
|
|
|
+ if (Check.isNull(account)) {
|
|
|
|
+ continue;
|
|
|
|
+ }
|
|
|
|
+ Long campaignId = getCampaignId(account.getAccountId(), account, strategy);
|
|
|
|
+ if (Check.isNull(campaignId)) {
|
|
|
|
+ continue;
|
|
|
|
+ }
|
|
|
|
+ String countKey = campaign_relation_unit + campaignId;
|
|
|
|
+ Object o = redisUtil.get(countKey);
|
|
|
|
+ Integer count = 0;
|
|
|
|
+ if (!Check.isNull(o)) {
|
|
|
|
+ Integer createCount = Integer.valueOf(o.toString());
|
|
|
|
+ if (createCount >= strategy.getUnitNum()) {
|
|
|
|
+ String inUseKey = in_use_key + account.getAccountId();
|
|
|
|
+ redisUtil.del(inUseKey);
|
|
|
|
+ campaignId = getCampaignId(account.getAccountId(), account, strategy);
|
|
|
|
+ if (Check.isNull(campaignId)) {
|
|
|
|
+ continue;
|
|
|
|
+ }
|
|
|
|
+ countKey = campaign_relation_unit + campaignId;
|
|
|
|
+ } else {
|
|
|
|
+ count = createCount;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ KuaiShouDimensionUnit unit = new KuaiShouDimensionUnit();
|
|
|
|
+ String uuid = getUuid();
|
|
|
|
+ unit.setId(uuid);
|
|
|
|
+ unit.setStrategyId(id);
|
|
|
|
+ unit.setAccountId(account.getAccountId());
|
|
|
|
+ unit.setCampaignId(campaignId);
|
|
|
|
+ String name = getName(unitName, account, strategy);
|
|
|
|
+ unit.setUnitName(name + "_" + count);
|
|
|
|
+ unit.setUnitDayBudget(unitDayBudget);
|
|
|
|
+ unit.setUseAppMarket(useAppMarket);
|
|
|
|
+ if (useAppMarket == 1) {
|
|
|
|
+ if (!Check.isNull(appStore)) {
|
|
|
|
+ unit.setAppStore(appStore.toJSONString());
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ unit.setAppId(account.getAppId());
|
|
|
|
+ if (account.getUseSchemaUri() == 0) {
|
|
|
|
+ unit.setSchemaUri(account.getSchemaUri());
|
|
|
|
+ }
|
|
|
|
+ unit.setShowMode(showMode);
|
|
|
|
+ unit.setSpeed(speed);
|
|
|
|
+ if (!Check.isNull(JSONArray.parseArray(account.getPopulation()))) {
|
|
|
|
+ unit.setPopulation(account.getPopulation());
|
|
|
|
+ }
|
|
|
|
+ if (!Check.isNull(JSONArray.parseArray(account.getExcludePopulation()))) {
|
|
|
|
+ unit.setExcludePopulation(account.getExcludePopulation());
|
|
|
|
+ }
|
|
|
|
+ if (!Check.isNull(JSONArray.parseArray(account.getPaidAudience()))) {
|
|
|
|
+ unit.setPaidAudience(account.getPaidAudience());
|
|
|
|
+ }
|
|
|
|
+ if (!Check.isNull(network)) {
|
|
|
|
+ unit.setNetwork(network);
|
|
|
|
+ }
|
|
|
|
+ if (!Check.isNull(fansStar)) {
|
|
|
|
+ unit.setFansStar(fansStar.toJSONString());
|
|
|
|
+ }
|
|
|
|
+ unit.setFilterConvertedLevel(filterConvertedLevel);
|
|
|
|
+ if (!Check.isNull(deviceBrand)) {
|
|
|
|
+ unit.setDeviceBrand(deviceBrand.toJSONString());
|
|
|
|
+ }
|
|
|
|
+ if (!Check.isNull(devicePrice)) {
|
|
|
|
+ unit.setDevicePrice(devicePrice.toJSONString());
|
|
|
|
+ }
|
|
|
|
+ unit.setUnitType(unitType);
|
|
|
|
+ if (!Check.isNull(bidType)) {
|
|
|
|
+ unit.setBidType(bidType);
|
|
|
|
+ }
|
|
|
|
+ if (!Check.isNull(ocpxActionType)) {
|
|
|
|
+ unit.setOcpxActionType(ocpxActionType);
|
|
|
|
+ }
|
|
|
|
+ if (!Check.isNull(deepConversionType)) {
|
|
|
|
+ unit.setDeepConversionType(deepConversionType);
|
|
|
|
+ }
|
|
|
|
+ if (!Check.isNull(bid)) {
|
|
|
|
+ unit.setBid(bid);
|
|
|
|
+ }
|
|
|
|
+ if (!Check.isNull(cpaBid)) {
|
|
|
|
+ unit.setCpaBid(getBidByString(cpaBid));
|
|
|
|
+ }
|
|
|
|
+ if (!Check.isNull(deepConversionBid)) {
|
|
|
|
+ unit.setDeepConversionBid(deepConversionBid);
|
|
|
|
+ }
|
|
|
|
+ unit.setSceneId(sceneId.toJSONString());
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ // 年龄
|
|
|
|
+ String ages_range = variableJson.getString("ages_range");
|
|
|
|
+ if (!Check.isNull(ages_range)) {
|
|
|
|
+ if (!"unlimited".equals(ages_range)) {
|
|
|
|
+ JSONArray ageArray = getAgeArray(ages_range);
|
|
|
|
+ unit.setAgesRange(ageArray.toJSONString());
|
|
|
|
+ unit.setAgeGroupName(getAgeName(ages_range));
|
|
|
|
+ } else {
|
|
|
|
+ unit.setAgeGroupName("不限");
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ unit.setAgeGroupName("不限");
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+ // 性别
|
|
|
|
+ String gender = variableJson.getString("gender");
|
|
|
|
+ if (!Check.isNull(gender)) {
|
|
|
|
+ if (!"unlimited".equals(gender)) {
|
|
|
|
+ unit.setGender(Integer.valueOf(gender));
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 时段
|
|
|
|
+ String schedule_time = variableJson.getString("schedule_time");
|
|
|
|
+ if (!Check.isNull(schedule_time)) {
|
|
|
|
+ if (!"unlimited".equals(schedule_time)) {
|
|
|
|
+ unit.setScheduleTime(schedule_time);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 应用名称-行为定向
|
|
|
|
+ JSONArray app_ids = variableJson.getJSONArray("app_ids");
|
|
|
|
+ if (!Check.isNull(app_ids)) {
|
|
|
|
+ String appId = app_ids.getString(0);
|
|
|
|
+ if (!"unlimited".equals(appId)) {
|
|
|
|
+ unit.setAppIds(app_ids.toJSONString());
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ // 行为意向-系统优选
|
|
|
|
+ String intention_target = variableJson.getString("intention_target");
|
|
|
|
+ if (!Check.isNull(intention_target)) {
|
|
|
|
+ if (!"unlimited".equals(intention_target)) {
|
|
|
|
+ if (intention_target.equals("1")) {
|
|
|
|
+ unit.setIntentionTarget(true);
|
|
|
|
+ } else {
|
|
|
|
+ unit.setIntentionTarget(false);
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ unit.setIntentionTarget(false);
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ unit.setIntentionTarget(false);
|
|
|
|
+ }
|
|
|
|
+ // 地域
|
|
|
|
+ String region = variableJson.getString("region");
|
|
|
|
+ if (!Check.isNull(region)) {
|
|
|
|
+ if (!"unlimited".equals(region)) {
|
|
|
|
+ JSONArray regionArray = getRegion(region);
|
|
|
|
+ unit.setRegion(regionArray.toJSONString());
|
|
|
|
+ unit.setRegionGroupName(getRegionName(region));
|
|
|
|
+ } else {
|
|
|
|
+ unit.setRegionGroupName("不限");
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ unit.setRegionGroupName("不限");
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ Integer intelli_extend = variableJson.getInteger("intelli_extend");
|
|
|
|
+ if (!Check.isNull(intelli_extend)) {
|
|
|
|
+ if (intelli_extend == 0) {
|
|
|
|
+ unit.setIsOpen(0);
|
|
|
|
+ } else if (intelli_extend == 1) {
|
|
|
|
+ unit.setIsOpen(1);
|
|
|
|
+ if (!Check.isNull(ages_range)) {
|
|
|
|
+ if (!"unlimited".equals(ages_range)) {
|
|
|
|
+ unit.setNoAgeBreak(1);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ if (!Check.isNull(gender)) {
|
|
|
|
+ if (!"unlimited".equals(gender)) {
|
|
|
|
+ unit.setNoGenderBreak(1);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ if (!Check.isNull(region)) {
|
|
|
|
+ if (!"unlimited".equals(region)) {
|
|
|
|
+ unit.setNoAreaBreak(1);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ redisUtil.set(countKey, count + 1);
|
|
|
|
+ addUnit(unit); // 组数据入库
|
|
|
|
+
|
|
|
|
+ // 平均获取行动号召按钮
|
|
|
|
+ if (actionBarTextIndex > actionBarTextMaxIndex) {
|
|
|
|
+ actionBarTextIndex = 0;
|
|
|
|
+ }
|
|
|
|
+ String actionBarTextStr = getStringByIndex(actionBarTextIndex, actionBarText);
|
|
|
|
+ // 平均获取广告语
|
|
|
|
+ if (descriptionIndex > descriptionMaxIndex) {
|
|
|
|
+ descriptionIndex = 0;
|
|
|
|
+ }
|
|
|
|
+ String descriptionStr = getStringByIndex(descriptionIndex, description);
|
|
|
|
+ // 创意数据入库
|
|
|
|
+ addCreative(uuid, videoArray, campaignId, account, actionBarTextStr, descriptionStr);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ returnJson.put("code", 0);
|
|
|
|
+ returnJson.put("message", "创建成功");
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
+ e.printStackTrace();
|
|
|
|
+ returnJson.put("code", -1);
|
|
|
|
+ returnJson.put("message", "创建失败");
|
|
|
|
+ }
|
|
|
|
+ return returnJson;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 获取年龄配置
|
|
|
|
+ *
|
|
|
|
+ * @param mapId
|
|
|
|
+ * @return
|
|
|
|
+ */
|
|
|
|
+ private JSONArray getAgeArray(String mapId) {
|
|
|
|
+ if (Check.isNullMap(ageMap)) {
|
|
|
|
+ ageMap = dimensionAgeConfigService.getAgeMap();
|
|
|
|
+ }
|
|
|
|
+ return ageMap.get(mapId);
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 获取年龄组名称
|
|
|
|
+ *
|
|
|
|
+ * @param mapId
|
|
|
|
+ * @return
|
|
|
|
+ */
|
|
|
|
+ private String getAgeName(String mapId) {
|
|
|
|
+ if (Check.isNullMap(ageNameMap)) {
|
|
|
|
+ ageNameMap = dimensionAgeConfigService.getAgeNameMap();
|
|
|
|
+ }
|
|
|
|
+ return ageNameMap.get(mapId);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 根据下标获取信息
|
|
|
|
+ *
|
|
|
|
+ * @param index
|
|
|
|
+ * @param jsonArray
|
|
|
|
+ * @return
|
|
|
|
+ */
|
|
|
|
+ private String getStringByIndex(Integer index, JSONArray jsonArray) {
|
|
|
|
+ return jsonArray.getString(index);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 多线程添加创意信息
|
|
|
|
+ *
|
|
|
|
+ * @param videoArray
|
|
|
|
+ * @param campaignId
|
|
|
|
+ * @param account
|
|
|
|
+ * @param actionBarText
|
|
|
|
+ * @param description
|
|
|
|
+ */
|
|
|
|
+ private void addCreative(String unitTableId, JSONArray videoArray, Long campaignId, KuaiShouDimensionAccount account, String actionBarText, String description) {
|
|
|
|
+ addCreativeService.submit(new Runnable() {
|
|
|
|
+ @Override
|
|
|
|
+ public void run() {
|
|
|
|
+ List<KuaiShouDimensionCreative> addList = new ArrayList<>();
|
|
|
|
+ for (int i = 0; i < videoArray.size(); i++) {
|
|
|
|
+ Long photoId = videoArray.getLong(i);
|
|
|
|
+ if (Check.isNull(photoId)) {
|
|
|
|
+ continue;
|
|
|
|
+ }
|
|
|
|
+ KuaiShouVideoGet videoGet = videoGetService.getVideoByPhotoId(photoId);
|
|
|
|
+ if (Check.isNull(videoGet)) {
|
|
|
|
+ continue;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ KuaiShouDimensionCreative creative = new KuaiShouDimensionCreative();
|
|
|
|
+ creative.setUnitTableId(unitTableId);
|
|
|
|
+ creative.setStrategyId(account.getStrategyId());
|
|
|
|
+ creative.setAccountId(account.getAccountId());
|
|
|
|
+ creative.setCampaignId(campaignId);
|
|
|
|
+ creative.setCreativeName("创意_" + i);
|
|
|
|
+ creative.setPhotoId(photoId);
|
|
|
|
+ creative.setCreativeMaterialType(videoGet.getMaterialType());
|
|
|
|
+ creative.setActionBarText(actionBarText);
|
|
|
|
+ creative.setDescription(description);
|
|
|
|
+ if (!Check.isNull(account.getClickTrackUrl())) {
|
|
|
|
+ creative.setClickTrackUrl(account.getClickTrackUrl());
|
|
|
|
+ }
|
|
|
|
+ if (!Check.isNull(account.getActionbarClickUrl())) {
|
|
|
|
+ creative.setActionbarClickUrl(account.getActionbarClickUrl());
|
|
|
|
+ }
|
|
|
|
+ if (!Check.isNull(account.getCreativeCategory())) {
|
|
|
|
+ creative.setCreativeCategory(account.getCreativeCategory());
|
|
|
|
+ }
|
|
|
|
+ if (!Check.isNull(account.getCreativeTag())) {
|
|
|
|
+ creative.setCreativeTag(account.getCreativeTag());
|
|
|
|
+ }
|
|
|
|
+ addList.add(creative);
|
|
|
|
+ }
|
|
|
|
+ if (!Check.isNull(addList)) {
|
|
|
|
+ dimensionCreativeService.addBatch(addList);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ });
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 多线程添加组信息
|
|
|
|
+ *
|
|
|
|
+ * @param unit
|
|
|
|
+ */
|
|
|
|
+ private void addUnit(KuaiShouDimensionUnit unit) {
|
|
|
|
+ addUnitService.submit(new Runnable() {
|
|
|
|
+ @Override
|
|
|
|
+ public void run() {
|
|
|
|
+ dimensionUnitService.save(unit);
|
|
|
|
+ }
|
|
|
|
+ });
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 获取地域信息
|
|
|
|
+ *
|
|
|
|
+ * @param mapId
|
|
|
|
+ * @return
|
|
|
|
+ */
|
|
|
|
+ private JSONArray getRegion(String mapId) {
|
|
|
|
+ if (Check.isNullMap(regionMap)) {
|
|
|
|
+ regionMap = dimensionRegionDetailService.getRegionList();
|
|
|
|
+ }
|
|
|
|
+ return regionMap.get(mapId);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 获取地域组名称
|
|
|
|
+ *
|
|
|
|
+ * @param mapId
|
|
|
|
+ * @return
|
|
|
|
+ */
|
|
|
|
+ private String getRegionName(String mapId) {
|
|
|
|
+ if (Check.isNullMap(regionNameMap)) {
|
|
|
|
+ regionNameMap = dimensionRegionDetailService.getRegionNameList();
|
|
|
|
+ }
|
|
|
|
+ return regionNameMap.get(mapId);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 获取随机、区间出价
|
|
|
|
+ *
|
|
|
|
+ * @param cpaBid
|
|
|
|
+ * @return
|
|
|
|
+ */
|
|
|
|
+ private Long getBidByString(String cpaBid) {
|
|
|
|
+ if (Check.isNull(cpaBid)) {
|
|
|
|
+ return null;
|
|
|
|
+ }
|
|
|
|
+ String bidString = null;
|
|
|
|
+ if (cpaBid.contains("/")) { // 阶梯出价
|
|
|
|
+ String[] split = cpaBid.split("/");
|
|
|
|
+ int random = new Random().nextInt(split.length);
|
|
|
|
+ bidString = split[random];
|
|
|
|
+
|
|
|
|
+ } else if (cpaBid.contains("-")) { // 随机出价
|
|
|
|
+ String[] split = cpaBid.split("-");
|
|
|
|
+ Double min = Double.valueOf(split[0]) / 1000;
|
|
|
|
+ Double max = Double.valueOf(split[1]) / 1000;
|
|
|
|
+ Double randomNumber = new BigDecimal(min + Math.random() * (max - min)).setScale(1, BigDecimal.ROUND_HALF_UP).doubleValue();
|
|
|
|
+ bidString = String.valueOf(new Double(randomNumber * 1000).longValue());
|
|
|
|
+ } else {
|
|
|
|
+ bidString = cpaBid;
|
|
|
|
+ }
|
|
|
|
+ return Long.valueOf(bidString);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 获取主键uuId
|
|
|
|
+ *
|
|
|
|
+ * @return
|
|
|
|
+ */
|
|
|
|
+ private static String getUuid() {
|
|
|
|
+ String uuid = UUID.randomUUID().toString().replace("-", "");
|
|
|
|
+ return uuid;
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 获取计划
|
|
|
|
+ *
|
|
|
|
+ * @param accountId
|
|
|
|
+ * @param account
|
|
|
|
+ * @param strategy
|
|
|
|
+ * @return
|
|
|
|
+ */
|
|
|
|
+ private Long getCampaignId(Long accountId, KuaiShouDimensionAccount account, KuaiShouDimensionStrategy strategy) {
|
|
|
|
+ String key = in_use_key + accountId;
|
|
|
|
+ Object o = redisUtil.get(key);
|
|
|
|
+ if (!Check.isNull(o)) {
|
|
|
|
+ return Long.valueOf(o.toString());
|
|
|
|
+ }
|
|
|
|
+ String createCampaignCountKey = account_count_key + accountId;
|
|
|
|
+ Object countObject = redisUtil.get(createCampaignCountKey);
|
|
|
|
+ Integer count = 0;
|
|
|
|
+ if (Check.isNull(countObject)) {
|
|
|
|
+ redisUtil.set(createCampaignCountKey, count);
|
|
|
|
+ } else {
|
|
|
|
+ count = Integer.valueOf(countObject.toString()) + 1;
|
|
|
|
+ redisUtil.set(createCampaignCountKey, count);
|
|
|
|
+ }
|
|
|
|
+ CtopOauthToken token = oauthTokenService.getTokenByAccountId(accountId);
|
|
|
|
+ JSONObject campaignParams = new JSONObject();
|
|
|
|
+ campaignParams.put("advertiser_id", token.getAccountId());
|
|
|
|
+
|
|
|
|
+ String campaignName = strategy.getCampaignName();
|
|
|
|
+ String name = getName(campaignName, account, strategy) + "_" + count;
|
|
|
|
+ campaignParams.put("campaign_name", name);
|
|
|
|
+ campaignParams.put("type", strategy.getCampaignType());
|
|
|
|
+ if (null != strategy.getCampaignDayBudget() && strategy.getCampaignDayBudget() != 0) {
|
|
|
|
+ campaignParams.put("day_budget", strategy.getCampaignDayBudget());
|
|
|
|
+ }
|
|
|
|
+ Map<String, Object> campaignCreateResult = kuaishouInterfaceService.campaignCreate(token.getAccessToken(), token.getAccountId(), campaignParams);
|
|
|
|
+ Integer code = (Integer) campaignCreateResult.get("code");
|
|
|
|
+ String message = (String) campaignCreateResult.get("message");
|
|
|
|
+ if (code != 0) {
|
|
|
|
+ log.info("计划创建失败,accountId:{}message:{}", accountId, message);
|
|
|
|
+ return null;
|
|
|
|
+ }
|
|
|
|
+ Long campaignId = (Long) campaignCreateResult.get("campaignId");
|
|
|
|
+ redisUtil.set(key, campaignId);
|
|
|
|
+ KuaiShouDimensionCampaign campaign = new KuaiShouDimensionCampaign();
|
|
|
|
+ campaign.setAccountId(accountId);
|
|
|
|
+ campaign.setStrategyId(strategy.getId());
|
|
|
|
+ campaign.setCampaignId(campaignId);
|
|
|
|
+ campaign.setCampaignType(strategy.getCampaignType());
|
|
|
|
+ campaign.setCampaignName(name);
|
|
|
|
+ campaign.setDayBudget(strategy.getCampaignDayBudget());
|
|
|
|
+ boolean save = dimensionCampaignService.save(campaign);
|
|
|
|
+ if (save) {
|
|
|
|
+ log.info("素材多维度计划入库成功,策略id:{},账户id:{},计划id:{}", strategy.getId(), accountId, campaignId);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return campaignId;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 获取账户配置
|
|
|
|
+ *
|
|
|
|
+ * @param index
|
|
|
|
+ * @param accountList
|
|
|
|
+ * @return
|
|
|
|
+ */
|
|
|
|
+ private KuaiShouDimensionAccount getAccountInfo(Integer index, List<KuaiShouDimensionAccount> accountList) {
|
|
|
|
+ return accountList.get(index);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private String getName(String name, KuaiShouDimensionAccount account, KuaiShouDimensionStrategy strategy) {
|
|
|
|
+ if (name.contains("{{应用包名}}") || name.contains("{{应用标记}}")) {
|
|
|
|
+ KuaiShouAppList getAppInfo = appListService.getAppInfo(account.getAccountId(), account.getAppId());
|
|
|
|
+ if (!Check.isNull(getAppInfo)) {
|
|
|
|
+ name = name.replace("{{应用包名}}", getAppInfo.getAppName());
|
|
|
|
+ name = name.replace("{{应用标记}}", getAppInfo.getAppVersion());
|
|
|
|
+ } else {
|
|
|
|
+ name = name.replace("{{应用包名}}", "");
|
|
|
|
+ name = name.replace("{{应用标记}}", "");
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ if (name.contains("{{创意制作方式}}")) {
|
|
|
|
+ if (strategy.getUnitType() == 4) {
|
|
|
|
+ name = name.replace("{{创意制作方式}}", "自定义");
|
|
|
|
+ } else if (strategy.getUnitType() == 7) {
|
|
|
|
+ name = name.replace("{{创意制作方式}}", "程序化");
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ if (name.contains("{{广告位置}}")) {
|
|
|
|
+ String adsence = getAdSenceByParams(strategy.getSceneId());
|
|
|
|
+ name = name.replace("{{广告位置}}", adsence);
|
|
|
|
+ }
|
|
|
|
+ if (name.contains("{{日期}}")) {
|
|
|
|
+ Date date = new Date();
|
|
|
|
+ String nowDate = DateUtils.formatDate(date, "yy-MMdd");
|
|
|
|
+ name = name.replace("{{日期}}", nowDate);
|
|
|
|
+ }
|
|
|
|
+ if (name.contains("{{时分}}")) {
|
|
|
|
+ Date date = new Date();
|
|
|
|
+ String nowDate = DateUtils.formatDate(date, "HH:mm");
|
|
|
|
+ name = name.replace("{{时分}}", nowDate);
|
|
|
|
+ }
|
|
|
|
+ if (name.endsWith("-")) {
|
|
|
|
+ name = name.substring(0, name.length() - 1);
|
|
|
|
+ }
|
|
|
|
+ return name;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private String getAdSenceByParams(String sceneIdString) {
|
|
|
|
+ String adsence = "";
|
|
|
|
+ if (null == sceneIdString || "".equals(sceneIdString)) {
|
|
|
|
+ return adsence;
|
|
|
|
+ }
|
|
|
|
+ JSONArray sceneIdArray = JSON.parseArray(sceneIdString);
|
|
|
|
+ if (null == sceneIdArray || sceneIdArray.isEmpty()) {
|
|
|
|
+ return adsence;
|
|
|
|
+ }
|
|
|
|
+ for (int i = 0; i < sceneIdArray.size(); i++) {
|
|
|
|
+ adsence += KuaishouCreativeAdsenceTypeEnum.getNameByType(sceneIdArray.getInteger(i)) + "-";
|
|
|
|
+ }
|
|
|
|
+ return adsence.substring(0, adsence.length() - 1);
|
|
|
|
+ }
|
|
|
|
+}
|