Pārlūkot izejas kodu

Merge remote-tracking branch 'origin/master'

# Conflicts:
#	jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/shiro/ShiroConfig.java
huangxuechao 4 gadi atpakaļ
vecāks
revīzija
3dda09f457
86 mainītis faili ar 3606 papildinājumiem un 125363 dzēšanām
  1. 0 124894
      db/jeecgboot-sqlserver2017.sql
  2. 0 1
      jeecg-boot-base/jeecg-boot-base-core/pom.xml
  3. 27 0
      jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/DateUtils.java
  4. 5 0
      jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/shiro/ShiroConfig.java
  5. 0 10
      jeecg-boot-bytedance/pom.xml
  6. 2 1
      jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/advertise/dockapi/MarketingService.java
  7. 36 19
      jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/advertise/dockapi/MarketingServiceImpl.java
  8. 3 0
      jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/advertise/entity/AiBytedanceAdDplinkInfo.java
  9. 1 1
      jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/advertise/entity/AiBytedanceAdvertiserStrategy.java
  10. 69 0
      jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/advertise/entity/AiBytedanceAutocreateLog.java
  11. 108 0
      jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/advertise/entity/ByteDanceCreativeWordPackage.java
  12. 13 0
      jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/advertise/entity/ByteDanceGeneralCopywriter.java
  13. 5 0
      jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/advertise/entity/ByteDanceVideoInfo.java
  14. 27 0
      jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/advertise/entity/BytedanceMaterialRejectReason.java
  15. 22 0
      jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/advertise/entity/BytedancePlanRejectReason.java
  16. 21 1
      jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/advertise/entity/BytedanceVideoSlogenInfo.java
  17. 19 0
      jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/advertise/entity/LowQualityRejectReason.java
  18. 43 1
      jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/advertise/enums/BytedanceCreativeMatTypeEnum.java
  19. 1 1
      jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/advertise/mapper/AiBytedanceAdvertiserStrategyMapper.java
  20. 17 0
      jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/advertise/mapper/AiBytedanceAutocreateLogMapper.java
  21. 13 4
      jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/advertise/mapper/ByteDanceGeneralCopywriterMapper.java
  22. 23 3
      jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/advertise/mapper/ByteDanceVideoInfoMapper.java
  23. 17 0
      jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/advertise/mapper/BytedanceMaterialRejectReasonMapper.java
  24. 14 0
      jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/advertise/mapper/BytedancePlanRejectReasonMapper.java
  25. 5 1
      jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/advertise/mapper/BytedanceVideoSlogenInfoMapper.java
  26. 15 0
      jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/advertise/mapper/LowQualityRejectReasonMapper.java
  27. 3 0
      jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/advertise/mapper/xml/AiBytedanceAdvertiserStrategyMapper.xml
  28. 5 0
      jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/advertise/mapper/xml/AiBytedanceAutocreateLogMapper.xml
  29. 12 0
      jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/advertise/mapper/xml/ByteDanceAdvertisePlanMapper.xml
  30. 41 10
      jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/advertise/mapper/xml/ByteDanceGeneralCopywriterMapper.xml
  31. 126 5
      jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/advertise/mapper/xml/ByteDanceVideoInfoMapper.xml
  32. 12 0
      jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/advertise/mapper/xml/BytedanceMaterialRejectReasonMapper.xml
  33. 9 0
      jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/advertise/mapper/xml/BytedancePlanRejectReasonMapper.xml
  34. 109 18
      jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/advertise/mapper/xml/BytedanceVideoSlogenInfoMapper.xml
  35. 9 0
      jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/advertise/mapper/xml/LowQualityRejectReasonMapper.xml
  36. 19 0
      jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/advertise/service/BytedanceRejectReasonService.java
  37. 2 2
      jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/advertise/service/IAiBytedanceAdDplinkInfoService.java
  38. 7 3
      jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/advertise/service/IAiBytedanceAdvertiserStrategyService.java
  39. 14 0
      jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/advertise/service/IAiBytedanceAutocreateLogService.java
  40. 2 0
      jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/advertise/service/IByteDanceAdvertisePlanService.java
  41. 0 1
      jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/advertise/service/IByteDanceCreativeService.java
  42. 8 1
      jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/advertise/service/IByteDanceGeneralCopywriterService.java
  43. 26 3
      jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/advertise/service/IByteDanceVideoInfoService.java
  44. 4 2
      jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/advertise/service/IBytedanceVideoSlogenInfoService.java
  45. 6 2
      jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/advertise/service/impl/AiBytedanceAdDplinkInfoServiceImpl.java
  46. 396 110
      jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/advertise/service/impl/AiBytedanceAdvertiserStrategyServiceImpl.java
  47. 19 0
      jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/advertise/service/impl/AiBytedanceAutocreateLogServiceImpl.java
  48. 14 0
      jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/advertise/service/impl/ByteDanceAdvertisePlanServiceImpl.java
  49. 2 0
      jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/advertise/service/impl/ByteDanceCampaignServiceImpl.java
  50. 66 21
      jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/advertise/service/impl/ByteDanceGeneralCopywriterServiceImpl.java
  51. 35 6
      jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/advertise/service/impl/ByteDanceVideoInfoServiceImpl.java
  52. 131 0
      jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/advertise/service/impl/BytedanceRejectReasonServiceImpl.java
  53. 36 10
      jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/advertise/service/impl/BytedanceVideoSlogenInfoServiceImpl.java
  54. 61 0
      jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/common/entity/BytedanceOperationLog.java
  55. 3 0
      jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/common/entity/MaterialInfo.java
  56. 17 0
      jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/common/mapper/BytedanceOperationLogMapper.java
  57. 5 0
      jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/common/mapper/xml/BytedanceOperationLogMapper.xml
  58. 2 7
      jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/common/mapper/xml/UserAllocationMapper.xml
  59. 14 0
      jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/common/service/IBytedanceOperationLogService.java
  60. 4 1
      jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/common/service/IMaterialInfoService.java
  61. 19 0
      jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/common/service/impl/BytedanceOperationLogServiceImpl.java
  62. 12 3
      jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/common/service/impl/MaterialInfoServiceImpl.java
  63. 12 4
      jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/common/utils/ExcelUtil.java
  64. 39 0
      jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/common/utils/GetCampaignNum.java
  65. 167 0
      jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/common/utils/StringUtils.java
  66. 6 2
      jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/report/entity/vo/ReportCostVo.java
  67. 11 0
      jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/report/mapper/BytedanceAdvertiserHourlyReportMapper.java
  68. 146 9
      jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/report/mapper/xml/BytedanceAdvertiserHourlyReportMapper.xml
  69. 5 5
      jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/report/mapper/xml/BytedanceReportMaterialDailyMapper.xml
  70. 156 99
      jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/report/service/impl/BytedanceAdvertiserHourlyReportServiceImpl.java
  71. 13 5
      jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/report/service/impl/BytedanceReportMaterialDailyServiceImpl.java
  72. 43 9
      jeecg-boot-module-system/src/main/java/org/jeecg/modules/bytedance/advertise/controller/AiBytedanceAdvertiserStrategyController.java
  73. 158 31
      jeecg-boot-module-system/src/main/java/org/jeecg/modules/bytedance/advertise/controller/BytedanceGeneralCopywriterController.java
  74. 111 0
      jeecg-boot-module-system/src/main/java/org/jeecg/modules/bytedance/advertise/controller/BytedanceRejectReasonController.java
  75. 68 11
      jeecg-boot-module-system/src/main/java/org/jeecg/modules/bytedance/advertise/controller/BytedanceReportController.java
  76. 206 25
      jeecg-boot-module-system/src/main/java/org/jeecg/modules/bytedance/advertise/controller/BytedanceVideoSlogenInfoController.java
  77. 124 8
      jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysUserController.java
  78. 30 0
      jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/entity/SysUser.java
  79. 4 0
      jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/mapper/SysUserMapper.java
  80. 56 0
      jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/mapper/xml/SysUserMapper.xml
  81. 5 0
      jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/ISysUserService.java
  82. 43 0
      jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/SysUserServiceImpl.java
  83. 37 1
      jeecg-boot-module-system/src/main/resources/application-dev.yml
  84. 329 0
      jeecg-boot-module-system/src/main/resources/application-pre.yml
  85. 43 10
      jeecg-boot-module-system/src/main/resources/application-prod.yml
  86. 38 2
      jeecg-boot-module-system/src/main/resources/application-test.yml

Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 124894
db/jeecgboot-sqlserver2017.sql


+ 0 - 1
jeecg-boot-base/jeecg-boot-base-core/pom.xml

@@ -242,7 +242,6 @@
             <groupId>com.github.pagehelper</groupId>
             <artifactId>pagehelper</artifactId>
             <version>5.1.10</version>
-            <scope>compile</scope>
         </dependency>
     </dependencies>
 

+ 27 - 0
jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/DateUtils.java

@@ -640,4 +640,31 @@ public class DateUtils extends PropertyEditorSupport {
         return calendar.get(Calendar.YEAR);
     }
 
+    public static String addDay(String dateString, int day) {
+        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
+        Date date = null;
+        try {
+            date = sdf.parse(dateString);
+        } catch (ParseException e) {
+            e.printStackTrace();
+        }
+        Calendar calendar = Calendar.getInstance();
+        calendar.setTime(date);
+        calendar.add(Calendar.DAY_OF_YEAR, day);
+        return sdf.format(calendar.getTime());
+    }
+
+    public static Date addDay(Date date, int day) {
+        Calendar calendar = Calendar.getInstance();
+        calendar.setTime(date);
+        calendar.add(Calendar.DAY_OF_YEAR, day);
+        return calendar.getTime();
+    }
+
+    public static Date addHour(Date date, int hour) {
+        Calendar calendar = Calendar.getInstance();
+        calendar.setTime(date);
+        calendar.add(Calendar.HOUR_OF_DAY, hour);
+        return calendar.getTime();
+    }
 }

+ 5 - 0
jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/shiro/ShiroConfig.java

@@ -135,8 +135,13 @@ public class ShiroConfig {
 
         filterChainDefinitionMap.put("/file/**","anon");//
 
+        //获取计划和素材维度的审核建议数据
+        filterChainDefinitionMap.put("/ctop/bytedanceRejectReason/**","anon");
+
         filterChainDefinitionMap.put("/sys/dict/**","anon");//
 
+        filterChainDefinitionMap.put("/advertiser/bytedanceReportController/updateADCpaBid","anon");//
+
         //性能监控  TODO 存在安全漏洞泄露TOEKN(durid连接池也有)
         filterChainDefinitionMap.put("/actuator/**", "anon");
 

+ 0 - 10
jeecg-boot-bytedance/pom.xml

@@ -38,15 +38,5 @@
             <version>1.16</version>
             <scope>compile</scope>
         </dependency>
-
-        <!--引入微服务启动依赖 starter
-      <dependency>
-          <groupId>org.jeecgframework.boot</groupId>
-          <artifactId>jeecg-boot-starter-cloud</artifactId>
-      </dependency>
-        <dependency>
-            <groupId>org.jeecgframework.boot</groupId>
-            <artifactId>jeecg-boot-starter-job</artifactId>
-        </dependency>-->
     </dependencies>
 </project>

+ 2 - 1
jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/advertise/dockapi/MarketingService.java

@@ -9,13 +9,14 @@ import org.jeecg.modules.bytedance.advertise.vo.ByteDanceSearchVo;
 import org.jeecg.modules.bytedance.advertise.vo.PlanSearchVo;
 import org.jeecg.modules.bytedance.common.entity.CtopOauthToken;
 
+import java.math.BigDecimal;
 import java.util.List;
 import java.util.Map;
 
 public interface MarketingService {
     Result getBudget(CtopOauthToken token, List<Long> advertiser_ids);
 
-    Result updateBudget(CtopOauthToken token, String budgetMode, String budget);
+    Result updateBudget(CtopOauthToken token, String budgetMode, BigDecimal budget);
 
     Result selectCustomAudience(CtopOauthToken token);
 

+ 36 - 19
jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/advertise/dockapi/MarketingServiceImpl.java

@@ -13,6 +13,7 @@ import org.jeecg.common.api.vo.Result;
 import org.jeecg.modules.bytedance.advertise.entity.AiBytedanceAdvertiserStrategy;
 import org.jeecg.modules.bytedance.advertise.entity.ByteDanceCampaign;
 import org.jeecg.modules.bytedance.advertise.enums.BytedanceConvertType;
+import org.jeecg.modules.bytedance.advertise.service.IAiBytedanceAutocreateLogService;
 import org.jeecg.modules.bytedance.advertise.service.IByteDanceCampaignService;
 import org.jeecg.modules.bytedance.advertise.vo.AdConvertQueryVo;
 import org.jeecg.modules.bytedance.advertise.vo.ByteDanceSearchVo;
@@ -28,6 +29,7 @@ import org.springframework.stereotype.Service;
 import java.io.BufferedReader;
 import java.io.IOException;
 import java.io.InputStreamReader;
+import java.math.BigDecimal;
 import java.net.URI;
 import java.util.HashMap;
 import java.util.List;
@@ -46,6 +48,9 @@ public class MarketingServiceImpl implements MarketingService{
 
     @Autowired
     private IByteDanceCampaignService campaignService;
+
+    @Autowired
+    IAiBytedanceAutocreateLogService iBytedanceAutocreateLogService;
     /**
      *
      * @description: 获取账户日预算
@@ -83,7 +88,7 @@ public class MarketingServiceImpl implements MarketingService{
      * @return: java.util.Map<java.lang.String,java.lang.Object>
      */
     @Override
-    public Result updateBudget(CtopOauthToken token, String budgetMode, String budget) {
+    public Result updateBudget(CtopOauthToken token, String budgetMode, BigDecimal budget) {
         JSONObject params = new JSONObject();
         //广告主ID
         params.put("advertiser_id", token.getAccountId());
@@ -102,7 +107,7 @@ public class MarketingServiceImpl implements MarketingService{
             log.info("修改计划预算接口异常==》accountId:{},message:{}", token.getAccountId(), jsonObject.getString("message"));
             return Result.error(jsonObject.getString("message"));
         }
-        return Result.successMsg("修改计划预算成功",null);
+        return Result.successMsg("修改账户预算成功",null);
     }
 
 
@@ -424,24 +429,29 @@ public class MarketingServiceImpl implements MarketingService{
      * @author: zianY
      */
     @Override
-    public  Result getRejectReason(CtopOauthToken token, String advertiserId, List<String> adIds) {
+    public Result getRejectReason(CtopOauthToken token, String advertiserId, List<String> adIds) {
         JSONObject params = new JSONObject();
         params.put("advertiser_id", advertiserId);
         params.put("ad_ids", adIds);
 
         JSONObject jsonObject = HttpUtils.bytedanceGetRequest(token.getAccessToken(),
-                urlPath + PropertiesUtils.getValue("bytedance_config", "bytedance_v2_ad_create_reasion"),params);
+                urlPath + PropertiesUtils.getValue("bytedance_config", "bytedance_v2_ad_create_reasion"), params);
         Integer code = jsonObject.getInteger("code");
         if (null == code || !code.equals(0)) {
-            log.info("获取广告主计划审核建议接口异常==》accountId:{},message:{}", token.getAccountId(), jsonObject.getString("message"));
-            return Result.error("获取广告主计划审核建议接口异常");
+//            log.info("获取广告主计划审核建议接口异常==》accountId:{},message:{}", token.getAccountId(), jsonObject.getString("message"));
+            if (jsonObject.getString("message").toString().contains("ad_ids:[")) {
+                JSONArray ad_ids = JSONArray.parseArray(jsonObject.getString("message").toString().split(":")[2]);
+                adIds.removeAll(ad_ids.toJavaList(String.class));
+                return getRejectReason(token, advertiserId, adIds);
+            }
+            return Result.error("获取广告主计划审核建议接口异常==》message:"+jsonObject.getString("message"));
         }
         JSONArray data = jsonObject.getJSONObject("data").getJSONArray("list");
         if (null == data || data.isEmpty()) {
             log.info("获取广告主计划审核建议不存在==》accountId:{},message:{}", token.getAccountId(), jsonObject.getString("message"));
             return Result.error("获取广告主计划审核建议不存在");
         }
-        return Result.successMsg("获取广告主计划审核建议成功。",data);
+        return Result.successMsg("获取广告主计划审核建议成功。", data);
     }
 
 
@@ -524,7 +534,7 @@ public class MarketingServiceImpl implements MarketingService{
             log.error("广告计划更新状态接口异常==》accountId:{},message:{}", token.getAccountId(), jsonObject.getString("message"));
             return Result.error("广告计划更新状态接口异常");
         }
-        return Result.successMsg("广告状态修改成功",jsonObject.getString("data"));
+        return Result.successMsg("广告计划状态修改成功",jsonObject.getString("data"));
     }
 
 
@@ -707,6 +717,9 @@ public class MarketingServiceImpl implements MarketingService{
         //params.put("operation", BytedanceConstant.OPERATION_ENABLE);
         // 投放范围  "DEFAULT"默认, "UNION"穿山甲
         params.put("delivery_range", strategy.getAdDeliveryRange() == null ? "DEFAULT" : strategy.getAdDeliveryRange());
+        if(null!=strategy.getAdDownloadUrl()&&!"".equals(strategy.getAdDownloadUrl().trim())){
+            params.put("download_url", strategy.getAdDownloadUrl());
+        }
         //投放形式(穿山甲视频创意类型) 当delivery_range为"UNION"时必填
         // 允许值: "ORIGINAL_VIDEO"原生, "REWARDED_VIDEO"激励视频,"SPLASH_VIDEO"开屏
         // params.put("union_video_type", byteDanceAdvertisePlan.getUnionVideoType() == null ? "ORIGINAL_VIDEO" : byteDanceAdvertisePlan.getUnionVideoType());
@@ -717,18 +730,18 @@ public class MarketingServiceImpl implements MarketingService{
             params.put("download_type", strategy.getAdDownloadType());
             //下载链接
             // 类型为下载链接
-            if ("DOWNLOAD_URL".equals(strategy.getAdDownloadType())){
-                params.put("download_url", strategy.getAdDownloadUrl());
-                //下载的应用类型,当download_type为DOWNLOAD_URL时必填
-                //允许值: "APP_ANDROID"Android APP, "APP_IOS"IOS APP
-                params.put("app_type", strategy.getAdAppType());
-                params.put("package", strategy.getAdPackage());
-            }
+//            if ("DOWNLOAD_URL".equals(strategy.getAdDownloadType())){
+//                params.put("download_url", strategy.getAdDownloadUrl());
+//                //下载的应用类型,当download_type为DOWNLOAD_URL时必填
+//                //允许值: "APP_ANDROID"Android APP, "APP_IOS"IOS APP
+//                params.put("app_type", strategy.getAdAppType());
+//                params.put("package", strategy.getAdPackage());
+//            }
             // 类型为 快应用+下载链接
             if ("QUICK_APP_URL".equals(strategy.getAdDownloadType())){
                 params.put("quick_app_url", strategy.getAdDownloadUrl());
             }
-            // 类型为下载链接
+            // 类型为落地页链接
             if ("EXTERNAL_URL".equals(strategy.getAdDownloadType())){
                 params.put("external_url", strategy.getAdDownloadUrl());
             }
@@ -780,14 +793,18 @@ public class MarketingServiceImpl implements MarketingService{
         params.put("schedule_time", strategy.getAdScheduleTime());
         //付费方式(计划出价类型) 决定投放目标的类型,比如CPC表示点击量,OCPM表示转化量
         params.put("pricing", strategy.getAdPricing());
+        //params.put("pricing", "PRICING_OCPM");
         //目标转化出价/预期成本, 当pricing为"OCPM"、"OCPC"出价方式时必填)
         //pricing为"OCPC"时取值范围:0.1-10000元;
         //pricing为"OCPM"时取值范围:0.1-10000元;
         //出价不能大于预算否则会报错
         params.put("cpa_bid", strategy.getAdCpaBid());
+        //params.put("bid", strategy.getAdCpaBid());
         params = Check.jsonRemoveEmpty(params);
+        System.out.println(params.toJSONString());
         JSONObject jsonObject = HttpUtils.bytedancePostRequest(token.getAccessToken(),
                 urlPath + PropertiesUtils.getValue("bytedance_config", "bytedance_v2_ad_update"), params);
+        System.out.println(jsonObject.toJSONString());
         Integer code = jsonObject.getInteger("code");
         if (null ==  code || !code.equals(0)) {
             log.error("广告计划修改失败==》accountId:{},message:{}", token.getAccountId(), jsonObject.getString("message"));
@@ -891,12 +908,12 @@ public class MarketingServiceImpl implements MarketingService{
         String message = jsonObject.getString("message");
         if (null == code || !code.equals(0)) {
             log.info("获取行业类别信息接口异常==》accountId:{},message:{}", token.getAccountId(), message);
-            return Result.errorMsg(message);
+            return Result.error(message);
         }
         JSONArray data = jsonObject.getJSONObject("data").getJSONArray("list");
         if (null == data || data.isEmpty()) {
             log.info("行业类别信息不存在==》accountId:{},message:{}", token.getAccountId(), message);
-            return Result.errorMsg("行业类别信息不存在");
+            return Result.error("行业类别信息不存在");
         }
 
         return Result.successMsg("行业类别信息获取成功",data);
@@ -951,7 +968,7 @@ public class MarketingServiceImpl implements MarketingService{
         JSONArray dataList = jsonObject.getJSONObject("data").getJSONArray("list");
         if (null == dataList || dataList.isEmpty()) {
             log.info("查询广告计划可用转化目标不存在==》accountId:{},message:{}", token.getAccountId(), message);
-            return Result.error("人群包信息不存在");
+            return Result.error("账户优化目标不存在!");
         }
         for (Object obj : dataList){
             JSONObject jobj = (JSONObject) obj;

+ 3 - 0
jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/advertise/entity/AiBytedanceAdDplinkInfo.java

@@ -29,6 +29,9 @@ public class AiBytedanceAdDplinkInfo {
 	private Long adId;
 	/**accountId*/
 	private Long accountId;
+
+	private String imageMode;
+
 	private BigDecimal adBid;
 	/**strategyId*/
 	private Long strategyId;

+ 1 - 1
jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/advertise/entity/AiBytedanceAdvertiserStrategy.java

@@ -192,7 +192,7 @@ public class AiBytedanceAdvertiserStrategy{
 	/**预算类型*/
 	private String adBudgetMode;
 	/**计划预算*/
-	private Integer adBudget;
+	private BigDecimal adBudget;
 	/**投放时间类型*/
 	private String adScheduleType;
 	/**投放开始时间 */

+ 69 - 0
jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/advertise/entity/AiBytedanceAutocreateLog.java

@@ -0,0 +1,69 @@
+package org.jeecg.modules.bytedance.advertise.entity;
+
+import java.io.Serializable;
+import java.util.Date;
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.baomidou.mybatisplus.annotation.TableField;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import org.springframework.format.annotation.DateTimeFormat;
+import org.jeecgframework.poi.excel.annotation.Excel;
+
+
+/**
+ * 自动创建计划日志
+ * @author jeecg-boot
+ * @date   2021-07-05
+ * @version V1.0
+ */
+@Data
+@TableName("ctop_ai_bytedance_autocreate_log")
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+@ApiModel(value="ctop_ai_bytedance_autocreate_log对象", description="自动创建计划日志")
+public class AiBytedanceAutocreateLog {
+
+	/**主键id*/
+	@TableId(type = IdType.AUTO)
+	@ApiModelProperty(value = "主键id")
+	private Integer id;
+	/**账户id*/
+	@Excel(name = "账户id", width = 15)
+	@ApiModelProperty(value = "账户id")
+	private Long accountId;
+	/**类型*/
+	@Excel(name = "类型", width = 15)
+	@ApiModelProperty(value = "类型")
+	private String execType;
+	/**代码*/
+	@Excel(name = "代码", width = 15)
+	@ApiModelProperty(value = "代码")
+	private Integer code;
+	/**返回消息*/
+	@Excel(name = "返回消息", width = 15)
+	@ApiModelProperty(value = "返回消息")
+	private String message;
+	/**创建调用接口的参数*/
+	@Excel(name = "创建调用接口的参数", width = 15)
+	@ApiModelProperty(value = "创建调用接口的参数")
+	private String createParam;
+	/**创建时间*/
+	@ApiModelProperty(value = "创建时间")
+	private Date createTime;
+
+	public AiBytedanceAutocreateLog(){}
+
+	public AiBytedanceAutocreateLog(Long accountId, String execType, Integer code, String message, String createParam){
+		this.accountId = accountId;
+		this.execType = execType;
+		this.code = code;
+		this.message = message;
+		this.createParam = createParam;
+	}
+}

+ 108 - 0
jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/advertise/entity/ByteDanceCreativeWordPackage.java

@@ -0,0 +1,108 @@
+package org.jeecg.modules.bytedance.advertise.entity;
+
+import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+import org.jeecgframework.poi.excel.annotation.Excel;
+
+import java.util.Date;
+
+@Data
+@TableName("ctop_bytedance_creative_word_package")
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+@ApiModel(value = "ctop_bytedance_creative_word_package对象", description = "今日头条创意词包")
+public class ByteDanceCreativeWordPackage {
+
+
+    /**id*/
+    @TableId(type = IdType.UUID)
+    @ApiModelProperty(value = "id")
+    private Integer id;
+    /**creativeWordId*/
+    @Excel(name = "creativeWordId", width = 15)
+    @ApiModelProperty(value = "creativeWordId")
+    private Integer creativeWordId;
+    /**name*/
+    @Excel(name = "name", width = 15)
+    @ApiModelProperty(value = "name")
+    private String name;
+    /**defaultWord*/
+    @Excel(name = "defaultWord", width = 15)
+    @ApiModelProperty(value = "defaultWord")
+    private String defaultWord;
+    /**words*/
+    @Excel(name = "words", width = 15)
+    @ApiModelProperty(value = "words")
+    private Object words;
+    /**contentType*/
+    @Excel(name = "contentType", width = 15)
+    @ApiModelProperty(value = "contentType")
+    private String contentType;
+    /**maxWordLen*/
+    @Excel(name = "maxWordLen", width = 15)
+    @ApiModelProperty(value = "maxWordLen")
+    private Integer maxWordLen;
+    /**status*/
+    @Excel(name = "status", width = 15)
+    @ApiModelProperty(value = "status")
+    private String status;
+    /**userRate*/
+    @Excel(name = "userRate", width = 15)
+    @ApiModelProperty(value = "userRate")
+    private Float userRate;
+    /**createTime*/
+    @ApiModelProperty(value = "createTime")
+    private Date createTime;
+    /**updateTime*/
+    @ApiModelProperty(value = "updateTime")
+    private Date updateTime;
+
+
+
+    public ByteDanceCreativeWordPackage(){}
+
+    public ByteDanceCreativeWordPackage(JSONObject jsonObject){
+        int creativeWordId = jsonObject.getInteger("creative_word_id");
+        this.creativeWordId = creativeWordId;
+
+        int maxWordLen = jsonObject.getInteger("max_word_len");
+        this.maxWordLen = maxWordLen;
+
+        String name = jsonObject.getString("name");
+        if (null != name && !"".equals(name.trim())) {
+            this.name = name;
+        }
+
+        String defaultWord = jsonObject.getString("default_word");
+        if (null != defaultWord && !"".equals(defaultWord.trim())) {
+            this.defaultWord = defaultWord;
+        }
+
+        String words = jsonObject.getString("words");
+        if (null != words && !"".equals(words.trim())) {
+            this.words = words;
+        }
+
+        String contentType = jsonObject.getString("content_type");
+        if (null != contentType && !"".equals(contentType.trim())) {
+            this.contentType = contentType;
+        }
+
+        String status = jsonObject.getString("status");
+        if (null != status && !"".equals(status.trim())) {
+            this.status = status;
+        }
+
+        Float userRate = jsonObject.getFloat("user_rate");
+        this.userRate = userRate;
+    }
+
+
+}

+ 13 - 0
jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/advertise/entity/ByteDanceGeneralCopywriter.java

@@ -67,5 +67,18 @@ public class ByteDanceGeneralCopywriter {
 
 	}
 
+	public ByteDanceGeneralCopywriter(Long accountId, String textCopywriter, String creativeWordIds){
+		if (!Check.isNull(accountId)) {
+			this.accountId = accountId;
+		}
+
+		if(!Check.isNull(textCopywriter)){
+			this.textCopywriter = textCopywriter;
+		}
+
+		if(!Check.isNull(creativeWordIds)){
+			this.creativeWordIds = creativeWordIds;
+		}
+	}
 
 }

+ 5 - 0
jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/advertise/entity/ByteDanceVideoInfo.java

@@ -80,6 +80,11 @@ public class ByteDanceVideoInfo {
     private String filename;
     private Integer type;
 
+
+    //素材类型  video-视频;image-图片
+    private String materialType;
+
+
     public ByteDanceVideoInfo(JSONObject data, CtopOauthToken token) {
         this.id = data.getString("id")+token.getAccountId();
         this.vid = data.getString("id");

+ 27 - 0
jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/advertise/entity/BytedanceMaterialRejectReason.java

@@ -0,0 +1,27 @@
+package org.jeecg.modules.bytedance.advertise.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+
+import java.util.Date;
+@Data
+@TableName("ctop_bytedance_material_reject_reason")
+public class BytedanceMaterialRejectReason {
+    private String videoId;
+
+    private String imageId;
+
+    private String title;
+
+    private String rejectReason;
+
+    private Integer isLowQuality;
+
+    private Date createTime;
+
+    private Long accountId;
+
+    private Long adId;
+}

+ 22 - 0
jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/advertise/entity/BytedancePlanRejectReason.java

@@ -0,0 +1,22 @@
+package org.jeecg.modules.bytedance.advertise.entity;
+
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+
+import java.util.Date;
+@Data
+@TableName("ctop_bytedance_plan_reject_reason")
+public class BytedancePlanRejectReason {
+    private Long adId;
+
+    private String rejectItem;
+
+    private String rejectReason;
+
+    private Integer isLowQuality;
+
+    private Date createTime;
+
+    private Long accountId;
+
+}

+ 21 - 1
jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/advertise/entity/BytedanceVideoSlogenInfo.java

@@ -1,11 +1,13 @@
 package org.jeecg.modules.bytedance.advertise.entity;
 
 import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
 import com.baomidou.mybatisplus.annotation.TableId;
 import com.baomidou.mybatisplus.annotation.TableName;
 import lombok.Data;
 
 import java.util.Date;
+import java.util.List;
 
 /**
  * 头条视频文案信息
@@ -22,8 +24,14 @@ public class BytedanceVideoSlogenInfo {
 	private Long id;
 	/**videoCode*/
 	private String videoCode;
+	@TableField(exist=false)
+	private String materialName;
+	@TableField(exist=false)
+	private List<String> materialNameArray;
 	/**slogan*/
 	private String slogan;
+	@TableField(exist=false)
+	private String newSlogan;
 	/**createTime*/
 	private Date createTime;
 	/**updateTime*/
@@ -35,7 +43,7 @@ public class BytedanceVideoSlogenInfo {
 	/**status*/
 	private Integer status;
 	private String creativeWordIds;
-
+	private Long projectId;
 	public BytedanceVideoSlogenInfo(String videoCode, String slogan, String userId) {
 		this.videoCode = videoCode;
 		this.slogan = slogan;
@@ -57,6 +65,18 @@ public class BytedanceVideoSlogenInfo {
 		this.creativeWordIds = creativeWordIds;
 	}
 
+	public BytedanceVideoSlogenInfo(Long projectId, String videoCode, String slogan, String userId, String creativeWordIds) {
+		this.videoCode = videoCode;
+		this.slogan = slogan;
+		this.createBy = userId;
+		this.updateBy = userId;
+		this.createTime = new Date();
+		this.updateTime = new Date();
+		this.status = 1;
+		this.creativeWordIds = creativeWordIds;
+		this.projectId = projectId;
+	}
+
 	public BytedanceVideoSlogenInfo() {
 	}
 }

+ 19 - 0
jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/advertise/entity/LowQualityRejectReason.java

@@ -0,0 +1,19 @@
+package org.jeecg.modules.bytedance.advertise.entity;
+
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+
+import java.util.Date;
+
+
+@Data
+@TableName("ctop_low_quality_reject_reason")
+public class LowQualityRejectReason {
+    private Integer id;
+
+    private String auditRejectReason;
+
+    private Integer status;
+
+    private Date createTime;
+}

+ 43 - 1
jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/advertise/enums/BytedanceCreativeMatTypeEnum.java

@@ -8,7 +8,20 @@ public enum BytedanceCreativeMatTypeEnum {
     BYTEDANCE_CREATIVE_MAT_TYPE_ENUM_NEW("1","上新",0L,0L),
     BYTEDANCE_CREATIVE_MAT_TYPE_ENUM_HIGH_QUALITY("2","高质量",-4*60*24L,-1*60*24L),
     BYTEDANCE_CREATIVE_MAT_TYPE_ENUM_MISSING("3","遗漏",-8*60*24L,-1*60*24L),
-    BYTEDANCE_CREATIVE_MAT_TYPE_ENUM_HISTORY("4","打捞",-8*60*24L,-1*60*24L);
+    BYTEDANCE_CREATIVE_MAT_TYPE_ENUM_HISTORY("4","打捞",-8*60*24L,-1*60*24L),
+
+
+
+
+    BYTEDANCE_CREATIVE_IMAGE_MODE_LARGE("CREATIVE_IMAGE_MODE_LARGE","1","大图横图"),
+    BYTEDANCE_CREATIVE_IMAGE_MODE_LARGE_VERTICAL("CREATIVE_IMAGE_MODE_LARGE_VERTICAL","2","大图竖图"),
+    BYTEDANCE_CREATIVE_IMAGE_MODE_UNION_SPLASH("CREATIVE_IMAGE_MODE_UNION_SPLASH","3","开屏"),
+    BYTEDANCE_CREATIVE_IMAGE_MODE_VIDEO("CREATIVE_IMAGE_MODE_VIDEO","1","横版视频"),
+    BYTEDANCE_CREATIVE_IMAGE_MODE_VIDEO_VERTICAL("CREATIVE_IMAGE_MODE_VIDEO_VERTICAL","2","竖版视频");
+
+
+
+
 
     /**
      * 类型
@@ -24,6 +37,8 @@ public enum BytedanceCreativeMatTypeEnum {
     private Long videoGetStartTime;
     private Long videoGetEndTime;
 
+    private String imageMode;
+
     BytedanceCreativeMatTypeEnum(String type, String name,Long videoGetStartTime,Long videoGetEndTime) {
         this.type = type;
         this.name = name;
@@ -89,4 +104,31 @@ public enum BytedanceCreativeMatTypeEnum {
     public void setVideoGetEndTime(Long videoGetEndTime) {
         this.videoGetEndTime = videoGetEndTime;
     }
+
+
+    public String getImageMode() {
+        return imageMode;
+    }
+
+    public void setImageMode(String imageMode) {
+        this.imageMode = imageMode;
+    }
+
+
+    BytedanceCreativeMatTypeEnum(String type, String name,String imageMode) {
+        this.type = type;
+        this.name = name;
+        this.imageMode = imageMode;
+    }
+
+
+    public static String getImageModeByType(String type) {
+        for (BytedanceCreativeMatTypeEnum createTypeEnum : BytedanceCreativeMatTypeEnum.values()) {
+            if (createTypeEnum.getType().equals(type)) {
+                return createTypeEnum.getImageMode();
+            }
+        }
+        return "";
+    }
+
 }

+ 1 - 1
jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/advertise/mapper/AiBytedanceAdvertiserStrategyMapper.java

@@ -14,7 +14,7 @@ import org.jeecg.modules.bytedance.advertise.entity.UpdAdStaOrCpaOrBudget;
 public interface AiBytedanceAdvertiserStrategyMapper extends BaseMapper<AiBytedanceAdvertiserStrategy> {
 
 
-    Integer updStaByAccountId(@Param("accountId") String accountId,@Param("state") String state,@Param("id") String id);
+    Integer updStaByAccountId(@Param("accountId") String accountId,@Param("creativeImageMode")String creativeImageMode,@Param("state") String state,@Param("id") String id);
 
     Integer updStaById(@Param("id") String id,@Param("state") String state);
 

+ 17 - 0
jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/advertise/mapper/AiBytedanceAutocreateLogMapper.java

@@ -0,0 +1,17 @@
+package org.jeecg.modules.bytedance.advertise.mapper;
+
+import java.util.List;
+
+import org.apache.ibatis.annotations.Param;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.jeecg.modules.bytedance.advertise.entity.AiBytedanceAutocreateLog;
+
+/**
+ * 自动创建计划日志
+ * @author jeecg-boot
+ * 2021-07-05
+ * @version V1.0
+ */
+public interface AiBytedanceAutocreateLogMapper extends BaseMapper<AiBytedanceAutocreateLog> {
+
+}

+ 13 - 4
jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/advertise/mapper/ByteDanceGeneralCopywriterMapper.java

@@ -1,11 +1,13 @@
 package org.jeecg.modules.bytedance.advertise.mapper;
 
-import java.util.List;
-import java.util.Map;
-
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Param;
+import org.jeecg.modules.bytedance.advertise.entity.ByteDanceCreativeWordPackage;
 import org.jeecg.modules.bytedance.advertise.entity.ByteDanceGeneralCopywriter;
 
+import java.util.List;
+import java.util.Map;
+
 /**
  * 通用文案库
  * @author jeecg-boot
@@ -13,5 +15,12 @@ import org.jeecg.modules.bytedance.advertise.entity.ByteDanceGeneralCopywriter;
  * @version V1.0
  */
 public interface ByteDanceGeneralCopywriterMapper extends BaseMapper<ByteDanceGeneralCopywriter> {
-    List<Map<String,Object>> selectGeneralCopywriterReport(String accountId, String keyWord, String startTime, String endTime);
+    List<Map<String,Object>> selectGeneralCopywriterReport(List<String> accountIds, String keyWord, Integer status, String startTime, String endTime);
+
+    ByteDanceCreativeWordPackage selectCreativeWordPackageByName(String name);
+
+    List<ByteDanceGeneralCopywriter> getRandThree(@Param(value = "accountId") Long accountId);
+    List<ByteDanceGeneralCopywriter> getRandTen(@Param(value = "accountId") Long accountId);
+
+    List<ByteDanceGeneralCopywriter> selectAllDataByTextCopywriter(@Param(value = "textCopywriter") String textCopywriter);
 }

+ 23 - 3
jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/advertise/mapper/ByteDanceVideoInfoMapper.java

@@ -25,9 +25,29 @@ public interface ByteDanceVideoInfoMapper extends BaseMapper<ByteDanceVideoInfo>
      * @param videoCnt
      * @return
      */
-    List<ByteDanceVideoInfo> getNewVideoByParams(@Param(value = "projectId") Long projectId,@Param(value = "accountId") Long accountId, @Param(value = "startTime")String startTime, @Param(value = "endTime")String endTime, @Param(value = "videoCnt")Long videoCnt,@Param(value = "creativeCnt")Long creativeCnt,@Param(value = "now") String now);
+    List<ByteDanceVideoInfo> getNewVideoByParams(@Param(value = "projectId") Long projectId,@Param(value = "accountId") Long accountId, @Param(value = "imageMode") String imageMode,@Param(value = "startTime")String startTime, @Param(value = "endTime")String endTime, @Param(value = "videoCnt")Long videoCnt,@Param(value = "creativeCnt")Long creativeCnt,@Param(value = "now") String now);
+
+    List<ByteDanceVideoInfo> topMatByParams(@Param(value = "projectId")Long projectId, @Param(value = "accountId")Long accountId, @Param(value = "imageMode") String imageMode,@Param(value = "startTime")String startTime, @Param(value = "endTime")String endTime, @Param(value = "videoCnt")Long videoCnt,@Param(value = "now") String now);
+
+    List<ByteDanceVideoInfo>historyMatByParams(@Param(value = "projectId")Long projectId, @Param(value = "accountId")Long accountId, @Param(value = "imageMode") String imageMode,@Param(value = "startTime")String startTime, @Param(value = "endTime")String endTime, @Param(value = "videoCnt")Long videoCnt,@Param(value = "now") String now);
+
+
+    /**
+     *图片 上新 遗漏
+     */
+    List<ByteDanceVideoInfo> imageListByParams(@Param(value = "projectId") Long projectId,@Param(value = "accountId") Long accountId, @Param(value = "imageMode") String imageMode,@Param(value = "startTime")String startTime, @Param(value = "endTime")String endTime, @Param(value = "videoCnt")Long videoCnt,@Param(value = "creativeCnt")Long creativeCnt,@Param(value = "now") String now);
+
+    /**
+     * 图片 跑量
+     */
+    List<ByteDanceVideoInfo> imageTopMatByParams(@Param(value = "projectId")Long projectId, @Param(value = "accountId")Long accountId, @Param(value = "imageMode") String imageMode,@Param(value = "startTime")String startTime, @Param(value = "endTime")String endTime, @Param(value = "videoCnt")Long videoCnt,@Param(value = "now") String now);
+
+    /**
+     * 图片 打捞
+     */
+    List<ByteDanceVideoInfo>imageHistoryMatByParams(@Param(value = "projectId")Long projectId, @Param(value = "accountId")Long accountId, @Param(value = "imageMode") String imageMode,@Param(value = "startTime")String startTime, @Param(value = "endTime")String endTime, @Param(value = "videoCnt")Long videoCnt,@Param(value = "now") String now);
+
+
 
-    List<ByteDanceVideoInfo> topMatByParams(@Param(value = "projectId")Long projectId, @Param(value = "accountId")Long accountId, @Param(value = "startTime")String startTime, @Param(value = "endTime")String endTime, @Param(value = "videoCnt")Long videoCnt,@Param(value = "now") String now);
 
-    List<ByteDanceVideoInfo>historyMatByParams(@Param(value = "projectId")Long projectId, @Param(value = "accountId")Long accountId, @Param(value = "startTime")String startTime, @Param(value = "endTime")String endTime, @Param(value = "videoCnt")Long videoCnt,@Param(value = "now") String now);
 }

+ 17 - 0
jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/advertise/mapper/BytedanceMaterialRejectReasonMapper.java

@@ -0,0 +1,17 @@
+package org.jeecg.modules.bytedance.advertise.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.jeecg.modules.bytedance.advertise.entity.BytedanceMaterialRejectReason;
+
+
+/**
+ * 头条视频文案信息
+ * @author jeecg-boot
+ * 2021-04-19
+ * @version V1.0
+ */
+public interface BytedanceMaterialRejectReasonMapper extends BaseMapper<BytedanceMaterialRejectReason> {
+    int replaceIntoDb(BytedanceMaterialRejectReason bytedanceMaterialRejectReason);
+
+    Integer getIsLowQualityByVideoId(String video);
+}

+ 14 - 0
jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/advertise/mapper/BytedancePlanRejectReasonMapper.java

@@ -0,0 +1,14 @@
+package org.jeecg.modules.bytedance.advertise.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.jeecg.modules.bytedance.advertise.entity.BytedancePlanRejectReason;
+
+/**
+ * 头条视频文案信息
+ * @author jeecg-boot
+ * 2021-04-19
+ * @version V1.0
+ */
+public interface BytedancePlanRejectReasonMapper extends BaseMapper<BytedancePlanRejectReason> {
+    int replaceIntoDb(BytedancePlanRejectReason bytedancePlanRejectReason);
+}

+ 5 - 1
jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/advertise/mapper/BytedanceVideoSlogenInfoMapper.java

@@ -1,6 +1,7 @@
 package org.jeecg.modules.bytedance.advertise.mapper;
 
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import io.swagger.models.auth.In;
 import org.jeecg.modules.bytedance.advertise.entity.BytedanceVideoSlogenInfo;
 
 import java.util.List;
@@ -13,5 +14,8 @@ import java.util.Map;
  * @version V1.0
  */
 public interface BytedanceVideoSlogenInfoMapper extends BaseMapper<BytedanceVideoSlogenInfo> {
-    List<Map<String,Object>> selectVideoSlogenReportByAccountIdAndTitle(String accountId, String keyWord, String startTime, String endTime);
+    List<Map<String,Object>> selectVideoSlogenReportByAccountIdAndTitle(List<String> projectIds, String keyWord, Integer status, String startTime, String endTime);
+    List<String> getProjectByUserId(String userId);
+
+    List<BytedanceVideoSlogenInfo> getDataBySlogenAndProjectId(String slogan, Long projectId);
 }

+ 15 - 0
jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/advertise/mapper/LowQualityRejectReasonMapper.java

@@ -0,0 +1,15 @@
+package org.jeecg.modules.bytedance.advertise.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.jeecg.modules.bytedance.advertise.entity.LowQualityRejectReason;
+
+
+/**
+ * 头条视频文案信息
+ * @author jeecg-boot
+ * 2021-04-19
+ * @version V1.0
+ */
+public interface LowQualityRejectReasonMapper extends BaseMapper<LowQualityRejectReason> {
+    LowQualityRejectReason getByRejectReason(String rejectReason);
+}

+ 3 - 0
jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/advertise/mapper/xml/AiBytedanceAdvertiserStrategyMapper.xml

@@ -10,6 +10,9 @@
         <if test="accountId !=null and accountId != ''">
             AND account_id = #{accountId}
         </if>
+        <if test="creativeImageMode !=null and creativeImageMode != ''">
+            AND creative_image_mode = #{creativeImageMode}
+        </if>
         <if test="id !=null and id != ''">
             AND id != #{id}
         </if>

+ 5 - 0
jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/advertise/mapper/xml/AiBytedanceAutocreateLogMapper.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.jeecg.modules.bytedance.advertise.mapper.AiBytedanceAutocreateLogMapper">
+
+</mapper>

+ 12 - 0
jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/advertise/mapper/xml/ByteDanceAdvertisePlanMapper.xml

@@ -42,6 +42,18 @@
             <if test="bid != null">
                 bid = #{bid},
             </if>
+            <if test="cpaBid != null and cpaBid!=''">
+                cpa_bid = #{cpaBid},
+            </if>
+            <if test="scheduleTime != null and scheduleTime!=''">
+                schedule_time = #{scheduleTime},
+            </if>
+            <if test="budgetMode != null and budgetMode!=''">
+                budget_mode = #{budgetMode},
+            </if>
+            <if test="budget != null and budget!=''">
+                budget = #{budget},
+            </if>
         </set>
         where id = #{id}
     </update>

+ 41 - 10
jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/advertise/mapper/xml/ByteDanceGeneralCopywriterMapper.xml

@@ -2,27 +2,58 @@
 <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
 <mapper namespace="org.jeecg.modules.bytedance.advertise.mapper.ByteDanceGeneralCopywriterMapper">
     <select id="selectGeneralCopywriterReport" resultType="java.util.HashMap">
+
+
+
+
         SELECT
-            b.account_id,
-            d.creative_id,
-            a.text_copywriter,
-            count(*) AS creative_count,
-            sum(d.cost) AS sum_cost,
-            sum(d.show_num) AS sum_show_material,
-            sum(d.click) AS sum_click,
-            sum(d.show_num) AS sum_convert_material
+            a.id,
+            a.status,
+            a.account_id as accountId,
+            d.creative_id as creativeId,
+            a.text_copywriter AS textCopywriter,
+            count(*) AS creativeCount,
+            sum(d.cost) AS sumCost,
+            sum(d.show_num) AS sumShowMaterial,
+            sum(d.click) AS sumClick,
+            sum(d.show_num) AS sumConvertMaterial
         FROM
             ctop_bytedance_general_copywriter a
         LEFT JOIN ctop_bytedance_creative b ON a.text_copywriter = b.title and a.account_id = b.account_id
         LEFT JOIN ctop_bytedance_report_creative_daily d ON b.id = d.creative_id
         WHERE
-            b.account_id = #{accountId}
+            1 = 1
+            <if test="status!=null">and a.`status` = #{status}</if>
             <if test="keyWord!=null and keyWord!=''">and a.text_copywriter like concat('%',#{keyWord},'%')</if>
             <if test="startTime!=null and startTime!=''">and STR_TO_DATE(d.stat_datetime,'%Y-%m-%d') &gt;= STR_TO_DATE(#{startTime},'%Y-%m-%d')</if>
             <if test="endTime!=null and endTime!=''">and STR_TO_DATE(d.stat_datetime,'%Y-%m-%d') &lt;= STR_TO_DATE(#{endTime},'%Y-%m-%d')</if>
-            AND a.`status` = 0
+        <if test="accountIds!=null and accountIds!=''">
+            AND a.account_id IN
+            <foreach item="item" index="index" collection="accountIds"
+                     open="(" separator="," close=")">
+                #{item}
+            </foreach>
+        </if>
         GROUP BY
         a.text_copywriter
 
     </select>
+
+    <select id="selectCreativeWordPackageByName" resultType="org.jeecg.modules.bytedance.advertise.entity.ByteDanceCreativeWordPackage">
+        select * from ctop_bytedance_creative_word_package where name = #{name}
+    </select>
+    <select id="getRandThree"
+            resultType="org.jeecg.modules.bytedance.advertise.entity.ByteDanceGeneralCopywriter">
+        select * from ctop_bytedance_general_copywriter where status = 1 and account_id = #{accountId} order by rand() limit 3
+    </select>
+
+    <select id="getRandTen"
+            resultType="org.jeecg.modules.bytedance.advertise.entity.ByteDanceGeneralCopywriter">
+        select * from ctop_bytedance_general_copywriter where status = 1 and account_id = #{accountId} order by rand() limit 10
+    </select>
+
+    <select id="selectAllDataByTextCopywriter" resultType="org.jeecg.modules.bytedance.advertise.entity.ByteDanceGeneralCopywriter">
+        select * from ctop_bytedance_general_copywriter where text_copywriter = #{textCopywriter}
+
+    </select>
 </mapper>

+ 126 - 5
jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/advertise/mapper/xml/ByteDanceVideoInfoMapper.xml

@@ -71,12 +71,15 @@
         select distinct video.*,
         (select count(1) from ctop_bytedance_ai_video_creative_log l where l.video_code = video.signature and l.account_id = video.account_id and l.state_date = #{now}) as creativeNum,
         (select count(1) from ctop_bytedance_creative c where c.video_id = video.vid and c.account_id = '${accountId}') as creativeCnt,
-        (select count(1) from ctop_bytedance_video_slogen_info s where s.video_code = video.signature) as slogens
+        (select count(1) from ctop_bytedance_video_slogen_info s where s.video_code = video.signature) as slogens,
+         'video' As materialType
         from ctop_bytedance_video_info video
         left join ctop_material_info cmi on video.signature = cmi.code and cmi.project_id = #{projectId}
         where account_id = #{accountId}
         and cmi.code is not null
+        and cmi.status = 1
         and cmi.offline_flag = 0
+        and video.type = #{imageMode}
         and material_upload_time &gt;= #{startTime}
         and material_upload_time &lt;= #{endTime}
         having creativeCnt &lt;= #{creativeCnt} and slogens >0 and creativeNum = 0
@@ -88,7 +91,8 @@
         a.totalCost,
         (select count(1) from ctop_bytedance_ai_video_creative_log l where l.video_code = video.signature and l.account_id = video.account_id and l.state_date = #{now}) as creativeNum,
         (select count(1) from ctop_bytedance_creative c where c.video_id = video.vid and c.account_id = '${accountId}') as creativeCnt,
-        (select count(1) from ctop_bytedance_video_slogen_info s where s.video_code = video.signature ) as slogens
+        (select count(1) from ctop_bytedance_video_slogen_info s where s.video_code = video.signature ) as slogens,
+         'video' As materialType
         from (select report.material_id, sum(cost) as totalCost
         from ctop_bytedance_report_material_daily report
         left join ctop_user_allocation cua on report.account_id = cua.account_id
@@ -97,7 +101,7 @@
         and report.stat_datetime &lt;= #{endTime}
         group by report.material_id
         order by sum(report.cost) desc ) a
-        left join (select distinct a.* from ctop_bytedance_video_info a where a.account_id = #{accountId})as video
+        left join (select distinct a.* from ctop_bytedance_video_info a where a.account_id = #{accountId} and a.type = #{imageMode})as video
         on a.material_id = video.material_id
         left join ctop_material_info cmi on cmi.code = video.signature and cmi.project_id = #{projectId}
         where cmi.id is not null
@@ -116,7 +120,8 @@
                a.totalCost,
                (select count(1) from ctop_bytedance_ai_video_creative_log l where l.video_code = video.signature and l.account_id = video.account_id and l.state_date = #{now}) as creativeNum,
                (select count(1) from ctop_bytedance_creative c where c.video_id = video.vid and c.account_id = '${accountId}') as creativeCnt,
-               (select count(1) from ctop_bytedance_video_slogen_info s where s.video_code = video.signature) as slogens
+               (select count(1) from ctop_bytedance_video_slogen_info s where s.video_code = video.signature) as slogens,
+               'video' As materialType
         from (select report.material_id, sum(cost) as totalCost
               from ctop_bytedance_report_material_daily report
                        left join ctop_user_allocation cua on report.account_id = cua.account_id
@@ -125,7 +130,7 @@
                 and report.stat_datetime &lt;= #{endTime}
               group by report.material_id
               order by sum(report.cost) desc ) a
-                 left join (select distinct a.* from ctop_bytedance_video_info a where a.account_id = #{accountId})as video
+                 left join (select distinct a.* from ctop_bytedance_video_info a where a.account_id = #{accountId} and a.type = #{imageMode})as video
                            on a.material_id = video.material_id
                  left join ctop_material_info cmi on cmi.code = video.signature and cmi.project_id = #{projectId}
         where cmi.id is not null
@@ -138,4 +143,120 @@
         order by a.material_id desc
             limit #{videoCnt}
     </select>
+
+
+    <!-- 图片 上新 遗漏 -->
+    <select id="imageListByParams" resultType="org.jeecg.modules.bytedance.advertise.entity.ByteDanceVideoInfo">
+        select distinct image.*,
+        (select count(1) from ctop_bytedance_ai_video_creative_log l
+        where l.video_code = image.signature
+        and l.account_id = image.account_id
+        and l.state_date = #{now}) as creativeNum,
+        (select count(1) from ctop_bytedance_creative c
+        where SUBSTRING_INDEX(SUBSTRING_INDEX(image_ids,'["',-1),'"]',1) in(image.id)
+        and c.account_id = '${accountId}') as creativeCnt,
+        'image' as materialType
+        from ctop_bytedance_image_info image
+        where account_id = #{accountId}
+        <if test="imageMode == '1'.toString()">
+            and image.type = '1'
+        </if>
+        <if test="imageMode == '2'.toString()">
+            and (image.type = '2' or image.type = '3')
+        </if>
+        <if test="imageMode == '3'.toString()">
+            and image.type = '3'
+        </if>
+        and image.image_create_time &gt;= #{startTime}
+        and image.image_create_time &lt;= #{endTime}
+        having creativeCnt &lt;= #{creativeCnt}
+        and creativeNum = 0
+        order by image.image_create_time desc
+            limit #{videoCnt}
+    </select>
+
+
+    <!-- 图片 跑量-->
+    <select id="imageTopMatByParams" resultType="org.jeecg.modules.bytedance.advertise.entity.ByteDanceVideoInfo">
+        select distinct image.*,
+        a.totalCost,
+        (select count(1) from ctop_bytedance_ai_video_creative_log l
+        where l.video_code = image.signature
+        and l.account_id = image.account_id
+        and l.state_date =#{now}) as creativeNum,
+        (select count(1)
+        from ctop_bytedance_creative c
+        where SUBSTRING_INDEX(SUBSTRING_INDEX(image_ids,'["',-1),'"]',1) in(image.id)
+        and c.account_id = '${accountId}')  as creativeCnt
+        from (select report.material_id, sum(cost) as totalCost,
+         'image' as materialType
+        from ctop_bytedance_report_image_daily report
+        left join ctop_user_allocation cua on report.account_id = cua.account_id
+        where cua.project_id = #{projectId}
+        and report.stat_datetime &gt;= #{startTime}
+        and report.stat_datetime &lt;= #{endTime}
+        group by report.material_id
+        order by sum(report.cost) desc ) a
+        left join (select distinct a.* from ctop_bytedance_image_info a where 1 = 1  and a.account_id = #{accountId}
+        <if test="imageMode == '1'.toString()">
+            and a.type = '1'
+        </if>
+        <if test="imageMode == '2'.toString()">
+            and (a.type = '2' or a.type = '3')
+        </if>
+        <if test="imageMode == '3'.toString()">
+            and a.type = '3'
+        </if>)as image
+        on a.material_id = image.material_id
+        where 1=1
+        and a.totalCost &gt; 500
+        having creativeCnt &lt;= 100
+        and creativeNum = 0
+        order by a.material_id desc
+            limit #{videoCnt}
+    </select>
+
+
+    <!-- 图片 打捞-->
+    <select id="imageHistoryMatByParams" resultType="org.jeecg.modules.bytedance.advertise.entity.ByteDanceVideoInfo">
+        select distinct image.*,
+        a.totalCost,
+        (select count(1)
+        from ctop_bytedance_ai_video_creative_log l
+        where l.video_code = image.signature
+        and l.account_id = image.account_id
+        and l.state_date = #{now}) as creativeNum,
+        (select count(1)
+        from ctop_bytedance_creative c
+        where SUBSTRING_INDEX(SUBSTRING_INDEX(image_ids,'["',-1),'"]',1) in(image.id)
+        and c.account_id = '${accountId}') as creativeCnt
+        from (select report.material_id, sum(cost) as totalCost,
+        'image' as materialType
+        from ctop_bytedance_report_image_daily report
+        left join ctop_user_allocation cua on report.account_id = cua.account_id
+        where cua.project_id = #{projectId}
+        and report.stat_datetime &gt;= #{startTime}
+        and report.stat_datetime &lt;= #{endTime}
+        group by report.material_id
+        order by sum(report.cost) desc) a
+        left join (select distinct a.* from ctop_bytedance_image_info a where 1 = 1 and a.account_id =#{accountId}
+        <if test="imageMode == '1'.toString()">
+            and a.type = '1'
+        </if>
+        <if test="imageMode == '2'.toString()">
+            and (a.type = '2' or a.type = '3')
+        </if>
+        <if test="imageMode == '3'.toString()">
+            and a.type = '3'
+        </if>) as image
+        on a.material_id = image.material_id
+        where 1=1
+        and a.totalCost &lt;= 100
+        having creativeCnt &lt; 20
+        and creativeNum = 0
+        order by a.material_id desc
+            limit #{videoCnt}
+    </select>
+
+
 </mapper>

+ 12 - 0
jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/advertise/mapper/xml/BytedanceMaterialRejectReasonMapper.xml

@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.jeecg.modules.bytedance.advertise.mapper.BytedanceMaterialRejectReasonMapper">
+<insert id="replaceIntoDb" parameterType="org.jeecg.modules.bytedance.advertise.entity.BytedanceMaterialRejectReason">
+    replace into ctop_bytedance_material_reject_reason (reject_reason,image_id,video_id,title,is_low_quality,account_id,ad_id) values (#{rejectReason},#{imageId},#{videoId},#{title},#{isLowQuality},#{accountId},#{adId})
+</insert>
+
+    <select id="getIsLowQualityByVideoId" resultType="integer">
+        select distinct is_low_quality from ctop_bytedance_material_reject_reason where video_id = #{videoId} limit 1
+    </select>
+
+</mapper>

+ 9 - 0
jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/advertise/mapper/xml/BytedancePlanRejectReasonMapper.xml

@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.jeecg.modules.bytedance.advertise.mapper.BytedancePlanRejectReasonMapper">
+
+<insert id="replaceIntoDb" parameterType="org.jeecg.modules.bytedance.advertise.entity.BytedancePlanRejectReason">
+    replace into ctop_bytedance_plan_reject_reason (ad_id,reject_item,reject_reason,is_low_quality,account_id) values (#{adId},#{rejectItem},#{rejectReason},#{isLowQuality},#{accountId})
+
+</insert>
+</mapper>

+ 109 - 18
jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/advertise/mapper/xml/BytedanceVideoSlogenInfoMapper.xml

@@ -4,8 +4,10 @@
     <select id="selectVideoSlogenReportByAccountIdAndTitle" resultType="java.util.HashMap">
 
         SELECT
-            b.account_id as accountId,
-            a.slogan ,
+            a.id,
+            a.status,
+            a.slogan,
+            a.project_id AS projectId,
             count(*) AS count,
             sum(d.cost) AS cost,
             sum(d.show_num) AS showNum,
@@ -14,26 +16,115 @@
         FROM
             ctop_bytedance_video_slogen_info a
         LEFT JOIN (
-            SELECT
-                t1.id,
-                t1.title,
-                t2.signature,
-                t1.account_id
-            FROM
-                ctop_bytedance_creative t1
-            LEFT JOIN ctop_bytedance_video_info t2 ON t1.video_id = t2.vid AND t1.account_id = t2.account_id
-            where t1.account_id = #{accountId}
-        ) b ON a.slogan = b.title AND a.video_code = b.signature
+        SELECT
+            t1.id,
+            t1.title,
+            t2.signature,
+            t1.account_id
+        FROM
+        (
+        SELECT
+            cbc.*
+        FROM
+            ctop_bytedance_creative cbc
+        WHERE
+        account_id IN (
+        SELECT
+        CONCAT(
+        ctop_user_allocation.account_id,
+        ''
+        )
+        FROM
+        ctop_user_allocation
+        WHERE
+        1=1
+        <if test="projectIds!=null">
+            AND project_id IN
+            <foreach item="item" index="index" collection="projectIds"
+                     open="(" separator="," close=")">
+                #{item}
+            </foreach>
+        </if>
+        )
+        ) t1
+        LEFT JOIN (
+        SELECT
+        cbvi.*
+        FROM
+        ctop_bytedance_video_info cbvi
+        WHERE
+        account_id IN (
+        SELECT
+        ctop_user_allocation.account_id
+        FROM
+        ctop_user_allocation
+        WHERE
+        1=1
+        <if test="projectIds!=null">
+            AND project_id IN
+            <foreach item="item" index="index" collection="projectIds"
+                     open="(" separator="," close=")">
+                #{item}
+            </foreach>
+        </if>
+        )
+        ) t2 ON t1.video_id = t2.vid
+        AND t1.account_id = t2.account_id
+        LEFT JOIN ctop_user_allocation cua ON cua.account_id = t1.account_id
+        WHERE
+        1=1
+        <if test="projectIds!=null">
+            AND cua.project_id IN
+            <foreach item="item" index="index" collection="projectIds"
+                     open="(" separator="," close=")">
+                #{item}
+            </foreach>
+        </if>
+        ) b ON a.slogan = b.title
+        AND a.video_code = b.signature
         LEFT JOIN ctop_bytedance_report_creative_daily d ON b.id = d.creative_id
         WHERE
-            b.account_id = #{accountId}
-            <if test="keyWord!=null and keyWord!=''">and a.slogan like concat('%',#{keyWord},'%')</if>
-            <if test="startTime!=null and startTime!=''">and STR_TO_DATE(d.stat_datetime,'%Y-%m-%d') &gt;= STR_TO_DATE(#{startTime},'%Y-%m-%d')</if>
-            <if test="endTime!=null and endTime!=''">and STR_TO_DATE(d.stat_datetime,'%Y-%m-%d') &lt;= STR_TO_DATE(#{endTime},'%Y-%m-%d')</if>
-        AND a.`status` = 1
+        1=1
+        <if test="status!=null">and a.status = #{status}</if>
+        <if test="keyWord!=null and keyWord!=''">and a.slogan like concat('%',#{keyWord},'%')</if>
+        <if test="startTime!=null and startTime != ''">and STR_TO_DATE(d.stat_datetime,'%Y-%m-%d') &gt;=
+            STR_TO_DATE(#{startTime},'%Y-%m-%d')
+        </if>
+        <if test="endTime!=null and endTime!=''">and STR_TO_DATE(d.stat_datetime,'%Y-%m-%d') &lt;=
+            STR_TO_DATE(#{endTime},'%Y-%m-%d')
+        </if>
+        <if test="projectIds!=null">
+            AND a.project_id IN
+            <foreach item="item" index="index" collection="projectIds"
+                     open="(" separator="," close=")">
+                #{item}
+            </foreach>
+        </if>
+
         GROUP BY
-            a.slogan
+        a.slogan
+
+
+    </select>
+
+    <select id="getProjectByUserId" resultType="java.lang.String">
+        select
+            project.id
+        from
+            ctop_project_member member left join ctop_project project on project.id = member.project_id
+        where
+            member.user_id = #{userId}
+    </select>
 
 
+    <select id="getDataBySlogenAndProjectId" resultType="org.jeecg.modules.bytedance.advertise.entity.BytedanceVideoSlogenInfo">
+    SELECT
+        t1.*,t2.material_name
+    FROM
+        ctop_bytedance_video_slogen_info t1
+    LEFT JOIN ctop_material_info t2 ON t1.video_code = t2.code
+    AND t1.project_id = t2.project_id
+    WHERE
+        slogan =#{slogan} and t1.project_id = #{projectId}
     </select>
 </mapper>

+ 9 - 0
jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/advertise/mapper/xml/LowQualityRejectReasonMapper.xml

@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.jeecg.modules.bytedance.advertise.mapper.LowQualityRejectReasonMapper">
+
+    <select id="getByRejectReason" resultType="org.jeecg.modules.bytedance.advertise.entity.LowQualityRejectReason">
+
+        select * from ctop_low_quality_reject_reason where status = 1 and audit_reject_reason =#{rejectReason}
+    </select>
+</mapper>

+ 19 - 0
jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/advertise/service/BytedanceRejectReasonService.java

@@ -0,0 +1,19 @@
+package org.jeecg.modules.bytedance.advertise.service;
+
+import com.alibaba.fastjson.JSONArray;
+import com.baomidou.mybatisplus.extension.service.IService;
+import org.jeecg.common.api.vo.Result;
+import org.jeecg.modules.bytedance.advertise.entity.BytedanceVideoSlogenInfo;
+
+import java.util.List;
+
+/**
+ * 头条视频文案信息
+ * @author jeecg-boot
+ * 2021-04-19
+ * @version V1.0
+ */
+public interface BytedanceRejectReasonService {
+
+     void saveRejectReasonToDb(JSONArray jsonArray,Long accountId);
+}

+ 2 - 2
jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/advertise/service/IAiBytedanceAdDplinkInfoService.java

@@ -11,7 +11,7 @@ import org.jeecg.modules.bytedance.advertise.entity.AiBytedanceAdDplinkInfo;
  */
 public interface IAiBytedanceAdDplinkInfoService extends IService<AiBytedanceAdDplinkInfo> {
 
-    AiBytedanceAdDplinkInfo getlatestDpLinkInfo(Long strategyId, Long accountId, Integer status);
+    AiBytedanceAdDplinkInfo getlatestDpLinkInfo(Long strategyId, Long accountId,String imageMode,Integer status);
 
-    int getDpLinkInfoCount(Long accountId);
+    int getDpLinkInfoCount(Long accountId,String imageMode);
 }

+ 7 - 3
jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/advertise/service/IAiBytedanceAdvertiserStrategyService.java

@@ -28,14 +28,14 @@ public interface IAiBytedanceAdvertiserStrategyService extends IService<AiByteda
     Result updateADCreative(AiBytedanceAdvertiserStrategy strategy,String groupModifyTime,String planModifyTime);
 
 
-    Long createCreative(AiBytedanceAdvertiserStrategy strategy, Integer createType, Long videoCnt, String openUrl);
+    Long createCreative(CtopOauthToken token, AiBytedanceAdvertiserStrategy strategy, Integer createType, Long videoCnt, String openUrl);
 
     /**
      * 头条 - 配置信息 修改 状态
      * @param
      * @return
      */
-    Result updStaById(String id,String state,String accountId);
+    Result updStaById(String id,String state,String accountId,String creativeImageMode);
 
     /**
      * 头条 - 配置信息 修改 出价; 预算;
@@ -96,7 +96,7 @@ public interface IAiBytedanceAdvertiserStrategyService extends IService<AiByteda
 
     List<AiBytedanceAdvertiserStrategy> getByAccountId(Long accountId,Integer status);
 
-    void customCreativeSupplement(AiBytedanceAdvertiserStrategy strategy, Integer hour,String openUrl);
+    void customCreativeSupplement( AiBytedanceAdvertiserStrategy strategy, Integer hour,String openUrl);
 
     Result getAdActionText(String accountId,String landingType,String advancedCreativeType) throws Exception;
 
@@ -114,6 +114,10 @@ public interface IAiBytedanceAdvertiserStrategyService extends IService<AiByteda
     Result getChengZiSite(String accountId);
 
 
+    /**
+     * 查询 组名称 计划名称
+     */
+    Result getStrategyInfoByName(AiBytedanceAdvertiserStrategy aiBytedanceAdvertiserStrategy);
 
 
 }

+ 14 - 0
jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/advertise/service/IAiBytedanceAutocreateLogService.java

@@ -0,0 +1,14 @@
+package org.jeecg.modules.bytedance.advertise.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import org.jeecg.modules.bytedance.advertise.entity.AiBytedanceAutocreateLog;
+
+/**
+ * 自动创建计划日志
+ * @author jeecg-boot
+ * 2021-07-05
+ * @version V1.0
+ */
+public interface IAiBytedanceAutocreateLogService extends IService<AiBytedanceAutocreateLog> {
+
+}

+ 2 - 0
jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/advertise/service/IByteDanceAdvertisePlanService.java

@@ -37,6 +37,8 @@ public interface IByteDanceAdvertisePlanService extends IService<ByteDanceAdvert
 
     List<ByteDanceAdvertisePlan> getAllPlans(Long accountId,String createDate);
 
+    List<ByteDanceAdvertisePlan> getAllPlansByAccountId(Long accountId,String adModifyTime);
+
     int queryToDayBuiltCount(Long accountId);
 
     Integer updatePlanOrPackage (ByteDanceAdvertisePlan byteDanceAdvertisePlan);

+ 0 - 1
jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/advertise/service/IByteDanceCreativeService.java

@@ -19,7 +19,6 @@ public interface IByteDanceCreativeService extends IService<ByteDanceCreative> {
 
     Map<String, Object> getAdvertiserCreative(CtopOauthToken token, String ids, String date);
 
-
     void replaceBatch(List<ByteDanceCreative> creatives);
 
     Map<String, Object> getCreativeDetail(CtopOauthToken token, Long planId);

+ 8 - 1
jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/advertise/service/IByteDanceGeneralCopywriterService.java

@@ -2,8 +2,11 @@ package org.jeecg.modules.bytedance.advertise.service;
 
 import com.baomidou.mybatisplus.extension.service.IService;
 import org.jeecg.common.api.vo.Result;
+import org.jeecg.modules.bytedance.advertise.entity.ByteDanceCreativeWordPackage;
 import org.jeecg.modules.bytedance.advertise.entity.ByteDanceGeneralCopywriter;
 
+import java.util.List;
+
 /**
  * 通用文案库
  * @author jeecg-boot
@@ -11,5 +14,9 @@ import org.jeecg.modules.bytedance.advertise.entity.ByteDanceGeneralCopywriter;
  * @version V1.0
  */
 public interface IByteDanceGeneralCopywriterService extends IService<ByteDanceGeneralCopywriter> {
-    Result getGeneralCopywriterReport(String accountId, String keyWord, String startTime, String endTime, Integer pageNum, Integer pageSize);
+    Result getGeneralCopywriterReport(String userId, String accountId, String keyWord,Integer status, String startTime, String endTime, Integer pageNum, Integer pageSize);
+
+    public ByteDanceCreativeWordPackage selectCreativeWordPackageByName(String name);
+
+    List<ByteDanceGeneralCopywriter> selectAllDataByTextCopywriter(String textCopywriter);
 }

+ 26 - 3
jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/advertise/service/IByteDanceVideoInfoService.java

@@ -19,9 +19,32 @@ public interface IByteDanceVideoInfoService extends IService<ByteDanceVideoInfo>
 
     void updateMaterialType();
 
-    List<ByteDanceVideoInfo> listByParams(Long projectId,Long accountId, String startTime, String endTime, Long videoCnt,long creativeCnt);
+    List<ByteDanceVideoInfo> listByParams(Long projectId,Long accountId, String imageMode,String startTime, String endTime, Long videoCnt,long creativeCnt);
+
+    List<ByteDanceVideoInfo> topMatByParams(Long projectId, Long accountId, String imageMode,String startTime, String endTime, Long videoCnt);
+
+    List<ByteDanceVideoInfo> historyMatByParams(Long projectId, Long accountId, String imageMode,String startTime, String endTime, Long videoCnt);
+
+
+    /**
+     * 图片 上新 遗漏
+     */
+    List<ByteDanceVideoInfo> imageListByParams(Long projectId,Long accountId, String imageMode,String startTime, String endTime, Long videoCnt,long creativeCnt);
+
+    /**
+     * 图片 跑量
+     */
+    List<ByteDanceVideoInfo> imageTopMatByParams(Long projectId, Long accountId, String imageMode,String startTime, String endTime, Long videoCnt);
+
+    /**
+     * 图片 打捞
+     */
+    List<ByteDanceVideoInfo> imageHistoryMatByParams(Long projectId, Long accountId,String imageMode, String startTime, String endTime, Long videoCnt);
+
+
+
+
+
 
-    List<ByteDanceVideoInfo> topMatByParams(Long projectId, Long accountId, String startTime, String endTime, Long videoCnt);
 
-    List<ByteDanceVideoInfo> historyMatByParams(Long projectId, Long accountId, String startTime, String endTime, Long videoCnt);
 }

+ 4 - 2
jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/advertise/service/IBytedanceVideoSlogenInfoService.java

@@ -15,9 +15,11 @@ import java.util.List;
  */
 public interface IBytedanceVideoSlogenInfoService extends IService<BytedanceVideoSlogenInfo> {
 
-    void insertSlogans(String videoCode, JSONArray slogans, String userId);
+    void insertSlogans(Long projectId, String videoCode, JSONArray slogans, String userId);
 
     List<BytedanceVideoSlogenInfo> listByParams(String code, Integer status);
 
-    Result getVideoSlogenReport(String accountId,String keyWord, String startTime, String endTime, Integer pageNum, Integer pageSize);
+    Result getVideoSlogenReport(String userId, String projectId,String keyWord,Integer status, String startTime, String endTime, Integer pageNum, Integer pageSize);
+
+    List<BytedanceVideoSlogenInfo> getVideoSlogenBySlogenAndProjectId(String slogen, Long projectId);
 }

+ 6 - 2
jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/advertise/service/impl/AiBytedanceAdDplinkInfoServiceImpl.java

@@ -24,7 +24,7 @@ public class AiBytedanceAdDplinkInfoServiceImpl extends ServiceImpl<AiBytedanceA
     private AiBytedanceAdDplinkInfoMapper aiBytedanceAdDplinkInfoMapper;
 
     @Override
-    public AiBytedanceAdDplinkInfo getlatestDpLinkInfo(Long strategyId, Long accountId, Integer status) {
+    public AiBytedanceAdDplinkInfo getlatestDpLinkInfo(Long strategyId, Long accountId, String imageMode,Integer status) {
         QueryWrapper<AiBytedanceAdDplinkInfo> queryWrapper = new QueryWrapper<>();
         if(null!=strategyId&&strategyId!=0){
             queryWrapper.eq("strategy_id",strategyId);
@@ -35,6 +35,9 @@ public class AiBytedanceAdDplinkInfoServiceImpl extends ServiceImpl<AiBytedanceA
         if(null!=status){
             queryWrapper.eq("status",status);
         }
+        if(null!=imageMode){
+            queryWrapper.eq("image_mode",imageMode);
+        }
         queryWrapper.orderByDesc("id").last("limit 1");
         return this.getOne(queryWrapper);
     }
@@ -48,13 +51,14 @@ public class AiBytedanceAdDplinkInfoServiceImpl extends ServiceImpl<AiBytedanceA
      * @author: zianY
      */
     @Override
-    public int getDpLinkInfoCount(Long accountId) {
+    public int getDpLinkInfoCount(Long accountId,String imageMode) {
         QueryWrapper<AiBytedanceAdDplinkInfo> queryWrapper = new QueryWrapper<>();
         Date date = new Date();
         SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
         String format = sdf.format(date);
         queryWrapper.eq("account_id",accountId);
         queryWrapper.ge("create_time",format);
+        queryWrapper.eq("image_mode",imageMode);
         return aiBytedanceAdDplinkInfoMapper.selectCount(queryWrapper);
 
     }

+ 396 - 110
jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/advertise/service/impl/AiBytedanceAdvertiserStrategyServiceImpl.java

@@ -12,9 +12,7 @@ import org.jeecg.common.util.DateUtils;
 import org.jeecg.modules.bytedance.advertise.dockapi.MarketingService;
 import org.jeecg.modules.bytedance.advertise.entity.*;
 import org.jeecg.modules.bytedance.advertise.enums.BytedanceCreativeMatTypeEnum;
-import org.jeecg.modules.bytedance.advertise.mapper.AiBytedanceAdvertiserStrategyMapper;
-import org.jeecg.modules.bytedance.advertise.mapper.BytedanceAreaInfoMapper;
-import org.jeecg.modules.bytedance.advertise.mapper.RuleDataAccountMapper;
+import org.jeecg.modules.bytedance.advertise.mapper.*;
 import org.jeecg.modules.bytedance.advertise.service.*;
 import org.jeecg.modules.bytedance.advertise.vo.AdConvertQueryVo;
 import org.jeecg.modules.bytedance.advertise.vo.AdGroupSearchVo;
@@ -27,6 +25,7 @@ import org.jeecg.modules.bytedance.common.entity.MaterialInfo;
 import org.jeecg.modules.bytedance.common.entity.UserAllocation;
 import org.jeecg.modules.bytedance.common.service.*;
 import org.jeecg.modules.bytedance.common.utils.Check;
+import org.jeecg.modules.bytedance.common.utils.GetCampaignNum;
 import org.jeecg.modules.bytedance.common.utils.StringUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
@@ -72,15 +71,15 @@ public class AiBytedanceAdvertiserStrategyServiceImpl extends ServiceImpl<AiByte
     private IByteDanceVideoInfoService videoInfoService;
     @Autowired
     private MarketingService marketingService;
+    @Resource
+    ByteDanceGeneralCopywriterMapper byteDanceGeneralCopywriterMapper;
+    @Resource
+    BytedanceMaterialRejectReasonMapper bytedanceMaterialRejectReasonMapper;
+    @Autowired
+    IAiBytedanceAutocreateLogService iBytedanceAutocreateLogService;
 
     @Override
-    public Long createCreative(AiBytedanceAdvertiserStrategy strategy, Integer createType, Long videoCnt, String openUrl) {
-        CtopOauthToken token = tokenService.getOauthTokenByAccountId(strategy.getAccountId()+"");
-        if (null == token) {
-            log.info("token获取失败=>accountId:{}", strategy.getAccountId());
-            return videoCnt;
-        }
-
+    public Long createCreative(CtopOauthToken token, AiBytedanceAdvertiserStrategy strategy, Integer createType, Long videoCnt, String openUrl) {
         UserAllocation userAllocation = userAllocationService.getByAccountId(strategy.getAccountId());
         if(null == userAllocation||userAllocation.getAccountStatus()!=0){
             log.info("此账户不存在或者已经被关闭=>accountId:{}", token.getAccountId());
@@ -100,17 +99,26 @@ public class AiBytedanceAdvertiserStrategyServiceImpl extends ServiceImpl<AiByte
         if(timeEnd != 0){
             endTime = DateUtils.formatDateTime(now + timeEnd * 60 * 1000L);
         }
-        List<ByteDanceVideoInfo> videoInfos = getVideoInfoByCreateType(userAllocation.getProjectId(),strategy,startTime,endTime,createType,videoCnt);
+        List<ByteDanceVideoInfo> videoInfos = getvideoOrImageInfoByCreateType(userAllocation.getProjectId(),strategy,startTime,endTime,createType,videoCnt);
         if(null == videoInfos||videoInfos.isEmpty()){
             log.info("获取{}视频素材为空=>accountId:{}",BytedanceCreativeMatTypeEnum.getNameByType(createType+""),token.getAccountId());
             return videoCnt;
         }
-        log.info("获取{}视频素材个数:{}=>accountId:{}",BytedanceCreativeMatTypeEnum.getNameByType(createType+""),videoInfos.size(),token.getAccountId());
-
+        log.info("获取{}素材个数:{}=>accountId:{}",BytedanceCreativeMatTypeEnum.getNameByType(createType+""),videoInfos.size(),token.getAccountId());
         for (ByteDanceVideoInfo video:videoInfos) {
+            //判断此素材为视频
+            if ("video".equalsIgnoreCase(video.getMaterialType())){
+                //视频是否是低质视频,为1跳过
+                Integer isLowQuality = bytedanceMaterialRejectReasonMapper.getIsLowQualityByVideoId(video.getVid());
+                if(!Check.isNull(isLowQuality) && 1 == isLowQuality){
+                    continue;
+                }
+            }
+
             Integer useDplinkIndex = strategy.getDpLinkIndexUsed();
             if(null==useDplinkIndex||useDplinkIndex.equals(0)){
-                AiBytedanceAdDplinkInfo adDplinkInfo = adDplinkInfoService.getlatestDpLinkInfo(strategy.getId(),strategy.getAccountId(),1);
+                //查看已使用的dp链接
+                AiBytedanceAdDplinkInfo adDplinkInfo = adDplinkInfoService.getlatestDpLinkInfo(strategy.getId(),strategy.getAccountId(),strategy.getCreativeImageMode(),1);
                 if(null == adDplinkInfo){
                     adDplinkInfo = new AiBytedanceAdDplinkInfo();
                     if("FIX".equalsIgnoreCase(strategy.getAdBidCreateType())){
@@ -121,6 +129,7 @@ public class AiBytedanceAdvertiserStrategyServiceImpl extends ServiceImpl<AiByte
                     adDplinkInfo.setDpLinkIndex(strategy.getDpLinkStartIndex());
                 }else{
                     adDplinkInfo.setId(null);
+                    adDplinkInfo.setCreateTime(new Date());
                     adDplinkInfo.setDpLinkIndex(adDplinkInfo.getDpLinkIndex()+1);
                 }
 
@@ -134,7 +143,9 @@ public class AiBytedanceAdvertiserStrategyServiceImpl extends ServiceImpl<AiByte
                     return videoCnt;
                 }
                 //计划名称
-                String adName = getAdName(strategy,null,video);
+                String adName = getAdName(strategy,null,video,userAllocation.getProjectId());
+                //截取 计划名称
+                adName = StringUtils.adNameSubMaterial(adName);
                 //计算本次出价
                 BigDecimal currentCpaBid = StringUtils.getRandomAdCpaBid(strategy.getAdBidCreateType(),strategy.getAdMaxBid(),strategy.getAdMinBid(),strategy.getAdStepBid(),adDplinkInfo.getAdBid(),strategy.getAdCpaBid());
                 JSONObject adParams = getAdParams(strategy,adName,campaignId,currentCpaBid);
@@ -142,22 +153,36 @@ public class AiBytedanceAdvertiserStrategyServiceImpl extends ServiceImpl<AiByte
                 if(null == adId){
                     continue;
                 }
-                adDplinkInfo.setAdId(adId);
-                adDplinkInfo.setAccountId(strategy.getAccountId());
-                adDplinkInfo.setStatus(1);
-                adDplinkInfo.setStrategyId(strategy.getId());
-                adDplinkInfoService.save(adDplinkInfo);
+
                 //3:创建创意
                 JSONObject creativeParams = getCreativeParams(strategy,adId,video,token);
-                log.info("创意创建参数:{}",creativeParams);
+                log.info("账户id:{};创意创建参数:{}",strategy.getAccountId(),creativeParams);
                 JSONObject creativeObject =  marketingService.creativeCreate(token,adId,creativeParams);
                 if(null!=creativeObject.getInteger("code")&&creativeObject.getInteger("code")!=0){
+                    List<Long> adIds = new ArrayList<>();
+                    adIds.add(adId);
+                    marketingService.updPlanStatus(token,adIds,"delete");
                     String message = creativeObject.getString("message");
                     Integer code = creativeObject.getInteger("code");
                     //创建创意失败
-                    log.info("创意创建失败:code==>{};message==>{}",code,message);
+                    log.info("账户id:{};创意创建失败:code==>{};message==>{}",strategy.getAccountId(),code,message);
+                    AiBytedanceAutocreateLog iBytedanceAutocreateLog = new AiBytedanceAutocreateLog(
+                            strategy.getAccountId(),
+                            "创意创建失败",
+                            code,
+                            message,
+                            "marketingService.creativeCreate => token:"+ token.toString()+",adIds:"+adIds.toString()+",creativeParams:"+creativeParams.toJSONString());
+                    iBytedanceAutocreateLogService.save(iBytedanceAutocreateLog);
                     continue;
                 }
+
+                adDplinkInfo.setAdId(adId);
+                adDplinkInfo.setAccountId(strategy.getAccountId());
+                adDplinkInfo.setStatus(1);
+                adDplinkInfo.setStrategyId(strategy.getId());
+                adDplinkInfo.setImageMode(strategy.getCreativeImageMode());
+                adDplinkInfoService.save(adDplinkInfo);
+
                 BytedanceAiVideoCreativeLog creativeLog = new BytedanceAiVideoCreativeLog(strategy,adId,campaignId,video);
                 videoCreativeLogService.saveOrUpdate(creativeLog);
                 videoCnt --;
@@ -166,7 +191,7 @@ public class AiBytedanceAdvertiserStrategyServiceImpl extends ServiceImpl<AiByte
                 }
             }else{
                 Long dpIndex ;
-                AiBytedanceAdDplinkInfo adDplinkInfo = adDplinkInfoService.getlatestDpLinkInfo(strategy.getId(),strategy.getAccountId(),1);
+                AiBytedanceAdDplinkInfo adDplinkInfo = adDplinkInfoService.getlatestDpLinkInfo(strategy.getId(),strategy.getAccountId(),strategy.getCreativeImageMode(),1);
                 if(null == adDplinkInfo){
                     adDplinkInfo = new AiBytedanceAdDplinkInfo();
                     if("FIX".equalsIgnoreCase(strategy.getAdBidCreateType())){
@@ -177,11 +202,14 @@ public class AiBytedanceAdvertiserStrategyServiceImpl extends ServiceImpl<AiByte
                     adDplinkInfo.setDpLinkIndex(strategy.getDpLinkStartIndex());
                 }else{
                     adDplinkInfo.setId(null);
+                    adDplinkInfo.setCreateTime(new Date());
                     adDplinkInfo.setDpLinkIndex(adDplinkInfo.getDpLinkIndex()+1);
                 }
                 dpIndex = adDplinkInfo.getDpLinkIndex();
-                if(dpIndex>strategy.getDpLinkEndIndex()){
-                    log.info("此账户策略创建结束=>账户id:{};策略id:{}", token.getAccountId(),strategy.getId());
+                // 超出下标范围
+                // 已使用dp链接 < 账户配置结束下标 || 已使用dp链接 > 结束下标
+                if( dpIndex < strategy.getDpLinkStartIndex() || dpIndex > strategy.getDpLinkEndIndex()){
+                    log.info("策略创建结束===dp链接超过了限制===>账户id:{};策略id:{}", token.getAccountId(),strategy.getId());
                     return 0L;
                 }
                 //组名称
@@ -194,7 +222,9 @@ public class AiBytedanceAdvertiserStrategyServiceImpl extends ServiceImpl<AiByte
                 strategy.setAdOpenUrl(openUrl.replace("{{dp链接下标}}",dpIndex.toString()));
                 String dplinkCode = StringUtils.getParamFromUrl(strategy.getAdOpenUrl(),"bc_fl_src");
                 //计划名称
-                String adName = getAdName(strategy,dplinkCode,video);
+                String adName = getAdName(strategy,dplinkCode,video,userAllocation.getProjectId());
+                //截取 计划名称
+                adName = StringUtils.adNameSubMaterial(adName);
                 //计算本次出价
                 BigDecimal currentCpaBid = StringUtils.getRandomAdCpaBid(strategy.getAdBidCreateType(),strategy.getAdMaxBid(),strategy.getAdMinBid(),strategy.getAdStepBid(),adDplinkInfo.getAdBid(),strategy.getAdCpaBid());
                 adDplinkInfo.setAdBid(currentCpaBid);
@@ -203,21 +233,35 @@ public class AiBytedanceAdvertiserStrategyServiceImpl extends ServiceImpl<AiByte
                 if(null == adId){
                     continue;
                 }
-                adDplinkInfo.setAdId(adId);
-                adDplinkInfo.setAccountId(strategy.getAccountId());
-                adDplinkInfo.setStatus(1);
-                adDplinkInfo.setStrategyId(strategy.getId());
-                adDplinkInfoService.save(adDplinkInfo);
                 //3:创建创意
                 JSONObject creativeParams = getCreativeParams(strategy,adId,video,token);
                 log.info("创意创建参数:{}",creativeParams);
                 JSONObject creativeObject =  marketingService.creativeCreate(token,adId,creativeParams);
                 log.info("创意创建返回数据:{}",creativeObject);
                 if(null!=creativeObject.getInteger("code")&&creativeObject.getInteger("code")!=0){
+                    List<Long> adIds = new ArrayList<>();
+                    adIds.add(adId);
+                    marketingService.updPlanStatus(token,adIds,"delete");
                     String message = creativeObject.getString("message");
                     Integer code = creativeObject.getInteger("code");
+                    //创建创意失败
+                    log.info("账户id:{};创意创建失败:code==>{};message==>{}",strategy.getAccountId(),code,message);
+                    AiBytedanceAutocreateLog iBytedanceAutocreateLog = new AiBytedanceAutocreateLog(
+                            strategy.getAccountId(),
+                            "创意创建失败",
+                            code,
+                            message,
+                            "marketingService.creativeCreate => token:"+ token.toString()+",adIds:"+adIds.toString()+",creativeParams:"+creativeParams.toJSONString());
+                    iBytedanceAutocreateLogService.save(iBytedanceAutocreateLog);
                     continue;
                 }
+
+                adDplinkInfo.setAdId(adId);
+                adDplinkInfo.setAccountId(strategy.getAccountId());
+                adDplinkInfo.setStatus(1);
+                adDplinkInfo.setStrategyId(strategy.getId());
+                adDplinkInfo.setImageMode(strategy.getCreativeImageMode());
+                adDplinkInfoService.save(adDplinkInfo);
                 BytedanceAiVideoCreativeLog creativeLog = new BytedanceAiVideoCreativeLog(strategy,adId,campaignId,video);
                 videoCreativeLogService.saveOrUpdate(creativeLog);
                 videoCnt --;
@@ -230,15 +274,20 @@ public class AiBytedanceAdvertiserStrategyServiceImpl extends ServiceImpl<AiByte
     }
     private JSONObject getCreativeParams(AiBytedanceAdvertiserStrategy strategy, Long adId,ByteDanceVideoInfo videoInfo,CtopOauthToken token) {
         JSONObject params = new JSONObject();
-        params.put("advertiser_id",strategy.getAccountId());
-        params.put("ad_id",adId);
+        params.put("advertiser_id", strategy.getAccountId());
+        params.put("ad_id", adId);
         String inventoryType = strategy.getCreativeInventoryType();
-        if(null!=inventoryType&&!"".equals(inventoryType)){
+        if ("CREATIVE_IMAGE_MODE_UNION_SPLASH".equalsIgnoreCase(strategy.getCreativeImageMode())) {
+            params.put("inventory_type", new String[]{"INVENTORY_UNION_SPLASH_SLOT"});
+        } else {
+        if (null != inventoryType && !"".equals(inventoryType)) {
             String[] inventoryTypeString = inventoryType.split(",");
-            if(inventoryTypeString.length>0){
-              params.put("inventory_type",inventoryTypeString);
+            if (inventoryTypeString.length > 0) {
+                params.put("inventory_type", inventoryTypeString);
             }
         }
+    }
+
         Integer smartInventory = strategy.getCreativeSmartInventory();
         if(null!=smartInventory&&smartInventory!=0){
             params.put("smart_inventory",smartInventory);
@@ -263,27 +312,37 @@ public class AiBytedanceAdvertiserStrategyServiceImpl extends ServiceImpl<AiByte
         //视频素材
         JSONArray imageArray = new JSONArray();
         JSONObject imageObject = new JSONObject();
-        //视频类型
-        if(videoInfo.getType() == 1){
-            //竖版视频
-            imageObject.put("image_mode","CREATIVE_IMAGE_MODE_VIDEO_VERTICAL");
-        }
-        if(videoInfo.getType() == 2){
-            //横版视频
-            imageObject.put("image_mode","CREATIVE_IMAGE_MODE_VIDEO");
-        }
-        imageObject.put("video_id",videoInfo.getVid());
-        //获取视频封面id
-        String imageId = getSuggestImageId(token,videoInfo.getVid());
-        if(!Check.isNull(imageId)){
-            imageObject.put("image_id",imageId);
+
+        if ("video".equalsIgnoreCase(videoInfo.getMaterialType())){
+            //视频类型
+            //1-竖版视频 2-横版视频
+//            String imageMode = videoInfo.getType() == 1 ? "CREATIVE_IMAGE_MODE_VIDEO_VERTICAL" : "CREATIVE_IMAGE_MODE_VIDEO";
+            String imageMode = strategy.getCreativeImageMode();
+            imageObject.put("image_mode",imageMode);
+            imageObject.put("video_id",videoInfo.getVid());
+            //获取视频封面id
+            String imageId = getSuggestImageId(token,videoInfo.getVid());
+            if(!Check.isNull(imageId)){
+                imageObject.put("image_id",imageId);
+            }
+        }else if ("image".equalsIgnoreCase(videoInfo.getMaterialType())){
+            //1-大图横图; 2-大图竖图
+//            String imageMode = videoInfo.getType() == 1 ? "CREATIVE_IMAGE_MODE_LARGE" : "CREATIVE_IMAGE_MODE_LARGE_VERTICAL";
+            String imageMode = strategy.getCreativeImageMode();
+            imageObject.put("image_mode",imageMode);
+            imageObject.put("image_ids",new String[]{videoInfo.getId()});
         }
+
         imageArray.add(imageObject);
         params.put("image_list",imageArray);
         JSONArray titleArray = new JSONArray();
-        List<BytedanceVideoSlogenInfo>slogenInfos = slogenInfoService.listByParams(videoInfo.getSignature(),1);
+        List<BytedanceVideoSlogenInfo> slogenInfos = slogenInfoService.listByParams(videoInfo.getSignature(),1);
+        //使用指定文案
         if(!Check.isNull(slogenInfos)){
-            slogenInfos.forEach(slogenInfo->{
+            for (BytedanceVideoSlogenInfo slogenInfo:slogenInfos) {
+                if(titleArray.size() >= 10){    //接口中是要求一个视频最多10个标题
+                    break;
+                }
                 JSONObject titleObject = new JSONObject();
                 titleObject.put("title",slogenInfo.getSlogan());
                 String creativeWordsIds = slogenInfo.getCreativeWordIds();
@@ -294,8 +353,48 @@ public class AiBytedanceAdvertiserStrategyServiceImpl extends ServiceImpl<AiByte
                     }
                 }
                 titleArray.add(titleObject);
-            });
+            }
         }
+
+        // 视频 指定文案不够的时候 使用通用文案 最多3条
+        if ("video".equalsIgnoreCase(videoInfo.getMaterialType())){
+            List<ByteDanceGeneralCopywriter> byteDanceGeneralCopywriter = byteDanceGeneralCopywriterMapper.getRandThree(strategy.getAccountId());
+            if(!Check.isNull(byteDanceGeneralCopywriter)){
+                for(int i = 0; i < byteDanceGeneralCopywriter.size(); i++){
+                    if(titleArray.size() >= 10){
+                        break;
+                    }
+                    JSONObject titleObject = new JSONObject();
+                    titleObject.put("title",byteDanceGeneralCopywriter.get(i).getTextCopywriter());
+                    String creativeWordsIds = byteDanceGeneralCopywriter.get(i).getCreativeWordIds();
+                    if(null!=creativeWordsIds&&!creativeWordsIds.trim().equals("")){
+                        JSONArray creativeWordsArray = JSON.parseArray(creativeWordsIds);
+                        if(null!=creativeWordsArray&&!creativeWordsArray.isEmpty()){
+                            titleObject.put("creative_word_ids",creativeWordsArray);
+                        }
+                    }
+                    titleArray.add(titleObject);
+                }
+            }
+            // 图片 使用通用文案 最多10条
+        }else if ("image".equalsIgnoreCase(videoInfo.getMaterialType())){
+            List<ByteDanceGeneralCopywriter> byteDanceGeneralCopywriterList = byteDanceGeneralCopywriterMapper.getRandTen(strategy.getAccountId());
+            if(!Check.isNull(byteDanceGeneralCopywriterList)){
+                for (ByteDanceGeneralCopywriter byteDanceGeneralCopywriter : byteDanceGeneralCopywriterList){
+                    JSONObject titleObject = new JSONObject();
+                    titleObject.put("title",byteDanceGeneralCopywriter.getTextCopywriter());
+                    String creativeWordsIds = byteDanceGeneralCopywriter.getCreativeWordIds();
+                    if(null!=creativeWordsIds&&!creativeWordsIds.trim().equals("")){
+                        JSONArray creativeWordsArray = JSON.parseArray(creativeWordsIds);
+                        if(null!=creativeWordsArray&&!creativeWordsArray.isEmpty()){
+                            titleObject.put("creative_word_ids",creativeWordsArray);
+                        }
+                    }
+                    titleArray.add(titleObject);
+                }
+            }
+        }
+
         if(!Check.isNull(titleArray)){
             params.put("title_list",titleArray);
         }
@@ -339,6 +438,7 @@ public class AiBytedanceAdvertiserStrategyServiceImpl extends ServiceImpl<AiByte
             params.put("action_text",actionText);
         }
 
+        //搭配试玩素材url
         String playableUrl = strategy.getCreativePlayableUrl();
         if(!Check.isNull(playableUrl)){
             params.put("playable_url",playableUrl);
@@ -464,8 +564,15 @@ public class AiBytedanceAdvertiserStrategyServiceImpl extends ServiceImpl<AiByte
 
     private Long createAdInfo(CtopOauthToken token, AiBytedanceAdvertiserStrategy strategy, JSONObject adParams) {
         Result result = marketingService.createAdvertiserPlan(token,adParams,strategy);
+        System.out.println(result);
         if(result.getCode()!=0){
-            //TODO 计划创建异常 后续需要加日志
+            AiBytedanceAutocreateLog iBytedanceAutocreateLog = new AiBytedanceAutocreateLog(
+                    strategy.getAccountId(),
+                    "计划创建异常",
+                    result.getCode(),
+                    result.getMessage(),
+                    adParams.toJSONString());
+            iBytedanceAutocreateLogService.save(iBytedanceAutocreateLog);
             return null;
         }
         return (Long)result.getResult();
@@ -480,7 +587,12 @@ public class AiBytedanceAdvertiserStrategyServiceImpl extends ServiceImpl<AiByte
         //竞价策略 默认优先跑量
         params.put("flow_control_mode","FLOW_CONTROL_MODE_FAST");
         //投放范围
-        params.put("delivery_range",strategy.getAdDeliveryRange());
+        if(null!=strategy.getAdDeliveryRange()&&!"".equals(strategy.getAdDeliveryRange().trim())){
+            params.put("delivery_range",strategy.getAdDeliveryRange());
+            if(!"UNION".equals(strategy.getAdDeliveryRange())){
+                params.put("feed_delivery_search","DISABLED");
+            }
+        }
         if(!Check.isNull(strategy.getAdUnionVideoType())){
             params.put("union_video_type",strategy.getAdUnionVideoType());
         }
@@ -489,7 +601,7 @@ public class AiBytedanceAdvertiserStrategyServiceImpl extends ServiceImpl<AiByte
         if(!Check.isNull(strategy.getAdDownloadUrl())){
             params.put("download_url",strategy.getAdDownloadUrl());
         }
-        if(!Check.isNull(strategy.getAdPackage())){
+        if(!Check.isNull(strategy.getAdPackage())&&!strategy.getAdPackage().equals("NONE")){
             params.put("package",strategy.getAdPackage());
         }
         //params.put("download_url","https://apps.bytesfield.com/download/basic/cur/1c728178004c8d4d6c83444a05c414c1a1cfae48");
@@ -688,6 +800,7 @@ public class AiBytedanceAdvertiserStrategyServiceImpl extends ServiceImpl<AiByte
                 params.put("exclude_flow_package",excludeFlowPackage);
             }
         }
+
         if(!Check.isNull(strategy.getAdPlatform())){
             String[] platform = strategy.getAdPlatform().split(",");
             if(platform.length>0){
@@ -795,6 +908,7 @@ public class AiBytedanceAdvertiserStrategyServiceImpl extends ServiceImpl<AiByte
         if(!Check.isNull(strategy.getAdAutoExtendEnabled())){
             params.put("auto_extend_enabled",strategy.getAdAutoExtendEnabled());
         }
+        //可放开定向
         if(!Check.isNull(strategy.getAdAutoExtendTargets())){
             String[] autoExtendTargets = strategy.getAdAutoExtendTargets().split(",");
             if(autoExtendTargets.length>0){
@@ -857,7 +971,7 @@ public class AiBytedanceAdvertiserStrategyServiceImpl extends ServiceImpl<AiByte
         return params;
     }
 
-    private String getAdName(AiBytedanceAdvertiserStrategy strategy, String dplinkCode, ByteDanceVideoInfo videoInfo) {
+    private String getAdName(AiBytedanceAdvertiserStrategy strategy, String dplinkCode, ByteDanceVideoInfo videoInfo,Long projectId) {
         String adName = strategy.getAdName();
         if(null == adName|| "".equals(adName.trim())){
             return null;
@@ -866,6 +980,9 @@ public class AiBytedanceAdvertiserStrategyServiceImpl extends ServiceImpl<AiByte
             String date = DateUtils.formatDate(new Date(),"yyyyMMdd");
             adName = adName.replace("{{日期}}",date);
         }
+        if(adName.contains("{{创意方式}}")){
+            adName = adName.replace("{{创意方式}}","程序化");
+        }
         if(adName.contains("{{dp链接标识}}")&&null!=dplinkCode){
             adName = adName.replace("{{dp链接标识}}",dplinkCode);
         }
@@ -873,13 +990,23 @@ public class AiBytedanceAdvertiserStrategyServiceImpl extends ServiceImpl<AiByte
             String pricing = strategy.getAdPricing().replace("PRICING_","").toLowerCase(Locale.ROOT);
             adName = adName.replace("{{出价方式}}",pricing);
         }
+
         if(adName.contains("{{素材名称}}")){
-            MaterialInfo info = materialInfoService.getParams(videoInfo.getSignature(),null);
-            if(null!=info&&null!=info.getMaterialName()){
-                adName = adName.replace("{{素材名称}}",info.getMaterialName());
+            if ("video".equals(videoInfo.getMaterialType())){
+                MaterialInfo info = materialInfoService.getParams(videoInfo.getSignature(),null,projectId);
+                if(null!=info&&null!=info.getMaterialName()){
+                    adName = adName.replace("{{素材名称}}","["+info.getMaterialName()+"]");
+                }
+            }else {
+                adName = adName.replace("{{素材名称}}","["+videoInfo.getFilename()+"]");
             }
         }
 
+        if(adName.contains("{{序号}}")){
+            int i = adDplinkInfoService.getDpLinkInfoCount(strategy.getAccountId(),strategy.getCreativeImageMode());
+            adName = adName.replace("{{序号}}",String.valueOf(i+1));
+        }
+
         adName = adName.replace("--","-");
         if(adName.startsWith("-")){
             adName = adName.substring(1);
@@ -926,7 +1053,13 @@ public class AiBytedanceAdvertiserStrategyServiceImpl extends ServiceImpl<AiByte
         //创建组
         Result campaignData = marketingService.createCampaign(token, campaignParam);
         if(campaignData.getCode()!=0){
-            //TODO 组创建异常 后续需要加日志
+            AiBytedanceAutocreateLog iBytedanceAutocreateLog = new AiBytedanceAutocreateLog(
+                    strategy.getAccountId(),
+                    "组创建异常",
+                    campaignData.getCode(),
+                    campaignData.getMessage(),
+                    campaignParam.toJSONString());
+            iBytedanceAutocreateLogService.save(iBytedanceAutocreateLog);
             return null;
         }
         return (Long)campaignData.getResult();
@@ -942,6 +1075,18 @@ public class AiBytedanceAdvertiserStrategyServiceImpl extends ServiceImpl<AiByte
             result = result + "-" + date;
         }
 
+        if(result.contains("{{序号}}")){
+            //查询同素材类型当天已有计划数量
+            int i = adDplinkInfoService.getDpLinkInfoCount(strategy.getAccountId(),strategy.getCreativeImageMode());
+            Long num = GetCampaignNum.getCampaignNameNum(strategy.getCampaignCnt(),strategy.getCampaignAdCnt(), i+1);
+            result = result.replace("{{序号}}",String.valueOf(num));
+        }
+
+        if(result.contains("{{日期}}")){
+            String time = DateUtils.formatDate(new Date(),"yyyyMMdd");
+            result = result.replace("{{日期}}",time);
+        }
+
         result = result.replace("--","-");
         if(result.startsWith("-")){
             result = result.substring(1);
@@ -954,10 +1099,10 @@ public class AiBytedanceAdvertiserStrategyServiceImpl extends ServiceImpl<AiByte
     }
 
     private String getRangeIndex(Long dpLinkStartIndex,Long dpLinkEndIndex, Long campaignAdCnt, Long dpIndex) {
-        if(dpIndex<dpLinkStartIndex||dpIndex>dpLinkEndIndex){
+       /* if(dpIndex<dpLinkStartIndex||dpIndex>dpLinkEndIndex){
             //超出下标范围
             return null;
-        }
+        }*/
         Long startIndex ;
         Long endIndex ;
         //计算当前下标值和范围区段的余数
@@ -969,24 +1114,69 @@ public class AiBytedanceAdvertiserStrategyServiceImpl extends ServiceImpl<AiByte
             startIndex = dpIndex-yzIndex+1;
             endIndex = dpIndex-yzIndex+campaignAdCnt;
         }
+        //dp 链接 超出可用范围
+        if (endIndex > dpLinkEndIndex){
+            endIndex = dpLinkEndIndex;
+        }
         return "-("+startIndex+"/"+endIndex+")";
     }
 
-    //TODO -- 高质量素材 一天只能创建一次 两周内总消耗》=500
-    //TODO -- 打捞素材  两周消耗 <500 并且总关联创意数<20
     private List<ByteDanceVideoInfo> getVideoInfoByCreateType(Long projectId,AiBytedanceAdvertiserStrategy strategy, String startTime, String endTime, Integer createType, Long videoCnt) {
+        //根据 imageMode 获取素材类型
+        //2-竖版视频 1-横板视频
+        String imageMode = BytedanceCreativeMatTypeEnum.getNameByType(strategy.getCreativeImageMode());
         //1:上新素材 2:跑量素材 3:遗漏素材 4:打捞素材
         if(createType == 1||createType == 3){
-            return videoInfoService.listByParams(projectId,strategy.getAccountId(),startTime,endTime,videoCnt,0);
+            return videoInfoService.listByParams(projectId,strategy.getAccountId(),imageMode,startTime,endTime,videoCnt,0);
         }else if(createType == 2){
             startTime = startTime.substring(0,10);
             endTime = endTime.substring(0,10);
-            return videoInfoService.topMatByParams(projectId,strategy.getAccountId(),startTime,endTime,videoCnt);
+            return videoInfoService.topMatByParams(projectId,strategy.getAccountId(),imageMode,startTime,endTime,videoCnt);
         }else if(createType == 4){
-            return videoInfoService.listByParams(projectId,strategy.getAccountId(),startTime,endTime,videoCnt,20);
+            return videoInfoService.historyMatByParams(projectId,strategy.getAccountId(),imageMode,startTime,endTime,videoCnt);
         }
         return null;
     }
+
+    /**
+     * 图片素材
+     */
+    private List<ByteDanceVideoInfo> getImageInfoByCreateType(Long projectId,AiBytedanceAdvertiserStrategy strategy, String startTime, String endTime, Integer createType, Long videoCnt) {
+        //根据 imageMode 获取素材类型
+        //1-大图横图; 2-大图竖图 3-开屏
+        String imageMode = BytedanceCreativeMatTypeEnum.getNameByType(strategy.getCreativeImageMode());
+        //1:上新素材 2:跑量素材 3:遗漏素材 4:打捞素材
+        if(createType == 1||createType == 3){
+            return videoInfoService.imageListByParams(projectId,strategy.getAccountId(),imageMode,startTime,endTime,videoCnt,0);
+        }else if(createType == 2){
+            return videoInfoService.imageTopMatByParams(projectId,strategy.getAccountId(),imageMode,startTime,endTime,videoCnt);
+        }else if(createType == 4){
+            return videoInfoService.imageHistoryMatByParams(projectId,strategy.getAccountId(),imageMode,startTime,endTime,videoCnt);
+        }
+        return null;
+    }
+
+    private List<ByteDanceVideoInfo> getvideoOrImageInfoByCreateType(Long projectId,AiBytedanceAdvertiserStrategy strategy, String startTime, String endTime, Integer createType, Long videoCnt) {
+        //横板视频 || 竖版视频
+        if (strategy.getCreativeImageMode().equalsIgnoreCase("CREATIVE_IMAGE_MODE_VIDEO")
+                || strategy.getCreativeImageMode().equalsIgnoreCase("CREATIVE_IMAGE_MODE_VIDEO_VERTICAL")){
+            //获取 视频 素材
+            return getVideoInfoByCreateType(projectId,strategy,startTime,endTime,createType,videoCnt);
+        }
+        //获取 图片 素材
+        return getImageInfoByCreateType(projectId,strategy,startTime,endTime,createType,videoCnt);
+    }
+
+
+
+
+
+
+
+
+
+
+
     /**
      *  修改状态 (0开-1关)
      *  同一账户下只能有一条数据信息为开启,可以全部关闭
@@ -995,13 +1185,13 @@ public class AiBytedanceAdvertiserStrategyServiceImpl extends ServiceImpl<AiByte
      */
     @Override
     @Transactional
-    public Result updStaById(String id,String state,String accountId) {
+    public Result updStaById(String id,String state,String accountId,String creativeImageMode) {
         //开启
         if (org.apache.commons.lang3.StringUtils.equals(state,"0")){
             //修改状态为开启
             aiBytedanceAdvertiserStrategyMapper.updStaById(id,state);
             //关闭 账户下 其他数据信息(不包含本条id信息) 状态为 关闭
-            aiBytedanceAdvertiserStrategyMapper.updStaByAccountId(accountId,"1",id);
+            aiBytedanceAdvertiserStrategyMapper.updStaByAccountId(accountId,creativeImageMode,"1",id);
         }
         //关闭
         if (org.apache.commons.lang3.StringUtils.equals(state,"1")){
@@ -1020,6 +1210,7 @@ public class AiBytedanceAdvertiserStrategyServiceImpl extends ServiceImpl<AiByte
      */
     @Override
     public Result updStaOrCpaOrBudgetById(UpdAdStaOrCpaOrBudget updAdStaOrCpaOrBudget) {
+        CtopOauthToken token = tokenService.getOauthTokenByAccountId(String.valueOf(updAdStaOrCpaOrBudget.getAccountId()));
         //1-修改出价
         if (BytedanceConstant.UPDTYPE_BID.equals(updAdStaOrCpaOrBudget.getType())) {
             //查询计划预算
@@ -1032,30 +1223,42 @@ public class AiBytedanceAdvertiserStrategyServiceImpl extends ServiceImpl<AiByte
             // 出价不为空 则 固定出价
             if (!Check.isNull(updAdStaOrCpaOrBudget.getAdCpaBid())){
                 // 出价 > 计划预算
-                a = updAdStaOrCpaOrBudget.getAdCpaBid().compareTo(new BigDecimal(strategyVo.getAdBudget()));
+                a = updAdStaOrCpaOrBudget.getAdCpaBid().compareTo(strategyVo.getAdBudget());
             //出价为空 则 随机出价 或者 阶梯出价
             // 最高出价 不能大于 计划预算
             }else {
                 // 最高出价 > 计划预算
-                a = updAdStaOrCpaOrBudget.getAdMaxBid().compareTo(new BigDecimal(strategyVo.getAdBudget()));
+                a = updAdStaOrCpaOrBudget.getAdMaxBid().compareTo(strategyVo.getAdBudget());
             }
             if (a == 1){
                 return Result.errorMsg("最高出价不能大于计划预算。");
             }
             aiBytedanceAdvertiserStrategyMapper.updCpaById(updAdStaOrCpaOrBudget);
         }
-        //2-修改预算
+        //2-修改预算(给西安提供 修改 预算)
         if (BytedanceConstant.UPDTYPE_BUDGET.equals(updAdStaOrCpaOrBudget.getType())) {
 
             //指定预算
             if (updAdStaOrCpaOrBudget.getBudgetType().equals("2")){
-                //  前者 < 后者
-                int a = new BigDecimal(updAdStaOrCpaOrBudget.getBudget()).compareTo(updAdStaOrCpaOrBudget.getCost().multiply(new BigDecimal(1.05)));
-                if (a == -1){
-                    return Result.errorMsg("修改后预算金额不能低于当前已消费金额的105%");
+                if (!Check.isNull(updAdStaOrCpaOrBudget.getCost())){
+                    //  前者 < 后者
+                    int a = new BigDecimal(updAdStaOrCpaOrBudget.getBudget()).compareTo(updAdStaOrCpaOrBudget.getCost().multiply(new BigDecimal(1.05)));
+                    if (a == -1){
+                        return Result.errorMsg("修改后预算金额不能低于当前已消费金额的105%");
+                    }
                 }
             }
             aiBytedanceAdvertiserStrategyMapper.updBudgetById(updAdStaOrCpaOrBudget.getId(), updAdStaOrCpaOrBudget.getBudget(),updAdStaOrCpaOrBudget.getBudgetType());
+
+            //账户预算 同步 头条
+            //BUDGET_MODE_DAY-日预算
+            // BUDGET_MODE_INFINITE-不限
+            String accountBudgetMode = updAdStaOrCpaOrBudget.getBudgetType().equals("1") ? "BUDGET_MODE_INFINITE" : "BUDGET_MODE_DAY";
+            Result resultBudget = marketingService.updateBudget(token,accountBudgetMode,new BigDecimal(updAdStaOrCpaOrBudget.getBudget()));
+            if (!resultBudget.isSuccess()){
+                return Result.error(resultBudget.getMessage());
+            }
+
         }
         return Result.successMsg("修改"+(BytedanceConstant.UPDTYPE_BID.equals(updAdStaOrCpaOrBudget.getType()) ? "出价" : "预算")+"成功。",null);
     }
@@ -1265,7 +1468,9 @@ public class AiBytedanceAdvertiserStrategyServiceImpl extends ServiceImpl<AiByte
      * @author zianY
      */
     @Override
+    @Transactional
     public Result addBytedanceStrategy(AiBytedanceAdvertiserStrategy aiBytedanceAdvertiserStrategy) {
+        CtopOauthToken token = tokenService.getOauthTokenByAccountId(String.valueOf(aiBytedanceAdvertiserStrategy.getAccountId()));
         //预算金额不能低于当前已消费金额的105%
         QueryWrapper<RuleDataAccount> ruleDataAccountQueryWrapper = new QueryWrapper<>();
         ruleDataAccountQueryWrapper.eq("account_id",aiBytedanceAdvertiserStrategy.getAccountId());
@@ -1274,14 +1479,15 @@ public class AiBytedanceAdvertiserStrategyServiceImpl extends ServiceImpl<AiByte
         // 值 为0 不限预算
         // !0 指定预算
         if (!aiBytedanceAdvertiserStrategy.getAccountBudget().equals(new BigDecimal("0"))){
-            //  前者 < 后者
-            int a = aiBytedanceAdvertiserStrategy.getAccountBudget().compareTo(ruleDataAccountVo.getCost().multiply(new BigDecimal(1.05)));
-            if (a == -1){
-                return Result.errorMsg("预算金额不能低于当前已消费金额的105%");
+            if (!Check.isNull(ruleDataAccountVo)){
+                //  前者 < 后者
+                int a = aiBytedanceAdvertiserStrategy.getAccountBudget().compareTo(ruleDataAccountVo.getCost().multiply(new BigDecimal(1.05)));
+                if (a == -1){
+                    return Result.errorMsg("预算金额不能低于当前已消费金额的105%");
+                }
             }
         }
 
-
         // 数据入库 string[] 转 string
         //商品卖点
         aiBytedanceAdvertiserStrategy.setCreativeProductSellingPoints(org.apache.commons.lang3.StringUtils.join(aiBytedanceAdvertiserStrategy.getProductSellingPoints(), ","));
@@ -1293,9 +1499,9 @@ public class AiBytedanceAdvertiserStrategyServiceImpl extends ServiceImpl<AiByte
         //默认组数量为 1 -前端已修改完成
         //aiBytedanceAdvertiserStrategy.setCampaignAdCnt(aiBytedanceAdvertiserStrategy.getCampaignAdCnt() == 0L ? 1 : aiBytedanceAdvertiserStrategy.getCampaignAdCnt());
 
-        //同一账户下 只能有一条信息为开启
+        //同一账户下 同素材类型 只能有一条信息为开启
         //关闭 账户下 其他数据信息(不包含本条id信息) 状态为 关闭
-        aiBytedanceAdvertiserStrategyMapper.updStaByAccountId(String.valueOf(aiBytedanceAdvertiserStrategy.getAccountId()),"1",null);
+        aiBytedanceAdvertiserStrategyMapper.updStaByAccountId(String.valueOf(aiBytedanceAdvertiserStrategy.getAccountId()),aiBytedanceAdvertiserStrategy.getCreativeImageMode(),"1",null);
         //状态(0开 1关)
         aiBytedanceAdvertiserStrategy.setStatus(0);
 
@@ -1305,8 +1511,19 @@ public class AiBytedanceAdvertiserStrategyServiceImpl extends ServiceImpl<AiByte
         imageInfo.setUserId(aiBytedanceAdvertiserStrategy.getUserId());
         materialImageInfoService.initImageCode(imageInfo);
 
+
+
         aiBytedanceAdvertiserStrategyMapper.insert(aiBytedanceAdvertiserStrategy);
 
+
+        //账户预算 同步 头条
+        //BUDGET_MODE_DAY-日预算
+        // BUDGET_MODE_INFINITE-不限
+        String accountBudgetMode = aiBytedanceAdvertiserStrategy.getAccountBudgetMode().equals("1") ? "BUDGET_MODE_INFINITE" : "BUDGET_MODE_DAY";
+        Result resultBudget = marketingService.updateBudget(token,accountBudgetMode,aiBytedanceAdvertiserStrategy.getAccountBudget());
+       /* if (!resultBudget.isSuccess()){
+            return Result.error(resultBudget.getMessage());
+        }*/
         return Result.successMsg("新增成功。",aiBytedanceAdvertiserStrategy);
     }
 
@@ -1325,34 +1542,58 @@ public class AiBytedanceAdvertiserStrategyServiceImpl extends ServiceImpl<AiByte
 
     @Autowired
     private IByteDanceAdvertisePlanService planService;
+    @Autowired
+    private IByteDanceAdvertiserDataService advertiserDataService;
+
     @Override
     public void customCreativeSupplement(AiBytedanceAdvertiserStrategy strategy, Integer hour,String openUrl) {
-        Long customUnitCnt = strategy.getCampaignAdCnt()*strategy.getCampaignCnt();
-        Long unitNum = customUnitCnt * hour / 15;
-        log.info("{}当前时间内需要创建计划总数:{}", strategy.getAccountId(), unitNum);
-        //查询当前账户创建自定义类型计划数量
-        int unitCreateCnt = planService.queryToDayBuiltCount(strategy.getAccountId());
-        log.info("{}截止目前创建组总数:{}", strategy.getAccountId(), unitCreateCnt);
-        long remindCnt = unitNum - unitCreateCnt;
-        if (remindCnt >= 1) {
-            log.info("{}计划创建不足,剩余需要创建个数{},使用上新素材创建", strategy.getAccountId(), remindCnt);
-            //优先创建历史遗漏素材
-            remindCnt = this.createCreative(strategy, 1, remindCnt,openUrl);
-        }
-        if (remindCnt >= 1) {
-            log.info("{}计划创建不足,剩余需要创建个数{},使用历史遗漏素材创建", strategy.getAccountId(), remindCnt);
-            //优先创建历史遗漏素材
-            remindCnt = this.createCreative(strategy, 3, remindCnt,openUrl);
-        }
-        if (remindCnt >= 1) {
-            log.info("{}计划创建不足,剩余需要创建个数{},使用高质量素材创建", strategy.getAccountId(), remindCnt);
-            //高质量素材
-            remindCnt = this.createCreative(strategy, 2, remindCnt,openUrl);
-        }
-        if (remindCnt >= 1) {
-            //历史打捞素材
-            log.info("{}计划创建不足,剩余需要创建个数{},使用历史打捞素材创建", strategy.getAccountId(), remindCnt);
-            this.createCreative(strategy, 4, remindCnt,openUrl);
+        try{
+            CtopOauthToken token = tokenService.getOauthTokenByAccountId(strategy.getAccountId()+"");
+            if (null == token) {
+                log.info("token获取失败=>accountId:{}", strategy.getAccountId());
+                return;
+            }
+            Long customUnitCnt = strategy.getCampaignAdCnt()*strategy.getCampaignCnt();
+            Long unitNum = customUnitCnt * hour / 19;
+            log.info("{}当前时间内需要创建计划总数:{}", strategy.getAccountId(), unitNum);
+            //查询当前账户创建自定义类型计划数量
+            int unitCreateCnt = planService.queryToDayBuiltCount(strategy.getAccountId());
+            log.info("{}截止目前创建计划总数:{}", strategy.getAccountId(), unitCreateCnt);
+            long remindCnt = unitNum - unitCreateCnt;
+            if (remindCnt >= 1) {
+                log.info("{}计划创建不足,剩余需要创建个数{},使用上新素材创建", strategy.getAccountId(), remindCnt);
+                //优先创建历史遗漏素材
+                remindCnt = this.createCreative(token, strategy, 1, remindCnt,openUrl);
+            }
+            if (remindCnt >= 1) {
+                log.info("{}计划创建不足,剩余需要创建个数{},使用历史遗漏素材创建", strategy.getAccountId(), remindCnt);
+                //优先创建历史遗漏素材
+                remindCnt = this.createCreative(token, strategy, 3, remindCnt,openUrl);
+            }
+            if (remindCnt >= 1) {
+                log.info("{}计划创建不足,剩余需要创建个数{},使用高质量素材创建", strategy.getAccountId(), remindCnt);
+                //高质量素材
+                remindCnt = this.createCreative(token, strategy, 2, remindCnt,openUrl);
+            }
+            if (remindCnt >= 1) {
+                //历史打捞素材
+                log.info("{}计划创建不足,剩余需要创建个数{},使用历史打捞素材创建", strategy.getAccountId(), remindCnt);
+                this.createCreative(token, strategy, 4, remindCnt,openUrl);
+            }
+            //获取最新的plan计划更新到表格
+            String nowDate = DateUtils.formatDate();
+            advertiserDataService.getAdvertiserPlan(token, "", nowDate, nowDate);
+
+            int newUnitCreateCnt = planService.queryToDayBuiltCount(strategy.getAccountId());
+            AiBytedanceAutocreateLog iBytedanceAutocreateLog = new AiBytedanceAutocreateLog(
+                    strategy.getAccountId(),
+                    "创建广告计划",
+                    200,
+                    "当前账户需要创建计划总数为"+unitNum+"个,截止目前有"+unitCreateCnt+"个,此次创建成功"+(newUnitCreateCnt - unitCreateCnt)+"个。",
+                    "aiBytedanceAdvertiserStrategyService.customCreativeSupplement => strategy:"+ strategy.toString()+",hour:"+hour);
+            iBytedanceAutocreateLogService.save(iBytedanceAutocreateLog);
+        }catch (Exception e){
+            log.info(e.getMessage());
         }
     }
 
@@ -1501,5 +1742,50 @@ public class AiBytedanceAdvertiserStrategyServiceImpl extends ServiceImpl<AiByte
         return Result.successMsg("获取橙子建站站点列表成功。",dataList);
     }
 
+    /**
+     *查询 组名称 计划名称
+     */
+    @Override
+    public Result getStrategyInfoByName(AiBytedanceAdvertiserStrategy aiBytedanceAdvertiserStrategy) {
+        //查询 组名称
+        QueryWrapper<AiBytedanceAdvertiserStrategy> queryWrapperCampaign = new QueryWrapper<>();
+        //查询计划名称
+        QueryWrapper<AiBytedanceAdvertiserStrategy> queryWrapperAdName = new QueryWrapper<>();
+        List<AiBytedanceAdvertiserStrategy> strategyInfoCampain = new ArrayList<>();
+        List<AiBytedanceAdvertiserStrategy> strategyInfoAdName = new ArrayList<>();
+        //新增
+        if (Check.isNull(aiBytedanceAdvertiserStrategy.getId())){
+            queryWrapperCampaign.eq("campaign_name",aiBytedanceAdvertiserStrategy.getCampaignName());
+            strategyInfoCampain = aiBytedanceAdvertiserStrategyMapper.selectList(queryWrapperCampaign);
+            if (!Check.isNull(strategyInfoCampain)){
+                return Result.error("新创建的账户配置已存在相同的组名称【"+aiBytedanceAdvertiserStrategy.getCampaignName()+"】请修改后重新保存。");
+            }
+            queryWrapperAdName.eq("ad_name",aiBytedanceAdvertiserStrategy.getAdName());
+            strategyInfoAdName = aiBytedanceAdvertiserStrategyMapper.selectList(queryWrapperAdName);
+            if (!Check.isNull(strategyInfoAdName)){
+                return Result.error("新创建的账户配置已存在相同的计划名称【"+aiBytedanceAdvertiserStrategy.getAdName()+"】请修改后重新保存。");
+            }
+        // 编辑
+        }else {
+            queryWrapperCampaign.eq("campaign_name",aiBytedanceAdvertiserStrategy.getCampaignName());
+            strategyInfoCampain = aiBytedanceAdvertiserStrategyMapper.selectList(queryWrapperCampaign);
+            strategyInfoCampain.stream().map(AiBytedanceAdvertiserStrategy::getId).collect(Collectors.toList());
+            if (!Check.isNull(strategyInfoCampain) &&
+                    !strategyInfoCampain.stream().map(AiBytedanceAdvertiserStrategy::getId).collect(Collectors.toList()).contains(aiBytedanceAdvertiserStrategy.getId())){
+                return Result.error("新创建的账户配置已存在相同的组名称【"+aiBytedanceAdvertiserStrategy.getCampaignName()+"】请修改后重新保存。");
+            }
+            queryWrapperAdName.eq("ad_name",aiBytedanceAdvertiserStrategy.getAdName());
+            strategyInfoAdName = aiBytedanceAdvertiserStrategyMapper.selectList(queryWrapperAdName);
+            if (!Check.isNull(strategyInfoAdName) &&
+                    !strategyInfoAdName.stream().map(AiBytedanceAdvertiserStrategy::getId).collect(Collectors.toList()).contains(aiBytedanceAdvertiserStrategy.getId())){
+                return Result.error("新创建的账户配置已存在相同的计划名称【"+aiBytedanceAdvertiserStrategy.getAdName()+"】请修改后重新保存。");
+            }
+        }
+
+
+
+        return Result.successMsg("成功。",null);
+    }
+
 
 }

+ 19 - 0
jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/advertise/service/impl/AiBytedanceAutocreateLogServiceImpl.java

@@ -0,0 +1,19 @@
+package org.jeecg.modules.bytedance.advertise.service.impl;
+
+import org.jeecg.modules.bytedance.advertise.entity.AiBytedanceAutocreateLog;
+import org.jeecg.modules.bytedance.advertise.service.IAiBytedanceAutocreateLogService;
+import org.jeecg.modules.bytedance.advertise.mapper.AiBytedanceAutocreateLogMapper;
+import org.springframework.stereotype.Service;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+
+/**
+ * 自动创建计划日志
+ * @author jeecg-boot
+ * 2021-07-05
+ * @version V1.0
+ */
+@Service
+public class AiBytedanceAutocreateLogServiceImpl extends ServiceImpl<AiBytedanceAutocreateLogMapper, AiBytedanceAutocreateLog> implements IAiBytedanceAutocreateLogService {
+
+}

+ 14 - 0
jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/advertise/service/impl/ByteDanceAdvertisePlanServiceImpl.java

@@ -210,6 +210,20 @@ public class ByteDanceAdvertisePlanServiceImpl extends ServiceImpl<ByteDanceAdve
     }
 
     @Override
+    public List<ByteDanceAdvertisePlan> getAllPlansByAccountId(Long accountId,String adModifyTime) {
+        QueryWrapper<ByteDanceAdvertisePlan>queryWrapper = new QueryWrapper<>();
+        queryWrapper.eq("account_id",accountId+"");
+        if(null!=adModifyTime&&!"".equals(adModifyTime.trim())){
+            queryWrapper.ge("ad_modify_time",adModifyTime);
+            queryWrapper.le("ad_modify_time",new Date());
+        }
+        queryWrapper.ne("toutiao_status","AD_STATUS_DELETE");
+//        queryWrapper.eq("toutiao_status","AD_STATUS_AUDIT_DENY");   //获取通过审核建议
+        queryWrapper.orderByDesc("ad_modify_time");
+        return this.list(queryWrapper);
+    }
+
+    @Override
     public int queryToDayBuiltCount(Long accountId) {
         String date = DateUtil.formatDate(new Date());
         return byteDanceAdvertisePlanMapper.queryTodayBuiltCount(accountId, date);

+ 2 - 0
jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/advertise/service/impl/ByteDanceCampaignServiceImpl.java

@@ -66,6 +66,8 @@ public class ByteDanceCampaignServiceImpl extends ServiceImpl<ByteDanceCampaignM
         if(!Check.isNull(campaignName)){
             queryWrapper.like("name",campaignName);
         }
+        //过滤已删除广告组信息
+        queryWrapper.ne("status","CAMPAIGN_STATUS_DELETE");
         queryWrapper.orderByDesc("create_time").last("limit 1");
         return this.getOne(queryWrapper);
 

+ 66 - 21
jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/advertise/service/impl/ByteDanceGeneralCopywriterServiceImpl.java

@@ -1,20 +1,27 @@
 package org.jeecg.modules.bytedance.advertise.service.impl;
 
+import com.alibaba.fastjson.JSONObject;
 import com.github.pagehelper.PageHelper;
 import com.github.pagehelper.PageInfo;
 import org.apache.commons.lang3.StringUtils;
 import org.jeecg.common.api.vo.Result;
+import org.jeecg.modules.bytedance.advertise.entity.ByteDanceCreativeWordPackage;
 import org.jeecg.modules.bytedance.advertise.entity.ByteDanceGeneralCopywriter;
 import org.jeecg.modules.bytedance.advertise.mapper.ByteDanceGeneralCopywriterMapper;
 import org.jeecg.modules.bytedance.advertise.mapper.BytedanceVideoSlogenInfoMapper;
 import org.jeecg.modules.bytedance.advertise.service.IByteDanceGeneralCopywriterService;
+import org.jeecg.modules.bytedance.common.service.IUserAllocationService;
 import org.jeecg.modules.bytedance.common.utils.Check;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 
 import javax.annotation.Resource;
 import java.math.BigDecimal;
+import java.text.DecimalFormat;
+import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 import java.util.Map;
 
@@ -28,55 +35,93 @@ import java.util.Map;
 public class ByteDanceGeneralCopywriterServiceImpl extends ServiceImpl<ByteDanceGeneralCopywriterMapper, ByteDanceGeneralCopywriter> implements IByteDanceGeneralCopywriterService {
     @Resource
     ByteDanceGeneralCopywriterMapper byteDanceGeneralCopywriterMapper;
-
+    @Autowired
+    IUserAllocationService IUserAllocationService;
 
     @Override
-    public Result getGeneralCopywriterReport(String accountId, String keyWord, String startTime, String endTime, Integer pageNum, Integer pageSize){
+    public Result getGeneralCopywriterReport(String userId, String accountId, String keyWord, Integer status, String startTime, String endTime, Integer pageNum, Integer pageSize){
+
+
+        List<String> accountIds = new ArrayList<>();
+        //查询普通用户的全量查询,当前用户所有项目
+        if(Check.isNull(accountId)){
+            List<JSONObject> jsonObjectList = IUserAllocationService.getAccountIdsByUserId(userId);
+            if(!Check.isNull(jsonObjectList)){
+                for (JSONObject jsonObject:jsonObjectList) {
+                    accountIds.add(jsonObject.getString("account_id"));
+                }
+            }else{
+                return Result.successMsg("当前登录人未绑定账户","");
+            }
+
+        }else if(accountId == "admin"){//管理员的全量查询
+            accountIds = null;
+        }else { //不论什么权限的用户的单独搜索一个项目
+            accountIds.add(accountId);
+        }
+
+
         PageHelper.startPage(pageNum,pageSize);
-        List<Map<String, Object>> generalCopywriteReportList = byteDanceGeneralCopywriterMapper.selectGeneralCopywriterReport(accountId,keyWord, startTime, endTime);
+        List<Map<String, Object>> generalCopywriteReportList = byteDanceGeneralCopywriterMapper.selectGeneralCopywriterReport(accountIds, keyWord, status, startTime, endTime);
         if(Check.isNull(generalCopywriteReportList)){
-            return Result.error("还没有此文案报表数据,请将此文案投放跑量!");
+            return Result.successMsg("还没有此文案报表数据,请将此文案投放跑量!",generalCopywriteReportList);
         }
 
-        for (Map<String, Object> videoSlogenReportMap: generalCopywriteReportList) {
+        for (Map<String, Object> generalCopywriteReportMap: generalCopywriteReportList) {
 
-            if(videoSlogenReportMap.get("count") == null){
-                videoSlogenReportMap.put("count",0);
+            if(generalCopywriteReportMap.get("count") == null){
+                generalCopywriteReportMap.put("count",0);
             }
 
-            BigDecimal cost = new BigDecimal(Check.isNull(videoSlogenReportMap.get("cost")) ? "0" : videoSlogenReportMap.get("cost").toString());
-            BigDecimal click = new BigDecimal(Check.isNull(videoSlogenReportMap.get("click")) ? "0" : videoSlogenReportMap.get("click").toString());
-            BigDecimal showNum = new BigDecimal(Check.isNull(videoSlogenReportMap.get("showNum")) ? "0" : videoSlogenReportMap.get("showNum").toString());
-            BigDecimal convertNum = new BigDecimal(Check.isNull(videoSlogenReportMap.get("convertNum")) ? "0" : videoSlogenReportMap.get("convertNum").toString());
+            BigDecimal cost = new BigDecimal(Check.isNull(generalCopywriteReportMap.get("cost")) ? "0" : generalCopywriteReportMap.get("cost").toString());
+            BigDecimal click = new BigDecimal(Check.isNull(generalCopywriteReportMap.get("click")) ? "0" : generalCopywriteReportMap.get("click").toString());
+            BigDecimal showNum = new BigDecimal(Check.isNull(generalCopywriteReportMap.get("showNum")) ? "0" : generalCopywriteReportMap.get("showNum").toString());
+            BigDecimal convertNum = new BigDecimal(Check.isNull(generalCopywriteReportMap.get("convertNum")) ? "0" : generalCopywriteReportMap.get("convertNum").toString());
+
+            DecimalFormat decimalFormat = new DecimalFormat("0.00#");
+            generalCopywriteReportMap.put("cost", decimalFormat.format(cost));
+            generalCopywriteReportMap.put("click", click);
+            generalCopywriteReportMap.put("showNum", showNum);
+            generalCopywriteReportMap.put("convertNum", convertNum);
 
             //被除数不能为0
             if (StringUtils.equals("0",showNum.toString())){
-                videoSlogenReportMap.put("costPerThousandShow", 0);
-                videoSlogenReportMap.put("clickRate", 0);
+                generalCopywriteReportMap.put("costPerThousandShow", 0);
+                generalCopywriteReportMap.put("clickRate", 0);
             }else {
                 BigDecimal costPerThousandShow = cost.multiply(new BigDecimal(1000)).divide(showNum, 2, BigDecimal.ROUND_HALF_UP);
-                videoSlogenReportMap.put("costPerThousandShow", costPerThousandShow);
+                generalCopywriteReportMap.put("costPerThousandShow", decimalFormat.format(costPerThousandShow));
                 BigDecimal clickRate = click.multiply(new BigDecimal(100)).divide(showNum, 2, BigDecimal.ROUND_HALF_UP);
-                videoSlogenReportMap.put("clickRate", clickRate);
+                generalCopywriteReportMap.put("clickRate", decimalFormat.format(clickRate));
             }
             if (StringUtils.equals("0", convertNum.toString())) {
-                videoSlogenReportMap.put("costConvert", 0);
+                generalCopywriteReportMap.put("costConvert", 0);
             }else {
                 BigDecimal costConvert = cost.divide(convertNum, 2, BigDecimal.ROUND_HALF_UP);
-                videoSlogenReportMap.put("costConvert", costConvert);
+                generalCopywriteReportMap.put("costConvert", decimalFormat.format(costConvert));
             }
             if (StringUtils.equals("0", click.toString())) {
-                videoSlogenReportMap.put("costPerClick", 0);
-                videoSlogenReportMap.put("convertRate", 0);
+                generalCopywriteReportMap.put("costPerClick", 0);
+                generalCopywriteReportMap.put("convertRate", 0);
             }else {
                 BigDecimal costPerClick = cost.divide(click, 2, BigDecimal.ROUND_HALF_UP);
-                videoSlogenReportMap.put("costPerClick", costPerClick);
+                generalCopywriteReportMap.put("costPerClick", decimalFormat.format(costPerClick));
                 BigDecimal convertRate = convertNum.multiply(new BigDecimal(100)).divide(click,2,BigDecimal.ROUND_HALF_UP);
-                videoSlogenReportMap.put("convertRate", convertRate);
+                generalCopywriteReportMap.put("convertRate", decimalFormat.format(convertRate));
             }
         }
 
         PageInfo<Map<String, Object>> pageInfo = new PageInfo<Map<String, Object>>(generalCopywriteReportList);
         return Result.successMsg("数据加载成功。",pageInfo);
     }
+    @Override
+    public ByteDanceCreativeWordPackage selectCreativeWordPackageByName(String name){
+        return byteDanceGeneralCopywriterMapper.selectCreativeWordPackageByName(name);
+    }
+
+    @Override
+    public List<ByteDanceGeneralCopywriter> selectAllDataByTextCopywriter(String textCopywriter){
+        return byteDanceGeneralCopywriterMapper.selectAllDataByTextCopywriter(textCopywriter);
+    }
+
 }

+ 35 - 6
jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/advertise/service/impl/ByteDanceVideoInfoServiceImpl.java

@@ -44,20 +44,49 @@ public class ByteDanceVideoInfoServiceImpl extends ServiceImpl<ByteDanceVideoInf
     }
 
     @Override
-    public List<ByteDanceVideoInfo> listByParams(Long projectId,Long accountId, String startTime, String endTime, Long videoCnt,long creativeCnt) {
+    public List<ByteDanceVideoInfo> listByParams(Long projectId,Long accountId, String imageMode,String startTime, String endTime, Long videoCnt,long creativeCnt) {
         String now = DateUtils.formatDate();
-        return videoInfoMapper.getNewVideoByParams(projectId,accountId,startTime,endTime,videoCnt,creativeCnt,now);
+        return videoInfoMapper.getNewVideoByParams(projectId,accountId,imageMode,startTime,endTime,videoCnt,creativeCnt,now);
     }
 
     @Override
-    public List<ByteDanceVideoInfo> topMatByParams(Long projectId, Long accountId, String startTime, String endTime, Long videoCnt) {
+    public List<ByteDanceVideoInfo> topMatByParams(Long projectId, Long accountId, String imageMode,String startTime, String endTime, Long videoCnt) {
         String now = DateUtils.formatDate();
-        return videoInfoMapper.topMatByParams(projectId,accountId,startTime,endTime,videoCnt,now);
+        return videoInfoMapper.topMatByParams(projectId,accountId,imageMode,startTime,endTime,videoCnt,now);
     }
 
     @Override
-    public List<ByteDanceVideoInfo> historyMatByParams(Long projectId, Long accountId, String startTime, String endTime, Long videoCnt) {
+    public List<ByteDanceVideoInfo> historyMatByParams(Long projectId, Long accountId, String imageMode,String startTime, String endTime, Long videoCnt) {
         String now = DateUtils.formatDate();
-        return videoInfoMapper.historyMatByParams(projectId,accountId,startTime,endTime,videoCnt,now);
+        return videoInfoMapper.historyMatByParams(projectId,accountId,imageMode,startTime,endTime,videoCnt,now);
+    }
+
+
+    /**
+     * 图片 上新 遗漏
+     */
+    @Override
+    public List<ByteDanceVideoInfo> imageListByParams(Long projectId, Long accountId, String imageMode,String startTime, String endTime, Long videoCnt, long creativeCnt) {
+        String now = DateUtils.formatDate();
+        return videoInfoMapper.imageListByParams(projectId,accountId,imageMode,startTime,endTime,videoCnt,creativeCnt,now);
+
+    }
+
+    /**
+     * 图片 跑量
+     */
+    @Override
+    public List<ByteDanceVideoInfo> imageTopMatByParams(Long projectId, Long accountId, String imageMode,String startTime, String endTime, Long videoCnt) {
+        String now = DateUtils.formatDate();
+        return videoInfoMapper.imageTopMatByParams(projectId,accountId,imageMode,startTime,endTime,videoCnt,now);
+    }
+
+    /**
+     * 图片 打捞
+     */
+    @Override
+    public List<ByteDanceVideoInfo> imageHistoryMatByParams(Long projectId, Long accountId, String imageMode,String startTime, String endTime, Long videoCnt) {
+        String now = DateUtils.formatDate();
+        return videoInfoMapper.imageHistoryMatByParams(projectId,accountId,imageMode,startTime,endTime,videoCnt,now);
     }
 }

+ 131 - 0
jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/advertise/service/impl/BytedanceRejectReasonServiceImpl.java

@@ -0,0 +1,131 @@
+package org.jeecg.modules.bytedance.advertise.service.impl;
+
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.jeecg.common.api.vo.Result;
+import org.jeecg.common.util.DateUtils;
+import org.jeecg.modules.bytedance.advertise.entity.*;
+import org.jeecg.modules.bytedance.advertise.mapper.BytedanceMaterialRejectReasonMapper;
+import org.jeecg.modules.bytedance.advertise.mapper.BytedancePlanRejectReasonMapper;
+import org.jeecg.modules.bytedance.advertise.mapper.LowQualityRejectReasonMapper;
+import org.jeecg.modules.bytedance.advertise.mapper.RuleDataAccountMapper;
+import org.jeecg.modules.bytedance.advertise.service.BytedanceRejectReasonService;
+import org.jeecg.modules.bytedance.advertise.service.IRuleDataAccountService;
+import org.jeecg.modules.bytedance.common.entity.CtopOauthToken;
+import org.jeecg.modules.bytedance.common.utils.Check;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.concurrent.CancellationException;
+
+/**
+ * 规则账户清洗数据
+ *
+ * @author jeecg-boot
+ * @version V1.0
+ * @date 2020-11-16
+ */
+@Service
+public class BytedanceRejectReasonServiceImpl implements BytedanceRejectReasonService {
+
+    @Resource
+    private BytedancePlanRejectReasonMapper bytedancePlanRejectReasonMapper;
+
+    @Resource
+    private BytedanceMaterialRejectReasonMapper BytedanceMaterialRejectReasonMapper;
+
+    @Resource
+    LowQualityRejectReasonMapper lowQualityRejectReasonMapper;
+    public void saveRejectReasonToDb(JSONArray jsonArray,Long accountId){
+        for(int i=0; i<jsonArray.size(); i++){
+            JSONObject jsonObject = jsonArray.getJSONObject(i);
+            JSONObject ad_reject = jsonObject.getJSONObject("ad_reject");
+            JSONArray reject_data = ad_reject.getJSONArray("reject_data");
+            if(!Check.isNull(reject_data)){
+                for(int j=0; j<reject_data.size();j++){
+                    JSONObject object = reject_data.getJSONObject(j);
+                    BytedancePlanRejectReason bytedancePlanRejectReason = new BytedancePlanRejectReason();
+                    bytedancePlanRejectReason.setAdId(ad_reject.getLong("ad_id"));
+                    bytedancePlanRejectReason.setRejectItem(object.getString("reject_item"));
+                    bytedancePlanRejectReason.setRejectReason(object.getString("reject_reason"));
+                    bytedancePlanRejectReason.setIsLowQuality(0);
+                    bytedancePlanRejectReason.setAccountId(accountId);
+                    String[] rejectReasons = bytedancePlanRejectReason.getRejectReason().split("广告体验优化建议:");
+                    if(rejectReasons.length == 0){
+                        LowQualityRejectReason lowQualityRejectReason = lowQualityRejectReasonMapper.getByRejectReason(bytedancePlanRejectReason.getRejectReason().trim());
+                        if(!Check.isNull(lowQualityRejectReason)){
+                            bytedancePlanRejectReason.setIsLowQuality(1);
+                        }
+                    }else {
+                        for(int k=1;k<rejectReasons.length;k++){
+                            LowQualityRejectReason lowQualityRejectReason = lowQualityRejectReasonMapper.getByRejectReason("广告体验优化建议:"+rejectReasons[k].trim());
+                            if(!Check.isNull(lowQualityRejectReason)){
+                                bytedancePlanRejectReason.setIsLowQuality(1);
+                            }
+                        }
+                    }
+
+                    int res = bytedancePlanRejectReasonMapper.replaceIntoDb(bytedancePlanRejectReason);
+                    if(res == 0){
+                        System.out.println(bytedancePlanRejectReason.toString());
+                    }
+                }
+            }
+
+            JSONArray material_reject = jsonObject.getJSONArray("material_reject");
+            if(!Check.isNull(material_reject)){
+                for(int j=0; j<material_reject.size();j++){
+                    JSONObject object = material_reject.getJSONObject(j);
+                    BytedanceMaterialRejectReason bytedanceMaterialRejectReason = new BytedanceMaterialRejectReason();
+                    bytedanceMaterialRejectReason.setRejectReason(object.getString("reject_reason"));
+                    bytedanceMaterialRejectReason.setIsLowQuality(0);
+                    bytedanceMaterialRejectReason.setAccountId(accountId);
+                    String[] rejectReasons = bytedanceMaterialRejectReason.getRejectReason().split("广告体验优化建议:");
+                    for(int k=1;k<rejectReasons.length;k++){
+                        LowQualityRejectReason lowQualityRejectReason = lowQualityRejectReasonMapper.getByRejectReason("广告体验优化建议:"+rejectReasons[k].trim());
+                        if(!Check.isNull(lowQualityRejectReason)){
+                            bytedanceMaterialRejectReason.setIsLowQuality(1);
+                        }
+                    }
+                    if(rejectReasons.length == 0){
+                        LowQualityRejectReason lowQualityRejectReason = lowQualityRejectReasonMapper.getByRejectReason(bytedanceMaterialRejectReason.getRejectReason().trim());
+                        if(!Check.isNull(lowQualityRejectReason)){
+                            bytedanceMaterialRejectReason.setIsLowQuality(1);
+                        }
+                    }else {
+                        for(int k=1;k<rejectReasons.length;k++){
+                            LowQualityRejectReason lowQualityRejectReason = lowQualityRejectReasonMapper.getByRejectReason("广告体验优化建议:"+rejectReasons[k].trim());
+                            if(!Check.isNull(lowQualityRejectReason)){
+                                bytedanceMaterialRejectReason.setIsLowQuality(1);
+                            }
+                        }
+                    }
+                    if(!Check.isNull(object.getString("title"))){
+                        bytedanceMaterialRejectReason.setTitle(object.getString("title"));
+                    }
+                    if(!Check.isNull(object.getJSONArray("image_id"))){
+                        bytedanceMaterialRejectReason.setImageId(object.getJSONArray("image_id").toJSONString());
+                    }
+                    if(!Check.isNull(object.getString("video_id"))){
+                        bytedanceMaterialRejectReason.setVideoId(object.getString("video_id"));
+                    }
+                    if(!Check.isNull(ad_reject.getLong("ad_id"))){
+                        bytedanceMaterialRejectReason.setAdId(ad_reject.getLong("ad_id"));
+                    }
+                    int res =  BytedanceMaterialRejectReasonMapper.replaceIntoDb(bytedanceMaterialRejectReason);
+                    if(res == 0){
+                        System.out.println(bytedanceMaterialRejectReason.toString());
+                    }
+//                    BytedanceMaterialRejectReasonMapper.insert(bytedanceMaterialRejectReason);
+                }
+            }
+        }
+    }
+
+
+}

+ 36 - 10
jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/advertise/service/impl/BytedanceVideoSlogenInfoServiceImpl.java

@@ -16,6 +16,8 @@ import org.springframework.stereotype.Service;
 
 import javax.annotation.Resource;
 import java.math.BigDecimal;
+import java.text.DecimalFormat;
+import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
 
@@ -30,16 +32,19 @@ public class BytedanceVideoSlogenInfoServiceImpl extends ServiceImpl<BytedanceVi
     @Resource
     BytedanceVideoSlogenInfoMapper bytedanceVideoSlogenInfoMapper;
 
+
     @Override
-    public void insertSlogans(String videoCode, JSONArray slogans,String userId){
+    public void insertSlogans(Long projectId, String videoCode, JSONArray slogans,String userId){
         if(null==slogans||slogans.isEmpty()){
             return;
         }
         for(int i=0;i<slogans.size();i++){
             JSONObject sloganObject = slogans.getJSONObject(i);
             String title = sloganObject.getString("title");
+            title = title.replaceAll("\\{\\{","{");
+            title = title.replaceAll("\\}\\}","}");
             String creativeWordIds = Check.isNull(sloganObject.getJSONArray("creative_word_ids")) ? "" : sloganObject.getJSONArray("creative_word_ids").toJSONString();
-            BytedanceVideoSlogenInfo slogenInfo = new BytedanceVideoSlogenInfo(videoCode,title,userId,creativeWordIds);
+            BytedanceVideoSlogenInfo slogenInfo = new BytedanceVideoSlogenInfo(projectId,videoCode,title,userId,creativeWordIds);
             this.save(slogenInfo);
         }
     }
@@ -57,12 +62,23 @@ public class BytedanceVideoSlogenInfoServiceImpl extends ServiceImpl<BytedanceVi
         return this.list(queryWrapper);
     }
     @Override
-    public Result getVideoSlogenReport(String accountId,String keyWord, String startTime, String endTime, Integer pageNum, Integer pageSize){
+    public Result getVideoSlogenReport(String userId, String projectId,String keyWord,Integer status, String startTime, String endTime, Integer pageNum, Integer pageSize){
+
+        List<String> projectIdList = new ArrayList<>();
+        //查询普通用户的全量查询,当前用户所有项目
+        if(Check.isNull(projectId)){
+            projectIdList = bytedanceVideoSlogenInfoMapper.getProjectByUserId(userId);
+        }else if(projectId == "admin"){//管理员的全量查询
+            projectIdList = null;
+        }else { //不论什么权限的用户的单独搜索一个项目
+            projectIdList.add(projectId);
+        }
+
         PageHelper.startPage(pageNum,pageSize);
-        List<Map<String, Object>> videoSlogenReportList = bytedanceVideoSlogenInfoMapper.selectVideoSlogenReportByAccountIdAndTitle(accountId,keyWord, startTime, endTime);
+        List<Map<String, Object>> videoSlogenReportList = bytedanceVideoSlogenInfoMapper.selectVideoSlogenReportByAccountIdAndTitle(projectIdList, keyWord, status, startTime, endTime);
 
         if(Check.isNull(videoSlogenReportList)){
-            return Result.error("还没有此文案报表数据,请将此文案投放跑量!");
+            return Result.successMsg("还没有此文案报表数据,请将此文案投放跑量!",videoSlogenReportList);
         }
 
         for (Map<String, Object> videoSlogenReportMap: videoSlogenReportList) {
@@ -75,34 +91,44 @@ public class BytedanceVideoSlogenInfoServiceImpl extends ServiceImpl<BytedanceVi
             BigDecimal showNum = new BigDecimal(Check.isNull(videoSlogenReportMap.get("showNum")) ? "0" : videoSlogenReportMap.get("showNum").toString());
             BigDecimal convertNum = new BigDecimal(Check.isNull(videoSlogenReportMap.get("convertNum")) ? "0" : videoSlogenReportMap.get("convertNum").toString());
 
+            DecimalFormat decimalFormat = new DecimalFormat("0.00#");
+            videoSlogenReportMap.put("cost", decimalFormat.format(cost));
+            videoSlogenReportMap.put("click", click);
+            videoSlogenReportMap.put("showNum", showNum);
+            videoSlogenReportMap.put("convertNum", convertNum);
+
             //被除数不能为0
             if (StringUtils.equals("0",showNum.toString())){
                 videoSlogenReportMap.put("costPerThousandShow", 0);
                 videoSlogenReportMap.put("clickRate", 0);
             }else {
                 BigDecimal costPerThousandShow = cost.multiply(new BigDecimal(1000)).divide(showNum, 2, BigDecimal.ROUND_HALF_UP);
-                videoSlogenReportMap.put("costPerThousandShow", costPerThousandShow);
+                videoSlogenReportMap.put("costPerThousandShow", decimalFormat.format(costPerThousandShow));
                 BigDecimal clickRate = click.multiply(new BigDecimal(100)).divide(showNum, 2, BigDecimal.ROUND_HALF_UP);
-                videoSlogenReportMap.put("clickRate", clickRate);
+                videoSlogenReportMap.put("clickRate", decimalFormat.format(clickRate));
             }
             if (StringUtils.equals("0", convertNum.toString())) {
                 videoSlogenReportMap.put("costConvert", 0);
             }else {
                 BigDecimal costConvert = cost.divide(convertNum, 2, BigDecimal.ROUND_HALF_UP);
-                videoSlogenReportMap.put("costConvert", costConvert);
+                videoSlogenReportMap.put("costConvert", decimalFormat.format(costConvert));
             }
             if (StringUtils.equals("0", click.toString())) {
                 videoSlogenReportMap.put("costPerClick", 0);
                 videoSlogenReportMap.put("convertRate", 0);
             }else {
                 BigDecimal costPerClick = cost.divide(click, 2, BigDecimal.ROUND_HALF_UP);
-                videoSlogenReportMap.put("costPerClick", costPerClick);
+                videoSlogenReportMap.put("costPerClick", decimalFormat.format(costPerClick));
                 BigDecimal convertRate = convertNum.multiply(new BigDecimal(100)).divide(click,2,BigDecimal.ROUND_HALF_UP);
-                videoSlogenReportMap.put("convertRate", convertRate);
+                videoSlogenReportMap.put("convertRate", decimalFormat.format(convertRate));
             }
         }
 
         PageInfo<Map<String, Object>> pageInfo = new PageInfo<Map<String, Object>>(videoSlogenReportList);
         return Result.successMsg("数据加载成功。",pageInfo);
     }
+    @Override
+    public List<BytedanceVideoSlogenInfo> getVideoSlogenBySlogenAndProjectId(String slogen, Long projectId){
+        return bytedanceVideoSlogenInfoMapper.getDataBySlogenAndProjectId(slogen, projectId);
+    }
 }

+ 61 - 0
jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/common/entity/BytedanceOperationLog.java

@@ -0,0 +1,61 @@
+package org.jeecg.modules.bytedance.common.entity;
+
+import java.io.Serializable;
+import java.util.Date;
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.baomidou.mybatisplus.annotation.TableField;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import org.springframework.format.annotation.DateTimeFormat;
+import org.jeecgframework.poi.excel.annotation.Excel;
+
+/**
+ * 操作日志
+ * @author jeecg-boot
+ * @date   2021-06-17
+ * @version V1.0
+ */
+@Data
+@TableName("ctop_bytedance_operation_log")
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+@ApiModel(value="ctop_bytedance_operation_log对象", description="操作日志")
+public class BytedanceOperationLog {
+    
+	/**id*/
+	@TableId(type = IdType.UUID)
+    @ApiModelProperty(value = "id")
+	private Integer id;
+	/**原始数据*/
+	@Excel(name = "原始数据", width = 15)
+    @ApiModelProperty(value = "原始数据")
+	private Object oldData;
+	/**修改后的数据*/
+	@Excel(name = "修改后的数据", width = 15)
+    @ApiModelProperty(value = "修改后的数据")
+	private Object newData;
+	/**操作类型*/
+	@Excel(name = "操作类型", width = 15)
+    @ApiModelProperty(value = "操作类型")
+	private String operationType;
+	/**操作内容*/
+	@Excel(name = "操作内容", width = 15)
+    @ApiModelProperty(value = "操作内容")
+	private Object operationContent;
+	/**创建人id*/
+	@Excel(name = "创建人id", width = 15)
+    @ApiModelProperty(value = "创建人id")
+	private String createById;
+	/**创建时间*/
+	@Excel(name = "创建时间", width = 20, format = "yyyy-MM-dd HH:mm:ss")
+	@JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
+    @DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
+    @ApiModelProperty(value = "创建时间")
+	private Date createTime;
+}

+ 3 - 0
jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/common/entity/MaterialInfo.java

@@ -163,4 +163,7 @@ public class MaterialInfo {
     //视频关联广告语信息--头条
     @TableField(exist = false)
     private JSONArray slogans;
+
+    @TableField(exist = false)
+    private JSONArray materialIds;
 }

+ 17 - 0
jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/common/mapper/BytedanceOperationLogMapper.java

@@ -0,0 +1,17 @@
+package org.jeecg.modules.bytedance.common.mapper;
+
+import java.util.List;
+
+import org.apache.ibatis.annotations.Param;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.jeecg.modules.bytedance.common.entity.BytedanceOperationLog;
+
+/**
+ * 操作日志
+ * @author jeecg-boot
+ * 2021-06-17
+ * @version V1.0
+ */
+public interface BytedanceOperationLogMapper extends BaseMapper<BytedanceOperationLog> {
+
+}

+ 5 - 0
jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/common/mapper/xml/BytedanceOperationLogMapper.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.jeecg.modules.bytedance.common.mapper.BytedanceOperationLogMapper">
+
+</mapper>

+ 2 - 7
jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/common/mapper/xml/UserAllocationMapper.xml

@@ -85,15 +85,10 @@
 
     <select id="getAccountIdsByUserId" resultType="com.alibaba.fastjson.JSONObject">
         SELECT
-            allocation.account_id,
-            allocation.auth_name,
-            project.project_name as project_name
+            allocation.account_id
         FROM
             ctop_user_allocation allocation
-            left join ctop_project project on allocation.project_id = project.id
-        WHERE
-            allocation.user_id = #{userId}
-          and allocation.account_status=0
+            where 1 =1 and allocation.project_id in (select DISTINCT project_id from ctop_project_member where user_id = #{userId})
     </select>
 
 

+ 14 - 0
jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/common/service/IBytedanceOperationLogService.java

@@ -0,0 +1,14 @@
+package org.jeecg.modules.bytedance.common.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import org.jeecg.modules.bytedance.common.entity.BytedanceOperationLog;
+
+/**
+ * 操作日志
+ * @author jeecg-boot
+ * 2021-06-17
+ * @version V1.0
+ */
+public interface IBytedanceOperationLogService extends IService<BytedanceOperationLog> {
+
+}

+ 4 - 1
jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/common/service/IMaterialInfoService.java

@@ -14,9 +14,12 @@ import java.util.List;
  * @date 2019-10-11
  */
 public interface IMaterialInfoService extends IService<MaterialInfo> {
-    MaterialInfo getParams(String signature, Integer status);
+    MaterialInfo getParams(String signature, Integer status,Long projectId);
 
 
     Result updMaterialOfflineById(List<String> ids, Integer offlineFlag);
 
+
+    public MaterialInfo getDetilByMaterialId(String materialId);
+
 }

+ 19 - 0
jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/common/service/impl/BytedanceOperationLogServiceImpl.java

@@ -0,0 +1,19 @@
+package org.jeecg.modules.bytedance.common.service.impl;
+
+import org.jeecg.modules.bytedance.common.entity.BytedanceOperationLog;
+import org.jeecg.modules.bytedance.common.mapper.BytedanceOperationLogMapper;
+import org.jeecg.modules.bytedance.common.service.IBytedanceOperationLogService;
+import org.springframework.stereotype.Service;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+
+/**
+ * 操作日志
+ * @author jeecg-boot
+ * 2021-06-17
+ * @version V1.0
+ */
+@Service
+public class BytedanceOperationLogServiceImpl extends ServiceImpl<BytedanceOperationLogMapper, BytedanceOperationLog> implements IBytedanceOperationLogService {
+
+}

+ 12 - 3
jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/common/service/impl/MaterialInfoServiceImpl.java

@@ -7,6 +7,7 @@ import org.jeecg.common.api.vo.Result;
 import org.jeecg.modules.bytedance.common.entity.MaterialInfo;
 import org.jeecg.modules.bytedance.common.mapper.MaterialInfoMapper;
 import org.jeecg.modules.bytedance.common.service.IMaterialInfoService;
+import org.jeecg.modules.bytedance.common.utils.Check;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
@@ -30,7 +31,7 @@ public class MaterialInfoServiceImpl extends ServiceImpl<MaterialInfoMapper, Mat
 
 
     @Override
-    public MaterialInfo getParams(String signature, Integer status) {
+    public MaterialInfo getParams(String signature, Integer status,Long projectId) {
         QueryWrapper<MaterialInfo>queryWrapper = new QueryWrapper<>();
         if(null!=signature&&!"".equals(signature.trim())){
             queryWrapper.eq("code",signature);
@@ -38,11 +39,13 @@ public class MaterialInfoServiceImpl extends ServiceImpl<MaterialInfoMapper, Mat
         if(null!=status){
             queryWrapper.eq("status",status);
         }
+        if(null!=projectId){
+            queryWrapper.eq("project_id",projectId);
+        }
         queryWrapper.orderByDesc("create_time").last("limit 1");
         return this.getOne(queryWrapper);
     }
 
-
     /**
      *
      * @description: 素材下线
@@ -60,7 +63,13 @@ public class MaterialInfoServiceImpl extends ServiceImpl<MaterialInfoMapper, Mat
         return Result.successMsg("素材下线成功。", null);
     }
 
-
+    @Override
+    public MaterialInfo getDetilByMaterialId(String materialId){
+        if(Check.isNull(materialId)){
+            return null;
+        }
+        return this.getById(materialId);
+    }
 }
 
 

+ 12 - 4
jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/common/utils/ExcelUtil.java

@@ -54,12 +54,20 @@ public class ExcelUtil {
                     int lastCellNum = row.getPhysicalNumberOfCells();
 //          String[] cells = new String[row.getPhysicalNumberOfCells()];
                     //循环当前行
-                    for(int cellNum = firstCellNum; cellNum <= lastCellNum;cellNum++){
-                        Cell cell = row.getCell(cellNum);
-//            cells[cellNum] = getCellValue(cell);
-                        String cellValue = getCellValue(cell);
+                    String cellValue = getCellValue(row.getCell(firstCellNum));
+//                        String cellValue = getCellValue(cell);
+                    if(!Check.isNull(cellValue)){ //只要当前行的第一列
                         list.add(cellValue);
                     }
+//                    for(int cellNum = firstCellNum; cellNum <= lastCellNum;cellNum++){
+//                        Cell cell = row.getCell(cellNum);
+////            cells[cellNum] = getCellValue(cell);
+//                        String cellValue = getCellValue(row.getCell(firstCellNum));
+////                        String cellValue = getCellValue(cell);
+//                        if(!Check.isNull(cellValue)){
+//                            list.add(cellValue);
+//                        }
+//                    }
 
                 }
             }

+ 39 - 0
jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/common/utils/GetCampaignNum.java

@@ -0,0 +1,39 @@
+package org.jeecg.modules.bytedance.common.utils;
+
+/**
+ * Administrator
+ * 2021/6/3
+ **/
+public class GetCampaignNum {
+
+
+    /**
+     *
+     * @param campaignCnt 组数量
+     * @param campaignAdCnt 每个组最大创建计划数
+     * @param countNum 当天已创建条数
+     * @return
+     */
+    public static Long getCampaignNameNum(int campaignCnt,Long campaignAdCnt, int countNum){
+/*
+        countNum = 61;
+        campaignAdCnt = 10L;
+        campaignCnt = 1;*/
+
+        Long zu = countNum / campaignAdCnt;
+        Long yu = countNum % campaignAdCnt;
+        //System.out.println("余---"+yu);
+        // 不能整除 有余数 则 组 = 商 + 1
+        // 整除 组 = 商
+        Long count = yu != 0 ? zu.intValue()+1 : zu;
+       // 账户配置中的组数量 < 当前 组序号
+        if (count.intValue() <= campaignCnt){
+            System.out.println("组序号----------"+count);
+        }else {
+            System.out.println("组序号-超过了规定的最大值-----"+count);
+        }
+        return count;
+    }
+
+
+}

+ 167 - 0
jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/common/utils/StringUtils.java

@@ -4,6 +4,7 @@ import java.math.BigDecimal;
 import java.math.RoundingMode;
 import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
@@ -174,6 +175,29 @@ public class StringUtils {
         return dest;
     }
 
+    /**
+     * 使用正则表达式提取中括号中的内容
+     * @param msg
+     * @return
+     */
+    public static List<String> extractMessageByRegular(String msg){
+
+        List<String> list=new ArrayList<String>();
+        Pattern p = Pattern.compile("\\{([^}]*)\\}");
+        Matcher m = p.matcher(msg);
+        while(m.find()){
+            list.add(m.group().substring(1, m.group().length()-1));
+        }
+        return list;
+    }
+
+    public static void main(String[] args) {
+        String msg = "PerformanceManager{第1个中括号}Product{第2个中括号}<{第3个中括号}79~";
+        List<String> list = extractMessageByRegular(msg);
+        for (int i = 0; i < list.size(); i++) {
+            System.out.println(i+"-->"+list.get(i));
+        }
+    }
 
 
     /**
@@ -224,4 +248,147 @@ public class StringUtils {
         }
         return reuslt;
     }
+
+    public static int lengthAsSlogan(String a)  {
+        char[] c = a.toCharArray();
+        int count=0;
+        for (char d : c) {
+            Character.UnicodeBlock ub = Character.UnicodeBlock.of(d);
+            if (ub == Character.UnicodeBlock.GENERAL_PUNCTUATION
+                    || ub == Character.UnicodeBlock.CJK_SYMBOLS_AND_PUNCTUATION
+                    || ub == Character.UnicodeBlock.HALFWIDTH_AND_FULLWIDTH_FORMS
+                    || ub == Character.UnicodeBlock.CJK_COMPATIBILITY_FORMS
+                    || ub == Character.UnicodeBlock.VERTICAL_FORMS
+                    || ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS
+                    || ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A
+                    || ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_B
+                    || ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_C
+                    || ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_D
+                    || ub == Character.UnicodeBlock.CJK_COMPATIBILITY_IDEOGRAPHS
+                    || ub == Character.UnicodeBlock.CJK_COMPATIBILITY_IDEOGRAPHS_SUPPLEMENT) {
+                count++;
+            }
+
+        }
+        BigDecimal strNum = new BigDecimal(count);
+        BigDecimal strlen = new BigDecimal(a.length());
+        BigDecimal res = strlen.subtract(strNum).divide(new BigDecimal(2),0, BigDecimal.ROUND_UP).add(strNum);
+        return res.intValue();
+    }
+
+    public static String replaceCreativeWordPackageText(String str){
+        int left = str.indexOf("{");
+        int right = str.indexOf("}");
+        if(left < 0){
+            return null;
+        }
+        String newStr = str.substring(left+1, right);
+        return newStr;
+    }
+
+
+
+    /**
+     * 获取字符串的长度,如果有中文,则每个中文字符计为2位
+     * @param value 指定的字符串
+     * @return 字符串的长度
+     */
+    public static int length(String value) {
+        int valueLength = 0;
+        String chinese = "[\u0391-\uFFE5]";
+        Pattern number = Pattern.compile("^[-\\+]?[\\d]*$");
+        /* 获取字段值的长度,如果含中文字符,则每个中文字符长度为2,否则为1 */
+        for (int i = 0; i < value.length(); i++) {
+            /* 获取一个字符 */
+            String temp = value.substring(i, i + 1);
+            /* 判断是否为中文字符 */
+            if (temp.matches(chinese)) {
+                valueLength += 2;
+            }else {
+                /* 其他字符长度为1 */
+                valueLength += 1;
+            }
+        }
+        return valueLength;
+    }
+
+
+    /**
+     * 字符串(如果是中文则占2个字符 的 字符串) 截取
+     * @param str 如果是中文则占2个字符 的 字符串
+     * @param length 要截取的长度
+     * @return
+     * @throws Exception
+     */
+    public static String subStr50(String str, int length) throws Exception {
+        byte[] bytes = str.getBytes("Unicode");
+        int n = 0; // 表示当前的字节数
+        int i = 2; // 要截取的字节数,从第3个字节开始
+        for (; i < bytes.length && n < length; i++) {
+            // 奇数位置,如3、5、7等,为UCS2编码中两个字节的第二个字节
+            if (i % 2 == 1) {
+                n++; // 在UCS2第二个字节时n加1
+            }
+            else {
+                // 当UCS2编码的第一个字节不等于0时,该UCS2字符为汉字,一个汉字算两个字节
+                if (bytes[i] != 0) {
+                    n++;
+                }
+            }
+        }
+        // 如果i为奇数时,处理成偶数
+        if (i % 2 == 1) {
+            // 该UCS2字符是汉字时,去掉这个截一半的汉字
+            if (bytes[i - 1] != 0){
+                i = i - 1;
+                // 该UCS2字符是字母或数字,则保留该字符
+            }else{
+                i = i + 1;
+            }
+        }
+        return new String(bytes, 0, i, "Unicode");
+    }
+
+
+    /**
+     * 计划名称 中的 素材名称 截取
+     * @param adName
+     * @return
+     * @throws Exception
+     */
+    public static String adNameSubMaterial(String adName){
+        try {
+            //String a = "20210814-促活-站内-RTA-sf_jrtt_huichuangch_ptb_297571-ocpm-[这是这是这是这这是这是这是这是这是这是这是这是这这是这是这是这是这是]-0728";
+            //获取[] 中的内容 --素材名称
+            if (adName.contains("[") && adName.contains("]")){
+                String materialName = adName.substring(adName.indexOf("["),adName.indexOf("]")+1);
+                //广告计划名称 总长度(1个中文 占 2个字符)
+                int adNameLength = length(adName.replaceAll("[\\[\\]]", ""));
+                //素材名称 长度 (1个中文 占 2个字符)
+                int materialLength = length(materialName.replaceAll("[\\[\\]]", ""));
+                // 计划名称 字符总长度
+                int totalLength = (adNameLength / 2) + (adNameLength % 2);
+                //不能超过 47个长度
+                if (totalLength > 47){
+                    //要截取的素材名称的长度
+                    int sub = (totalLength - 47) * 2 ;
+                    // 去除 [] 并截取素材名称
+                    String mateName = materialName.replaceAll("[\\[\\]]", "");
+                    String rep = subStr50(mateName,materialLength - sub);
+                    return adName.replace(materialName, rep);
+                }else {
+                    return adName.replaceAll("[\\[\\]]", "");
+                }
+            }else {
+                return adName;
+            }
+
+
+        }catch (Exception e){
+            e.printStackTrace();
+        }
+        return null;
+    }
+
+
 }

+ 6 - 2
jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/report/entity/vo/ReportCostVo.java

@@ -15,6 +15,7 @@ public class ReportCostVo implements Serializable {
     private String id;
     //花费
     private double cost;
+    private String costStr;
     //展示量
     private Integer showNum;
     //点击量
@@ -34,9 +35,9 @@ public class ReportCostVo implements Serializable {
     //计划名称
     private String adName;
     //出价 - 目标转化出价
-    private BigDecimal cpaBid;
+    private String cpaBid;
     // 出价
-    private BigDecimal Bid;
+    private String Bid;
     //平均千次展显费用 = 总花费/展示数 * 1000
     private String averageShow;
     //平均点击单价 = 花费 / 点击数
@@ -56,5 +57,8 @@ public class ReportCostVo implements Serializable {
     //操作状态
     private String optStatus;
 
+    //计划预算
+    private BigDecimal adBudget;
+
 
 }

+ 11 - 0
jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/report/mapper/BytedanceAdvertiserHourlyReportMapper.java

@@ -20,12 +20,23 @@ public interface BytedanceAdvertiserHourlyReportMapper extends BaseMapper<Byteda
 
 
     List<ReportCostVo> getReportCostInfo(@Param("accountId") String accountId, @Param("startTime") String startTime, @Param("endTime") String endTime);
+
+    //账户日报 数据
+    List<ReportCostVo> selectPlanCostInfoCount(@Param("accountId") String accountId, @Param("planId") String planId, @Param("startTime") String startTime, @Param("endTime") String endTime);
+    //账户 时报
     List<ReportCostVo> getReportCostInfoStage(@Param("accountId") String accountId, @Param("startTime") String startTime, @Param("endTime") String endTime);
+    //查询上阶段 同时间点的 日报 数据信息
+    List<ReportCostVo> getReportCostInfoStageLast(@Param("accountId") String accountId, @Param("startTime") String startTime, @Param("endTime") String endTime,@Param("statHour") String statHour);
 
     Map<String,Object> selAcountIdCostMax(@Param("userId") String userId, @Param("type") String type);
 
     Map<String,Object> selectAccountCost(@Param("accountId") String accountId);
 
+    //计划日报
+    List<ReportCostVo> selectReportPlanCostInfoDay(@Param("accountId") String accountId, @Param("planId") String planId, @Param("startTime") String startTime, @Param("endTime") String endTime);
+    //计划 时报
     List<ReportCostVo> selectReportPlanCostInfo(@Param("accountId") String accountId, @Param("planId") String planId, @Param("startTime") String startTime, @Param("endTime") String endTime);
+    //查询上阶段 同时间点的 日报 数据信息
+    List<ReportCostVo> selectReportPlanCostHourLast(@Param("accountId") String accountId,@Param("planId") String planId,@Param("startTime") String startTime, @Param("endTime") String endTime,@Param("statHour") Integer statHour);
 
 }

+ 146 - 9
jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/report/mapper/xml/BytedanceAdvertiserHourlyReportMapper.xml

@@ -31,7 +31,7 @@
 
     </select>
 
-    <!-- 阶段 查询  账户时报数据信息 -->
+    <!-- 查询  账户时报 数据信息 -->
     <select id="getReportCostInfoStage" resultType="org.jeecg.modules.bytedance.report.entity.vo.ReportCostVo">
         SELECT
             id,
@@ -39,20 +39,60 @@
             SUM(show_num) AS showNum,
             SUM(click) AS click,
             SUM(convert_num) AS convertNum,
-            SUM(stat_hour) AS statHour,
             stat_datetime,
-            stat_datetime AS time,
+            stat_hour AS time,
+            create_time
+        FROM
+            ctop_bytedance_report_advertiser_hourly
+        WHERE 1 = 1
+        <if test="accountId !=null and accountId != ''">
+            AND advertiser_id = #{accountId}
+        </if>
+        <if test="startTime !=null and startTime != ''">
+            AND stat_datetime &gt;= #{startTime}
+        </if>
+        <if test="endTime !=null and endTime != ''">
+            AND stat_datetime &lt;= #{endTime}
+        </if>
+        GROUP BY
+            stat_hour
+        ORDER BY
+            stat_datetime,
+            stat_hour
+    </select>
+
+    <!-- 查询  账户时报  时间点截至 数据信息 -->
+    <select id="getReportCostInfoStageLast" resultType="org.jeecg.modules.bytedance.report.entity.vo.ReportCostVo">
+        SELECT
+            id,
+            SUM(cost) AS cost,
+            SUM(show_num) AS showNum,
+            SUM(click) AS click,
+            SUM(convert_num) AS convertNum,
+            stat_datetime,
+            stat_hour AS time,
             create_time
         FROM
             ctop_bytedance_report_advertiser_hourly
         WHERE
-            advertiser_id = #{accountId}
+        1 = 1
+        <if test="accountId !=null and accountId != ''">
+            AND advertiser_id = #{accountId}
+        </if>
+        <if test="startTime !=null and startTime != ''">
             AND stat_datetime &gt;= #{startTime}
+        </if>
+        <if test="endTime !=null and endTime != ''">
             AND stat_datetime &lt;= #{endTime}
+        </if>
+        <if test="statHour !=null and statHour != ''">
+            AND stat_hour &lt;= #{statHour}
+        </if>
         GROUP BY
-            stat_datetime
+            stat_hour
         ORDER BY
-            stat_datetime
+            stat_datetime,
+            stat_hour
     </select>
 
 <!-- 查询用户下 花费最高的 账户-->
@@ -108,6 +148,35 @@
         ad_id,
         ad_name,
         create_time,
+        update_time,
+        MAX(stat_hour) as statHour
+        FROM
+        ctop_bytedance_report_plan_hourly
+        where 1 =1
+        <if test="accountId !=null and accountId != ''">
+            and advertiser_id = #{accountId}
+        </if>
+        <if test="planId !=null and planId != ''">
+            and ad_id = #{planId}
+        </if>
+        <if test="startTime !=null and startTime != ''">
+            and DATE_FORMAT(stat_datetime,'%Y-%m-%d') &gt;= #{startTime}
+        </if>
+        <if test="endTime !=null and endTime != ''">
+            and DATE_FORMAT(stat_datetime,'%Y-%m-%d') &lt;= #{endTime}
+        </if>
+         GROUP BY ad_id
+        ORDER BY cost DESC
+
+    </select>
+<!-- 查询  上阶段 计划时报 数据-->
+    <select id="selectReportPlanCostHourLast" resultType="org.jeecg.modules.bytedance.report.entity.vo.ReportCostVo">
+        SELECT
+        stat_datetime,
+        sum(cost) AS cost,
+        ad_id,
+        ad_name,
+        create_time,
         update_time
         FROM
         ctop_bytedance_report_plan_hourly
@@ -119,12 +188,80 @@
             and ad_id = #{planId}
         </if>
         <if test="startTime !=null and startTime != ''">
-            and stat_datetime &gt;= #{startTime}
+            and DATE_FORMAT(stat_datetime,'%Y-%m-%d') &gt;= #{startTime}
+        </if>
+        <if test="endTime !=null and endTime != ''">
+            and DATE_FORMAT(stat_datetime,'%Y-%m-%d') &lt;= #{endTime}
+        </if>
+        <if test="statHour !=null and statHour != ''">
+            and stat_hour &lt;= #{statHour}
+        </if>
+         GROUP BY ad_id
+        ORDER BY cost DESC
+
+    </select>
+
+<!-- 查询 计划日报 数据-->
+    <select id="selectReportPlanCostInfoDay" resultType="org.jeecg.modules.bytedance.report.entity.vo.ReportCostVo">
+        SELECT
+        stat_datetime,
+        sum(show_num) AS showNum,
+        sum(click) AS click,
+        sum(convert_num) AS convertNum,
+        sum(cost) AS cost,
+        ad_id,
+        ad_name,
+        create_time,
+        update_time
+        FROM
+        ctop_bytedance_report_plan_daily
+        where 1 =1
+        <if test="accountId !=null and accountId != ''">
+            and advertiser_id = #{accountId}
+        </if>
+        <if test="planId !=null and planId != ''">
+            and ad_id = #{planId}
+        </if>
+        <if test="startTime !=null and startTime != ''">
+            and DATE_FORMAT(stat_datetime,'%Y-%m-%d') &gt;= #{startTime}
+        </if>
+        <if test="endTime !=null and endTime != ''">
+            and DATE_FORMAT(stat_datetime,'%Y-%m-%d') &lt;= #{endTime}
+        </if>
+        group BY ad_id
+        ORDER BY cost DESC
+
+    </select>
+
+
+
+    <!-- 查询 账户日报 数据 数据-->
+    <select id="selectPlanCostInfoCount" resultType="org.jeecg.modules.bytedance.report.entity.vo.ReportCostVo">
+        SELECT
+        stat_datetime,
+        sum(show_num) AS showNum,
+        sum(click) AS click,
+        sum(convert_num) AS convertNum,
+        sum(cost) AS cost,
+        DATE_FORMAT(stat_datetime,'%Y-%m-%d') AS time,
+        create_time,
+        update_time
+        FROM
+        ctop_bytedance_report_advertiser_daily
+        where 1 =1
+        <if test="accountId !=null and accountId != ''">
+            and advertiser_id = #{accountId}
+        </if>
+        <if test="planId !=null and planId != ''">
+            and ad_id = #{planId}
+        </if>
+        <if test="startTime !=null and startTime != ''">
+            and DATE_FORMAT(stat_datetime,'%Y-%m-%d') &gt;= #{startTime}
         </if>
         <if test="endTime !=null and endTime != ''">
-            and stat_datetime &lt;= #{endTime}
+            and DATE_FORMAT(stat_datetime,'%Y-%m-%d') &lt;= #{endTime}
         </if>
-        GROUP BY ad_id
+        GROUP BY stat_datetime
         ORDER BY cost DESC
 
     </select>

+ 5 - 5
jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/report/mapper/xml/BytedanceReportMaterialDailyMapper.xml

@@ -6,11 +6,11 @@
     <select id="selectMaterialDailyReportByAccountId" resultType="java.util.HashMap">
         SELECT
             video.video_url as videoUrl,
-            report.material_id as materialId,
-            report.cost,
-            report.show_material as showMaterial,
-            report.click,
-            report.convert_material as convertMaterial,
+            concat(report.material_id,'') as materialId,
+            sum(report.cost) as cost,
+            sum(report.show_material) as showMaterial,
+            sum(report.click) as click,
+            sum(report.convert_material) as convertMaterial,
             creative.count,
             video.material_upload_time as materialUploadTime,
             video.poster_url as posterUrl,

+ 156 - 99
jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/report/service/impl/BytedanceAdvertiserHourlyReportServiceImpl.java

@@ -5,6 +5,7 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.github.pagehelper.PageHelper;
 import com.github.pagehelper.PageInfo;
+import com.sun.xml.bind.v2.TODO;
 import org.jeecg.common.api.vo.Result;
 import org.jeecg.modules.bytedance.advertise.entity.AiBytedanceAdvertiserStrategy;
 import org.jeecg.modules.bytedance.advertise.entity.ByteDanceAdvertisePlan;
@@ -43,6 +44,7 @@ public class BytedanceAdvertiserHourlyReportServiceImpl extends ServiceImpl<Byte
 
     //时段数组
     private final static List<String> TIMES = Arrays.asList("0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15","16","17","18","19","20","21","22","23");
+    public static final String PATTEN_DEFAULT_YMD = "yyyy-MM-dd";
 
 
     @Resource
@@ -71,32 +73,62 @@ public class BytedanceAdvertiserHourlyReportServiceImpl extends ServiceImpl<Byte
         DecimalFormat df = new DecimalFormat("0.00%");
         Map<String,Object> resultMap = new HashMap<>();
         double compare = 0;
+        double lastCost = 0;
+        double nowCost = 0;
         List<ReportCostVo> nowCostList = new ArrayList<>();
         List<ReportCostVo> lastCostList = new ArrayList<>();
 
-        //当前时间段数据
-        nowCostList = bytedanceAdvertiserHourlyReportMapper.getReportCostInfo(accountId,startTime,endTime);
-
-        //更新时间
-        List<ReportCostVo> updTimeList = nowCostList.stream().sorted(Comparator.comparing(ReportCostVo::getCreateTime)).collect(Collectors.toList());
-        resultMap.put("updTime",Check.isNull(updTimeList) ? new Date() : updTimeList.get(0).getCreateTime());
-
-        //当前阶段 总花费
-        double nowCost = nowCostList.stream().mapToDouble(ReportCostVo::getCost).sum();
-        resultMap.put("nowCost", String.format("%.2f", nowCost));
 
         //根据本阶段时间 获取 上阶段 开始-截至 时间
         Map<String,String> lastTimeMap = TimeStartAndEndUtil.getStartEndTime(startTime,endTime);
-        //上阶段数据
-        lastCostList = bytedanceAdvertiserHourlyReportMapper.getReportCostInfo(accountId,lastTimeMap.get("lastTimeStart"),lastTimeMap.get("lastTimeEnd"));
-        //上阶段花费
-        double lastCost = lastCostList.stream().mapToDouble(ReportCostVo::getCost).sum();
-        resultMap.put("lastCost", String.format("%.2f", lastCost));
 
-        //环比 =(当前花费 - 上阶段花费 )/ 上阶段花费
-        compare = (nowCost - lastCost) / lastCost;
-        //resultMap.put("compare", Double.isNaN(compare) ? "0" : df.format(compare));
-        resultMap.put("compare", Double.isNaN(compare) ? "0" : String.format("%.2f", compare*100));
+        /**
+         * 日期相差不为 0 则 展示 日报(每天数据总和)数据
+         * 日期相差天数为0  则 展示 24小时 数据
+         */
+        if (!lastTimeMap.get("daysBetween").equals("0")){
+            // 账户 日报 阶段 数据
+            nowCostList = bytedanceAdvertiserHourlyReportMapper.selectPlanCostInfoCount(accountId,null,startTime,endTime);
+            lastCostList = bytedanceAdvertiserHourlyReportMapper.selectPlanCostInfoCount(accountId,null,lastTimeMap.get("lastTimeStart"),lastTimeMap.get("lastTimeEnd"));
+            //当前阶段 总花费
+            nowCost = nowCostList.stream().mapToDouble(ReportCostVo::getCost).sum();
+            resultMap.put("nowCost", String.format("%.2f", nowCost));
+            //上阶段花费
+            lastCost = lastCostList.stream().mapToDouble(ReportCostVo::getCost).sum();
+            resultMap.put("lastCost", String.format("%.2f", lastCost));
+            //环比 =(当前花费 - 上阶段 同时段 花费 )/ 上阶段花费
+            compare = (nowCost - lastCost) / lastCost;
+            //resultMap.put("compare", Double.isNaN(compare) ? "0" : df.format(compare));
+            resultMap.put("compare", new Double(lastCost).intValue() == 0 ? "0" : String.format("%.2f", compare*100));
+
+        }else{
+            // 账户 当前时间段数据
+            nowCostList = bytedanceAdvertiserHourlyReportMapper.getReportCostInfoStage(accountId,startTime,endTime);
+            //上阶段数据
+            lastCostList = bytedanceAdvertiserHourlyReportMapper.getReportCostInfoStageLast(accountId,lastTimeMap.get("lastTimeStart"),lastTimeMap.get("lastTimeEnd"),null);
+            //计算环比 =(当前花费 - 上阶段 同时段 花费 )/ 上阶段花费
+            //获取 同时段 的花费
+            ReportCostVo statHourVo = new ReportCostVo();
+            if (nowCostList.size() > 0){
+                statHourVo = nowCostList.get(nowCostList.size()-1);
+            }
+            List<ReportCostVo> compareCost = bytedanceAdvertiserHourlyReportMapper.getReportCostInfoStageLast(accountId,lastTimeMap.get("lastTimeStart"),lastTimeMap.get("lastTimeEnd"),statHourVo.getTime());
+            double lastCompareCost = compareCost.stream().mapToDouble(ReportCostVo::getCost).sum();
+            //当前阶段 总花费
+            nowCost = nowCostList.stream().mapToDouble(ReportCostVo::getCost).sum();
+            resultMap.put("nowCost", String.format("%.2f", nowCost));
+            //上阶段花费
+            lastCost = lastCostList.stream().mapToDouble(ReportCostVo::getCost).sum();
+            resultMap.put("lastCost", String.format("%.2f", lastCost));
+            //环比 =(当前花费 - 上阶段 同时段 花费 )/ 上阶段花费
+            compare = (nowCost - lastCompareCost) / lastCompareCost;
+            //resultMap.put("compare", Double.isNaN(compare) ? "0" : df.format(compare));
+            resultMap.put("compare", new Double(lastCompareCost).intValue() == 0 ? "0" : String.format("%.2f", compare*100));
+        }
+
+        //更新时间
+        List<ReportCostVo> updTimeList = nowCostList.stream().sorted(Comparator.comparing(ReportCostVo::getCreateTime)).collect(Collectors.toList());
+        resultMap.put("updTime",Check.isNull(updTimeList) ? new Date() : updTimeList.get(0).getCreateTime());
 
         //花费占比 = 花费 / 账户预算
         //获取账户预算
@@ -106,34 +138,32 @@ public class BytedanceAdvertiserHourlyReportServiceImpl extends ServiceImpl<Byte
         strategyQueryWrapper.last("limit 1");
         AiBytedanceAdvertiserStrategy strategy = aiBytedanceAdvertiserStrategyMapper.selectOne(strategyQueryWrapper);
         //没有预算则使用上阶段花费
-        double accountBudget = Check.isNull(strategy) ? lastCost : strategy.getAccountBudget().doubleValue();
+        double accountBudget = Check.isNull(strategy) || strategy.getAccountBudget().intValue() == 0 ? lastCost : strategy.getAccountBudget().doubleValue();
         //花费占比
         double costShare = nowCost / accountBudget;
-        resultMap.put("costShare", Double.isNaN(costShare) ? "0" : df.format(costShare));
+        resultMap.put("costShare",new Double(accountBudget).intValue() == 0 ? "0" : df.format(costShare));
 
         //获取 本阶段  转化成本;转化数;转化率;平均千次展现费用。数据展示
         Map nowMap = getCost(nowCostList);
         // 上阶段数据
         Map lastMap = getCost(lastCostList);
 
-        /**
-         * 日期相差不为 0 则 展示 时间段(每天数据总和)数据
-         * 日期相差天数为0  则 展示 24小时 数据
-         */
-        if (!lastTimeMap.get("daysBetween").equals("0")){
-            //阶段 数据
-          nowCostList = bytedanceAdvertiserHourlyReportMapper.getReportCostInfoStage(accountId,startTime,endTime);
-          lastCostList = bytedanceAdvertiserHourlyReportMapper.getReportCostInfoStage(accountId,lastTimeMap.get("lastTimeStart"),lastTimeMap.get("lastTimeEnd"));
+        if (nowCostList.size() > 0){
+            //当前阶段 每个时间 的 转化成本;转化数;转化率;平均千次展现费用。数据展示
+            nowMap.put("costList", getCostList(nowCostList,startTime,endTime,lastTimeMap.get("daysBetween")));
+        }else {
+            nowMap.put("costList",Arrays.asList());
+        }
+
+        if (lastCostList.size() > 0){
+            //上个阶段 每个时间 的 转化成本;转化数;转化率;平均千次展现费用。数据展示
+            lastMap.put("costList", getCostList(lastCostList,lastTimeMap.get("lastTimeStart"),lastTimeMap.get("lastTimeEnd"),lastTimeMap.get("daysBetween")));
+        }else {
+            lastMap.put("costList",Arrays.asList());
         }
-        //当前阶段 每个时间 的 转化成本;转化数;转化率;平均千次展现费用。数据展示
-        nowMap.put("costList", getCostList(nowCostList,startTime,endTime,lastTimeMap.get("daysBetween")));
-        //上个阶段 每个时间 的 转化成本;转化数;转化率;平均千次展现费用。数据展示
-        lastMap.put("costList", getCostList(lastCostList,lastTimeMap.get("lastTimeStart"),lastTimeMap.get("lastTimeEnd"),lastTimeMap.get("daysBetween")));
 
         resultMap.put("nowMap", nowMap);
         resultMap.put("lastMap", lastMap);
-
-
         return Result.successMsg("成功。",resultMap);
     }
 
@@ -150,16 +180,16 @@ public class BytedanceAdvertiserHourlyReportServiceImpl extends ServiceImpl<Byte
         //转化成本 = 总花费 / 转化数
         int converNum = list.stream().mapToInt(ReportCostVo::getConvertNum).sum();
         double conver = cost / new Double(converNum);
-        map.put("conver",Double.isNaN(conver) ? "0" : String.format("%.2f", conver));
+        map.put("conver",converNum == 0 ? "0" : String.format("%.2f", conver));
         map.put("converNum", converNum);
         //转化率 = 转化数 / 点击数 * 100
         int clickNum = list.stream().mapToInt(ReportCostVo::getClick).sum();
         double click = Double.valueOf(converNum) /  Double.valueOf(clickNum) * 100;
-        map.put("converRate", Double.isNaN(click) ? "0" : String.format("%.2f", click));
+        map.put("converRate", clickNum == 0 ? "0" : String.format("%.2f", click));
         // 平均千次展显费用 = 总花费/展示数 * 1000
         int showNum = list.stream().mapToInt(ReportCostVo::getShowNum).sum();
         double show = (cost / showNum) * 1000 ;
-        map.put("averageShow", Double.isNaN(show) ? "0" : String.format("%.2f", show));
+        map.put("averageShow", showNum == 0 ? "0" : String.format("%.2f", show));
         return map;
     }
 
@@ -207,6 +237,7 @@ public class BytedanceAdvertiserHourlyReportServiceImpl extends ServiceImpl<Byte
         if (!Check.isNull(reduceList)){
             reduceList.forEach(reduce ->{
                 ReportCostVo vo = new ReportCostVo();
+                vo.setStatDatetime(startTime);
                 vo.setTime(reduce);
                 vo.setConver("0");//转化成本
                 vo.setConvertNum(0);//转化数
@@ -287,70 +318,96 @@ public class BytedanceAdvertiserHourlyReportServiceImpl extends ServiceImpl<Byte
      */
     @Override
     public Result getReportPlanCost(String accountId, String startTime, String endTime,Integer pageNum,Integer pageSize) throws Exception {
+        SimpleDateFormat sf = new SimpleDateFormat(PATTEN_DEFAULT_YMD);
         DecimalFormat df = new DecimalFormat("0.00%");
+        DecimalFormat df1 = new DecimalFormat("0.00");
+        List<ReportCostVo> reportCostVoList = new ArrayList<ReportCostVo>();
+        List<ReportCostVo> lastReportCostVoList = new ArrayList<ReportCostVo>();
         //根据本阶段时间 获取 上阶段 开始-截至 时间
         Map<String,String> lastTimeMap = TimeStartAndEndUtil.getStartEndTime(startTime,endTime);
-        PageHelper.startPage(pageNum,pageSize);
-        //查询计划数据时报
-       List<ReportCostVo> reportCostVoList = bytedanceAdvertiserHourlyReportMapper.selectReportPlanCostInfo(accountId, null, startTime,endTime);
-       reportCostVoList.forEach(reportCostVo -> {
-           //出价
-           QueryWrapper<ByteDanceAdvertisePlan> planQueryWrapper = new QueryWrapper<>();
-           planQueryWrapper.eq("account_id",accountId);
-           planQueryWrapper.last("limit 1");
-           ByteDanceAdvertisePlan planInfo = byteDanceAdvertisePlanMapper.selectOne(planQueryWrapper);
-           reportCostVo.setCpaBid(planInfo.getCpaBid());
-           reportCostVo.setBid(planInfo.getBid());
-
-           // 平均千次展显费用 = 总花费/展示数 * 1000
-           double show = 0;
-           if (reportCostVo.getShowNum() != 0){
-               show = (reportCostVo.getCost() / reportCostVo.getShowNum()) * 1000 ;
-           }
-           reportCostVo.setAverageShow(String.format("%.2f", show));
-
-           double avgClick = 0;
-           double clickRate = 0;
-           double convetRate = 0;
-           if (reportCostVo.getClick() != 0){
-               //平均点击单价 = 花费 / 点击数
-               avgClick = reportCostVo.getCost() / reportCostVo.getClick().doubleValue();
-               //点击率 = 点击数 / 展示数
-               clickRate = reportCostVo.getClick().doubleValue() / reportCostVo.getShowNum().doubleValue();
-               //转化率 = 转化数 / 点击数 * 100
-               convetRate = Double.valueOf(reportCostVo.getConvertNum()) /  Double.valueOf(reportCostVo.getClick()) * 100;
-           }
-
-           reportCostVo.setAverageClick(String.format("%.2f", avgClick));
-           reportCostVo.setClickRate(df.format(clickRate));
-           reportCostVo.setConverRate(String.format("%.2f", convetRate));
-
-           //转化成本 = 总花费 / 转化数
-           double conver = 0;
-           if (reportCostVo.getConvertNum() != 0){
-               conver = reportCostVo.getCost() / reportCostVo.getConvertNum();
-           }
-           reportCostVo.setConver(String.format("%.2f", conver));
-
-           // 计划id 和 上阶段 时间 查询 上阶段数据
-           List<ReportCostVo> lastReportCostVoList = bytedanceAdvertiserHourlyReportMapper.selectReportPlanCostInfo(accountId, reportCostVo.getAdId(), lastTimeMap.get("lastTimeStart"),lastTimeMap.get("lastTimeEnd"));
-           double compare = 0;
-           if (lastReportCostVoList.size() > 0){
-               if (lastReportCostVoList.get(0).getCost() !=0){
-                   //环比 =(当前花费 - 上阶段花费 )/ 上阶段花费
-                   compare = (reportCostVo.getCost() - lastReportCostVoList.get(0).getCost()) / lastReportCostVoList.get(0).getCost();
-               }
-           }
-           reportCostVo.setCompare(df.format(compare));
-
-           //操作状态
-           QueryWrapper<ByteDanceAdvertisePlan> advertisePlanQueryWrapper = new QueryWrapper<>();
-           advertisePlanQueryWrapper.eq("account_id",accountId);
-           advertisePlanQueryWrapper.eq("id",reportCostVo.getAdId());
-           advertisePlanQueryWrapper.last("limit 1");
-           ByteDanceAdvertisePlan advertisePlan = byteDanceAdvertisePlanMapper.selectOne(advertisePlanQueryWrapper);
-           reportCostVo.setOptStatus(advertisePlan.getOptStatus());
-       });
+        String nowTime = sf.format(new Date());
+
+        if (!startTime.equals(nowTime)){
+            //日报
+            PageHelper.startPage(pageNum,pageSize);
+            reportCostVoList = bytedanceAdvertiserHourlyReportMapper.selectReportPlanCostInfoDay(accountId, null, startTime,endTime);
+        }else {
+            PageHelper.startPage(pageNum,pageSize);
+            //时报
+           reportCostVoList = bytedanceAdvertiserHourlyReportMapper.selectReportPlanCostInfo(accountId, null, startTime,endTime);
+
+        }
+
+
+        for (ReportCostVo reportCostVo : reportCostVoList) {
+            reportCostVo.setCostStr(String.format("%.2f",reportCostVo.getCost()));
+            //出价  ctop_bytedance_advertise_plan 广告计划信息表
+            QueryWrapper<ByteDanceAdvertisePlan> planQueryWrapper = new QueryWrapper<>();
+            planQueryWrapper.eq("account_id",accountId);
+            planQueryWrapper.eq("id",reportCostVo.getAdId());
+            planQueryWrapper.last("limit 1");
+            ByteDanceAdvertisePlan planInfo = byteDanceAdvertisePlanMapper.selectOne(planQueryWrapper);
+            reportCostVo.setCpaBid(Check.isNull(planInfo) ? "0" : String.format("%.2f",planInfo.getCpaBid()));
+            reportCostVo.setBid(Check.isNull(planInfo) ? "0" : String.format("%.2f",planInfo.getBid()));
+            //广告预算 (修改出价不能大于广告计划预算)
+            reportCostVo.setAdBudget(Check.isNull(planInfo) ? new BigDecimal(0) : planInfo.getBudget());
+
+            // 平均千次展显费用 = 总花费/展示数 * 1000
+            double show = 0;
+            if (reportCostVo.getShowNum() != 0){
+                show = (reportCostVo.getCost() / reportCostVo.getShowNum()) * 1000 ;
+            }
+            reportCostVo.setAverageShow(String.format("%.2f", show));
+
+            double avgClick = 0;
+            double clickRate = 0;
+            double convetRate = 0;
+            if (reportCostVo.getClick() != 0){
+                //平均点击单价 = 花费 / 点击数
+                avgClick = reportCostVo.getCost() / reportCostVo.getClick().doubleValue();
+                //点击率 = 点击数 / 展示数
+                clickRate = reportCostVo.getClick().doubleValue() / reportCostVo.getShowNum().doubleValue();
+                //转化率 = 转化数 / 点击数 * 100
+                convetRate = Double.valueOf(reportCostVo.getConvertNum()) /  Double.valueOf(reportCostVo.getClick()) * 100;
+            }
+
+            reportCostVo.setAverageClick(String.format("%.2f", avgClick));
+            reportCostVo.setClickRate(df.format(clickRate));
+            reportCostVo.setConverRate(String.format("%.2f", convetRate));
+
+            //转化成本 = 总花费 / 转化数
+            double conver = 0;
+            if (reportCostVo.getConvertNum() != 0){
+                conver = reportCostVo.getCost() / reportCostVo.getConvertNum();
+            }
+            reportCostVo.setConver(String.format("%.2f", conver));
+
+            //日报
+            if (!startTime.equals(nowTime)){
+                // 计划id 和 上阶段 时间 查询 上阶段数据
+                lastReportCostVoList = bytedanceAdvertiserHourlyReportMapper.selectReportPlanCostInfoDay(accountId, reportCostVo.getAdId(), lastTimeMap.get("lastTimeStart"),lastTimeMap.get("lastTimeEnd"));
+            }else {
+                //时报
+                //查询上阶段 同时间点 之前的 时报 数据信息
+                lastReportCostVoList = bytedanceAdvertiserHourlyReportMapper.selectReportPlanCostHourLast(accountId,reportCostVo.getAdId(),lastTimeMap.get("lastTimeStart"),lastTimeMap.get("lastTimeEnd"),reportCostVo.getStatHour());
+            }
+            double compare = 0;
+            if (lastReportCostVoList.size() > 0){
+                if (lastReportCostVoList.get(0).getCost() !=0){
+                    //环比 =(当前花费 - 上阶段花费 )/ 上阶段花费
+                    compare = (reportCostVo.getCost() - lastReportCostVoList.get(0).getCost()) / lastReportCostVoList.get(0).getCost();
+                }
+            }
+            reportCostVo.setCompare(df.format(compare));
+
+            //操作状态
+            QueryWrapper<ByteDanceAdvertisePlan> advertisePlanQueryWrapper = new QueryWrapper<>();
+            advertisePlanQueryWrapper.eq("account_id",accountId);
+            advertisePlanQueryWrapper.eq("id",reportCostVo.getAdId());
+            advertisePlanQueryWrapper.last("limit 1");
+            ByteDanceAdvertisePlan advertisePlan = byteDanceAdvertisePlanMapper.selectOne(advertisePlanQueryWrapper);
+            reportCostVo.setOptStatus(Check.isNull(advertisePlan) ? "0" : advertisePlan.getOptStatus());
+        }
         PageInfo<ReportCostVo> pageInfo = new PageInfo<ReportCostVo>(reportCostVoList);
         return Result.successMsg("成功。", pageInfo);
     }

+ 13 - 5
jeecg-boot-bytedance/src/main/java/org/jeecg/modules/bytedance/report/service/impl/BytedanceReportMaterialDailyServiceImpl.java

@@ -15,6 +15,7 @@ import org.springframework.stereotype.Service;
 
 import javax.annotation.Resource;
 import java.math.BigDecimal;
+import java.text.DecimalFormat;
 import java.text.SimpleDateFormat;
 import java.util.Date;
 import java.util.List;
@@ -60,30 +61,37 @@ public class BytedanceReportMaterialDailyServiceImpl extends ServiceImpl<Bytedan
             BigDecimal showMaterial = new BigDecimal(Check.isNull(dailyReportMap.get("showMaterial")) ? "0" : dailyReportMap.get("showMaterial").toString());
             BigDecimal convertMaterial = new BigDecimal(Check.isNull(dailyReportMap.get("convertMaterial")) ? "0" : dailyReportMap.get("convertMaterial").toString());
 
+
+            DecimalFormat decimalFormat = new DecimalFormat("0.00#");
+            dailyReportMap.put("cost", decimalFormat.format(cost));
+            dailyReportMap.put("click", click);
+            dailyReportMap.put("showMaterial", showMaterial);
+            dailyReportMap.put("convertMaterial", convertMaterial);
+
             //被除数不能为0
             if (StringUtils.equals("0",showMaterial.toString())){
                 dailyReportMap.put("costPerThousandShow", 0);
                 dailyReportMap.put("clickRate", 0);
             }else {
                 BigDecimal costPerThousandShow = cost.multiply(new BigDecimal(1000)).divide(showMaterial, 2, BigDecimal.ROUND_HALF_UP);
-                dailyReportMap.put("costPerThousandShow", costPerThousandShow);
+                dailyReportMap.put("costPerThousandShow", decimalFormat.format(costPerThousandShow));
                 BigDecimal clickRate = click.multiply(new BigDecimal(100)).divide(showMaterial, 2, BigDecimal.ROUND_HALF_UP);
-                dailyReportMap.put("clickRate", clickRate);
+                dailyReportMap.put("clickRate", decimalFormat.format(clickRate));
             }
             if (StringUtils.equals("0", convertMaterial.toString())) {
                 dailyReportMap.put("costConvert", 0);
             }else {
                 BigDecimal costConvert = cost.divide(convertMaterial, 2, BigDecimal.ROUND_HALF_UP);
-                dailyReportMap.put("costConvert", costConvert);
+                dailyReportMap.put("costConvert", decimalFormat.format(costConvert));
             }
             if (StringUtils.equals("0", click.toString())) {
                 dailyReportMap.put("costPerClick", 0);
                 dailyReportMap.put("convertRate", 0);
             }else {
                 BigDecimal costPerClick = cost.divide(click, 2, BigDecimal.ROUND_HALF_UP);
-                dailyReportMap.put("costPerClick", costPerClick);
+                dailyReportMap.put("costPerClick", decimalFormat.format(costPerClick));
                 BigDecimal convertRate = convertMaterial.multiply(new BigDecimal(100)).divide(click,2,BigDecimal.ROUND_HALF_UP);
-                dailyReportMap.put("convertRate", convertRate);
+                dailyReportMap.put("convertRate", decimalFormat.format(convertRate));
             }
         }
 

+ 43 - 9
jeecg-boot-module-system/src/main/java/org/jeecg/modules/bytedance/advertise/controller/AiBytedanceAdvertiserStrategyController.java

@@ -38,7 +38,7 @@ import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 
 /**
- * 头条智能投放账户配置信息表
+ * 头条智能投放账户配置
  * @author jeecg-boot
  * @date   2021-04-20
  * @version V1.0
@@ -125,6 +125,14 @@ public class AiBytedanceAdvertiserStrategyController {
 	@PostMapping(value = "/addBytedanceStrategy")
 	public Result addBytedanceStrategy(@RequestBody AiBytedanceAdvertiserStrategy aiBytedanceAdvertiserStrategy) {
 		try {
+			//复制功能 防止前端传id到后台
+			aiBytedanceAdvertiserStrategy.setId(null);
+			// 组名称 计划名称 是否重复
+			/*Result<AiBytedanceAdvertiserStrategy> resultName = aiBytedanceAdvertiserStrategyService.getStrategyInfoByName(aiBytedanceAdvertiserStrategy);
+			if (!resultName.isSuccess()) {
+				return Result.error(resultName.getMessage());
+			}*/
+
 			return aiBytedanceAdvertiserStrategyService.addBytedanceStrategy(aiBytedanceAdvertiserStrategy);
 		} catch (Exception e) {
 			log.error(e.getMessage(),e);
@@ -140,6 +148,14 @@ public class AiBytedanceAdvertiserStrategyController {
 	@ApiOperation(value="头条智能投放账户配置信息表-编辑", notes="头条智能投放账户配置信息表-编辑")
 	@PutMapping(value = "/edit")
 	public Result<AiBytedanceAdvertiserStrategy> edit(@RequestBody AiBytedanceAdvertiserStrategy aiBytedanceAdvertiserStrategy) {
+		// 组名称 计划名称 是否重复
+		/*
+		Result<AiBytedanceAdvertiserStrategy> resultName = aiBytedanceAdvertiserStrategyService.getStrategyInfoByName(aiBytedanceAdvertiserStrategy);
+		if (!resultName.isSuccess()) {
+			return Result.errorMsg(resultName.getMessage());
+		}
+		*/
+		CtopOauthToken token = tokenService.getOauthTokenByAccountId(String.valueOf(aiBytedanceAdvertiserStrategy.getAccountId()));
 		//修改后预算金额不能低于当前已消费金额的105%
 		QueryWrapper<RuleDataAccount> ruleDataAccountQueryWrapper = new QueryWrapper<>();
 		ruleDataAccountQueryWrapper.eq("account_id",aiBytedanceAdvertiserStrategy.getAccountId());
@@ -176,6 +192,15 @@ public class AiBytedanceAdvertiserStrategyController {
 			if (!ok) {
 				return Result.errorMsg("修改失败!");
 			}
+			//账户预算 同步 头条
+			//BUDGET_MODE_DAY-日预算
+			// BUDGET_MODE_INFINITE-不限
+			String accountBudgetMode = aiBytedanceAdvertiserStrategy.getAccountBudgetMode().equals("1") ? "BUDGET_MODE_INFINITE" : "BUDGET_MODE_DAY";
+			Result resultBudget = marketingService.updateBudget(token,accountBudgetMode,aiBytedanceAdvertiserStrategy.getAccountBudget());
+			/*if (!resultBudget.isSuccess()){
+				return Result.errorMsg(resultBudget.getMessage());
+			}*/
+
 		}
 		return Result.successMsg("修改成功!", null);
 
@@ -256,9 +281,10 @@ public class AiBytedanceAdvertiserStrategyController {
 	@PutMapping(value = "/updStaById")
 	public Result updStaById(@RequestParam("id")String id,
 							 @ApiParam("状态(0开-1关)") @RequestParam("state") String state,
-							 @ApiParam("账户id") @RequestParam("accountId") String accountId) {
+							 @ApiParam("账户id") @RequestParam("accountId") String accountId,
+							 @ApiParam("素材类型") @RequestParam("creativeImageMode") String creativeImageMode) {
 		try {
-			return aiBytedanceAdvertiserStrategyService.updStaById(id,state,accountId);
+			return aiBytedanceAdvertiserStrategyService.updStaById(id,state,accountId,creativeImageMode);
 		}catch (Exception e){
 			log.error("修改状态(0开-1关)失败",e);
 			return Result.error("请求失败,请联系开发人员!");
@@ -362,7 +388,8 @@ public class AiBytedanceAdvertiserStrategyController {
 			return result;
 		}
 		strategys.forEach(strategy -> executorService.submit(()->{
-			aiBytedanceAdvertiserStrategyService.customCreativeSupplement(strategy, hour,strategy.getAdOpenUrl());
+				aiBytedanceAdvertiserStrategyService.customCreativeSupplement(strategy, hour,strategy.getAdOpenUrl());
+
 		}));
 		ResultMapUtils.setResultMap(result, StatusCode.COMMON_SUCCESS);
 		return result;
@@ -394,6 +421,9 @@ public class AiBytedanceAdvertiserStrategyController {
 					map.put("platform", "APP_IOS");
 				}
 			}
+			if (map.get("code").toString().equals("-1")){
+				return Result.error(map.get("error").toString()+"请输入正确的链接。");
+			}
 			return Result.successMsg("根据下载链接获取应用包名成功", map);
 		}catch (Exception e){
 			log.error("根据下载链接获取应用包名异常",e);
@@ -424,15 +454,19 @@ public class AiBytedanceAdvertiserStrategyController {
 	@GetMapping(value = "/getAdAudiencePackage")
 	public Result getAdAudiencePackage(@RequestParam(value = "accountId",required = false) String accountId,
 									   @RequestParam(value = "landingType",required = false) String landingType,
-									   @RequestParam(value = "deliveryRange",required = false,defaultValue = "DEFAULT") String deliveryRange) {
+									   @RequestParam(value = "deliveryRange",required = false) String deliveryRange) {
 		try {
 			if (Check.isNull(accountId)){
 				return Result.errorMsg("请选择账户。");
 			}
-			/*if (Check.isNull(landingType)){
-				return Result.errorMsg("投放内容不能为空");
-			}*/
-			return aiBytedanceAdvertiserStrategyService.getAdAudiencePackage(accountId,landingType,deliveryRange);
+			// 默认 定向包
+			Result resultDefault = aiBytedanceAdvertiserStrategyService.getAdAudiencePackage(accountId,landingType,"DEFAULT");
+			//穿山甲定向包
+			Result resultUnion = aiBytedanceAdvertiserStrategyService.getAdAudiencePackage(accountId,landingType,"UNION");
+			List listDefault = (List) resultDefault.getResult();
+			List listUnion = (List) resultUnion.getResult();
+			listDefault.addAll(listUnion);
+			return Result.successMsg("获取定向包成功。",listDefault);
 		}catch (Exception e){
 			log.error("获取定向包异常",e);
 			return Result.error("请求失败,请联系开发人员!");

+ 158 - 31
jeecg-boot-module-system/src/main/java/org/jeecg/modules/bytedance/advertise/controller/BytedanceGeneralCopywriterController.java

@@ -1,18 +1,25 @@
 package org.jeecg.modules.bytedance.advertise.controller;
 
 import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONArray;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import lombok.extern.slf4j.Slf4j;
+import org.apache.shiro.SecurityUtils;
 import org.jeecg.common.api.vo.Result;
 import org.jeecg.common.system.query.QueryGenerator;
+import org.jeecg.common.system.vo.LoginUser;
 import org.jeecg.common.util.oConvertUtils;
+import org.jeecg.modules.bytedance.advertise.entity.ByteDanceCreativeWordPackage;
 import org.jeecg.modules.bytedance.advertise.entity.ByteDanceGeneralCopywriter;
 import org.jeecg.modules.bytedance.advertise.service.IByteDanceGeneralCopywriterService;
+import org.jeecg.modules.bytedance.common.utils.Check;
 import org.jeecg.modules.bytedance.common.utils.ExcelUtil;
+import org.jeecg.modules.bytedance.common.utils.StringUtils;
+import org.jeecg.modules.system.service.ISysRoleService;
 import org.jeecgframework.poi.excel.ExcelImportUtil;
 import org.jeecgframework.poi.excel.def.NormalExcelConstants;
 import org.jeecgframework.poi.excel.entity.ExportParams;
@@ -28,8 +35,13 @@ import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import java.io.IOException;
 import java.io.UnsupportedEncodingException;
+import java.math.BigDecimal;
 import java.net.URLDecoder;
+import java.text.DecimalFormat;
 import java.util.*;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
 /**
  * 头条通用文案上传接口
  * @author jeecg-boot
@@ -43,37 +55,61 @@ import java.util.*;
 public class BytedanceGeneralCopywriterController {
     @Autowired
     private IByteDanceGeneralCopywriterService byteDanceGeneralCopywriterService;
+    @Autowired
+    private ISysRoleService sysRoleService;
+
 
     @ApiOperation(value="通用文案库-上传excel", notes="通用文案库-上传excel")
     @PostMapping("/loadExcel")
     public Result<ByteDanceGeneralCopywriter> loadExcel(
-            @RequestParam("accountId") Long accountId,
+            @RequestParam("accountId") String accountId,
             @RequestParam("excelFile") MultipartFile excelFile){
         Result<ByteDanceGeneralCopywriter> result = new Result<>();
+        List<ByteDanceGeneralCopywriter> byteDanceGeneralCopywriterList = new ArrayList<ByteDanceGeneralCopywriter>();
+        String[] accountIds = new String[]{accountId};
+        if(accountId.contains(",")){
+            accountIds = accountId.split(",");
+        }
         try {
             List<String> list = ExcelUtil.readExcel(excelFile);
-            //去掉null值
-            list.removeIf(Objects::isNull);
-            //去掉空字符串
-            Iterator<String> iterator = list.iterator();
-            while (iterator.hasNext()){
-                if (iterator.next() == ""){
-                    iterator.remove();
+
+            for (String accountIdStr:accountIds) {
+                for (String str: list) {
+                    ByteDanceGeneralCopywriter byteDanceGeneralCopywriter = new ByteDanceGeneralCopywriter(Long.parseLong(accountIdStr),str);
+                    int len = StringUtils.lengthAsSlogan(str);
+                    int left = str.indexOf("{");
+                    int right = str.indexOf("}");
+                    if(left >= 0 || right >= 0){
+                        List<String> strs = new ArrayList<>();
+                        ByteDanceCreativeWordPackage creativeWordPackage = byteDanceGeneralCopywriterService.selectCreativeWordPackageByName(str.substring(left+1, right));
+                        strs.add(creativeWordPackage.getCreativeWordId().toString());
+                        len = len - (right - left) + creativeWordPackage.getMaxWordLen();
+                        String nextStr = str.substring(right+1,str.length());
+                        left = nextStr.indexOf("{");
+                        right = nextStr.indexOf("}");
+                        if(left >= 0 || right >= 0){
+                            ByteDanceCreativeWordPackage creativeWordPackage2 = byteDanceGeneralCopywriterService.selectCreativeWordPackageByName(nextStr.substring(left+1, right));
+                            strs.add(creativeWordPackage2.getCreativeWordId().toString());
+                            len = len - (right - left) + creativeWordPackage2.getMaxWordLen();
+                        }
+                        byteDanceGeneralCopywriter.setCreativeWordIds(Arrays.toString(strs.toArray()).replaceAll(" ",""));
+                    }
+                    //校验标题长度,长度小于5和大于30的全部过滤
+                    if(len<5 || len>30){
+                        continue;
+                    }
+
+                    //截取{}中的内容,匹配动态词包id,拼接数组存储
+                    byteDanceGeneralCopywriterList.add(byteDanceGeneralCopywriter);
                 }
             }
-            List<ByteDanceGeneralCopywriter> byteDanceGeneralCopywriterList = new ArrayList<ByteDanceGeneralCopywriter>();
 
-            //遍历list,查看数据
-            for (String textCopywriter : list) {
-                byteDanceGeneralCopywriterList.add(new ByteDanceGeneralCopywriter(accountId,textCopywriter));
-            }
 
             byteDanceGeneralCopywriterService.saveBatch(byteDanceGeneralCopywriterList);
-            result.success("添加成功!");
-
+            result.success("添加成功"+byteDanceGeneralCopywriterList.size()+"条"+",失败"+(list.size() * accountIds.length - byteDanceGeneralCopywriterList.size())+"条");
+            result.setCode(0);
         } catch (IOException e) {
-            e.printStackTrace();
-            result.error500("操作失败");
+            result.error500("动态词包格式错误,请重新上传!");
         }
         return result;
     }
@@ -104,15 +140,29 @@ public class BytedanceGeneralCopywriterController {
 
     @ApiOperation(value="通用文案报表展示", notes="通用文案报表展示")
     @GetMapping(value = "/queryPageListByText")
-    public Result queryPageListByText(@RequestParam("accountId") String accountId,
+    public Result queryPageListByText(
+                                      @RequestParam(value = "userId",defaultValue = "") String userId,
+                                      @RequestParam(value = "accountId",defaultValue = "") String accountId,
                                       @RequestParam(value = "keyWord",defaultValue = "") String keyWord,
                                       @RequestParam(value = "startTime",defaultValue = "") String startTime,
                                       @RequestParam(value = "endTime",defaultValue = "") String endTime,
                                       @RequestParam(value = "pageNo", defaultValue="1") Integer pageNo,
-                                      @RequestParam(value = "pageSize", defaultValue="10") Integer pageSize
+                                      @RequestParam(value = "pageSize", defaultValue="10") Integer pageSize,
+                                      @RequestParam(value = "status",required = false)  Integer status
+
     ) {
         try {
-            return byteDanceGeneralCopywriterService.getGeneralCopywriterReport(accountId,keyWord, startTime,endTime,pageNo,pageSize);
+
+            String roleCode = sysRoleService.getRoleCodeByUserId(userId);
+            if (Check.isNull(roleCode)){
+                return Result.errorMsg("请输入正确的用户id。");
+            }
+            //角色为 管理员并且projectId是空表示:全量查询
+            if ("admin".equals(roleCode) && Check.isNull(accountId)) {
+                accountId = "admin";	//传递projectId为admin
+            }
+
+            return byteDanceGeneralCopywriterService.getGeneralCopywriterReport(userId, accountId, keyWord, status, startTime, endTime, pageNo, pageSize);
         }catch (Exception e){
             log.error("通用文案数据-获取文案维度创意报表数据异常",e);
             return Result.error("请求失败,请联系开发人员!");
@@ -164,20 +214,69 @@ public class BytedanceGeneralCopywriterController {
      * @return
      */
     @ApiOperation(value="通用文案库-编辑", notes="通用文案库-编辑")
-    @PutMapping(value = "/edit")
+    @PostMapping(value = "/edit")
     public Result<ByteDanceGeneralCopywriter> edit(@RequestBody ByteDanceGeneralCopywriter byteDanceGeneralCopywriter) {
-        Result<ByteDanceGeneralCopywriter> result = new Result<ByteDanceGeneralCopywriter>();
-        ByteDanceGeneralCopywriter byteDanceGeneralCopywriterEntity = byteDanceGeneralCopywriterService.getById(byteDanceGeneralCopywriter.getId());
-        if(byteDanceGeneralCopywriterEntity==null) {
-            result.error500("未找到对应实体");
-        }else {
+
+        Result<ByteDanceGeneralCopywriter> result = new Result<>();
+        try{
+            ByteDanceGeneralCopywriter byteDanceGeneralCopywriterEntity = byteDanceGeneralCopywriterService.getById(byteDanceGeneralCopywriter.getId());
+            if(byteDanceGeneralCopywriterEntity==null) {
+                return result.error500("未找到对应实体");
+            }
+//            LoginUser user = (LoginUser) SecurityUtils.getSubject().getPrincipal();
+            byteDanceGeneralCopywriter.setUpdateTime(new Date());
+
+            String title = byteDanceGeneralCopywriter.getTextCopywriter();
+            title = title.trim().replaceAll("[\\{]{2,}", "{");
+            title = title.trim().replaceAll("[\\}]{2,}", "}");
+
+            String reg = "\\{[\\u4e00-\\u9fa5\\-]{2,6}\\}";
+            Pattern pattern = Pattern.compile(reg);
+            Matcher matcher = pattern.matcher(title);
+            JSONArray creativeWordIdsArray = new JSONArray();
+
+            int len = StringUtils.lengthAsSlogan(title);
+            int left = title.indexOf("{");
+            int right = title.indexOf("}");
+            if (left >= 0 || right >= 0) {
+                int times = 0;
+                while (matcher.find()) { //此处find()每次被调用后,会偏移到下一个匹配
+                    times++;
+                    if (times >= 3) {
+                        return result.error500("动态词包不合法,词包数量超过2个");
+                    }
+                    String matchStr = matcher.group();//获取当前匹配的值
+                    title = title.replace(matchStr,"");
+
+                    ByteDanceCreativeWordPackage creativeWordPackage = byteDanceGeneralCopywriterService.selectCreativeWordPackageByName(matchStr.substring(1, matchStr.length() - 1));
+                    if (Check.isNull(creativeWordPackage)) {
+                        return result.error500("动态词包不合法,词包不存在或者含有单独的非词包大括号");
+                    }
+                    creativeWordIdsArray.add(creativeWordPackage.getCreativeWordId());
+                    len = len - (right - left) + creativeWordPackage.getMaxWordLen();
+                    left = title.indexOf("{");
+                    right = title.indexOf("}");
+                }
+                if(title.contains("{") || title.contains("}")){
+                    return result.error500("文案含有词包特殊字符,请检查");
+                }
+                byteDanceGeneralCopywriter.setCreativeWordIds(creativeWordIdsArray.toJSONString());
+            }
+            //校验标题长度,长度小于5和大于30的全部过滤
+            if (len < 5 || len > 30) {
+                return result.error500("文案长度不合法,小于5或大于30");
+            }
+
             boolean ok = byteDanceGeneralCopywriterService.updateById(byteDanceGeneralCopywriter);
             if(ok) {
                 result.success("修改成功!");
+                result.setCode(0);
             }
+            return result;
+        } catch (Exception e) {
+            log.error(e.getMessage(),e);
+            return result.error500("操作失败");
         }
-
-        return result;
     }
 
     /**
@@ -188,15 +287,28 @@ public class BytedanceGeneralCopywriterController {
     @ApiOperation(value="通用文案库-通过id删除", notes="通用文案库-通过id删除")
     @DeleteMapping(value = "/delete")
     public Result<?> delete(@RequestParam(name="id") String id) {
+        Result result = new Result();
         try {
-            byteDanceGeneralCopywriterService.removeById(id);
+            ByteDanceGeneralCopywriter generalCopywriter = byteDanceGeneralCopywriterService.getById(id);
+            if(null == generalCopywriter||generalCopywriter.getStatus() == 0){
+                return result.ok("此文案不存在或者已经被删除");
+            }
+            generalCopywriter.setStatus(0);
+            generalCopywriter.setUpdateTime(new Date());
+            boolean ok = byteDanceGeneralCopywriterService.updateById(generalCopywriter);
+            if(ok){
+                result.setMessage("删除成功!");
+                result.setCode(0);
+            }
+            return result;
         } catch (Exception e) {
             log.error("删除失败",e.getMessage());
-            return Result.error("删除失败!");
+            return result.error500("删除失败!");
         }
-        return Result.ok("删除成功!");
+
     }
 
+
     /**
      *  批量删除
      * @param ids
@@ -234,6 +346,21 @@ public class BytedanceGeneralCopywriterController {
         return result;
     }
 
+    @ApiOperation(value="通用文案库-通过id查询", notes="通用文案库-通过id查询")
+    @GetMapping(value = "/queryByTextCopywriter")
+    public Result<List<ByteDanceGeneralCopywriter>> queryByCopywriter(@RequestParam(name="textCopywriter",required=true) String textCopywriter) {
+        Result<List<ByteDanceGeneralCopywriter>> result = new Result<>();
+        List<ByteDanceGeneralCopywriter> byteDanceGeneralCopywriter = byteDanceGeneralCopywriterService.selectAllDataByTextCopywriter(textCopywriter);
+        if(byteDanceGeneralCopywriter==null) {
+            result.error500("未找到对应实体");
+        }else {
+            result.setResult(byteDanceGeneralCopywriter);
+            result.setSuccess(true);
+        }
+        return result;
+    }
+
+
     /**
      * 导出excel
      *

+ 111 - 0
jeecg-boot-module-system/src/main/java/org/jeecg/modules/bytedance/advertise/controller/BytedanceRejectReasonController.java

@@ -0,0 +1,111 @@
+package org.jeecg.modules.bytedance.advertise.controller;
+
+import com.alibaba.fastjson.JSONArray;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+import org.jeecg.common.api.vo.Result;
+import org.jeecg.common.util.DateUtils;
+import org.jeecg.modules.bytedance.advertise.dockapi.MarketingService;
+import org.jeecg.modules.bytedance.advertise.entity.ByteDanceAdvertisePlan;
+import org.jeecg.modules.bytedance.advertise.service.BytedanceRejectReasonService;
+import org.jeecg.modules.bytedance.advertise.service.IByteDanceAdvertisePlanService;
+import org.jeecg.modules.bytedance.common.entity.CtopOauthToken;
+import org.jeecg.modules.bytedance.common.service.ICtopOauthTokenService;
+import org.jeecg.modules.bytedance.common.utils.Check;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.*;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+/**
+ * 广告计划审核建议
+ * @author hxc
+ * 2021-06-28
+ * @version V1.0
+ */
+@Slf4j
+@Api(tags="广告计划审核建议")
+@RestController
+@RequestMapping("/ctop/bytedanceRejectReason")
+public class BytedanceRejectReasonController {
+
+
+
+    static ExecutorService executorService = Executors.newFixedThreadPool(5);
+    @Autowired
+    MarketingService marketingService;
+    @Autowired
+    private ICtopOauthTokenService tokenService;
+    @Autowired
+    IByteDanceAdvertisePlanService byteDanceAdvertisePlanService;
+    @Autowired
+    BytedanceRejectReasonService bytedanceRejectReasonService;
+
+    /**
+     *  编辑
+     * @param hour : 获取当前时间近几个小时的数据。根据广告计划表,近hour个小时新增进来的计划信息,更新他们的审核建议
+     * @return
+     */
+    @ApiOperation(value="广告计划审核建议-从接口获取数据落库", notes="广告计划审核建议-从接口获取数据落库")
+    @GetMapping(value = "/getReasonInRecentHours")
+    public Result getReasonInRecentHours(@RequestParam(value = "hour",required = false) Integer hour) {
+        Result result = new Result();
+        List<CtopOauthToken> tokens = tokenService.selectToutiaoToken();
+        if (null == tokens || tokens.isEmpty()) {
+            System.out.println("未获取到token");
+            result.setCode(500);
+            result.setMessage("未获取到token");
+            return result;
+        }
+
+        System.out.println("---------------------------------->>"+tokens.size()+"个token<<----------------------------------");
+
+        tokens.forEach(token -> executorService.submit(()->getRejectReasonByToken(token, hour)));
+
+
+        return result.success("调用任务已开启");
+    }
+
+
+    public void getRejectReasonByToken(CtopOauthToken token, Integer hour){
+
+            if(token.getAccessTokenExpiresIn().before(new Date())){
+                log.info("token已过期,accountId ==> {}",token.getAccountId());
+                return;
+            }
+
+            List<ByteDanceAdvertisePlan> allPlansByAccountId = byteDanceAdvertisePlanService.getAllPlansByAccountId(token.getAccountId(), Check.isNull(hour)?null:DateUtils.formatDate(DateUtils.addHour(new Date(),-hour),"yyyy-MM-dd HH:mm:ss"));
+
+            if(Check.isNull(allPlansByAccountId) || allPlansByAccountId.size() < 1){
+                return;
+            }
+            List<String> adids = new ArrayList<>();
+            allPlansByAccountId.forEach(plan -> adids.add(plan.getId().toString()));
+
+
+            while(adids.size() > 10){
+                List<String> mulAdids = adids.subList(0,10);
+//                System.out.println("查询的计划是"+Arrays.toString(mulAdids.toArray()));
+                Result dataListResult = marketingService.getRejectReason(token, token.getAccountId().toString(), mulAdids);
+                if(dataListResult.getMessage().toString().contains("No permission to operate account")){
+                    return;
+                }
+                if(Check.isNull(dataListResult.getResult()) || dataListResult.getCode().equals(500)){
+                    continue;
+                }
+                JSONArray jsonArray = JSONArray.parseArray(dataListResult.getResult().toString());
+                bytedanceRejectReasonService.saveRejectReasonToDb(jsonArray,token.getAccountId());
+                adids.removeAll(mulAdids);
+            }
+            Result dataListResult = marketingService.getRejectReason(token, token.getAccountId().toString(), adids);
+            if(Check.isNull(dataListResult.getResult())|| dataListResult.getCode().equals(500)){
+                return;
+            }
+            JSONArray jsonArray = JSONArray.parseArray(dataListResult.getResult().toString());
+            bytedanceRejectReasonService.saveRejectReasonToDb(jsonArray,token.getAccountId());
+        }
+
+}

+ 68 - 11
jeecg-boot-module-system/src/main/java/org/jeecg/modules/bytedance/advertise/controller/BytedanceReportController.java

@@ -2,12 +2,9 @@ package org.jeecg.modules.bytedance.advertise.controller;
 
 import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.JSONObject;
-import com.google.gson.JsonArray;
-import io.lettuce.core.StrAlgoArgs;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import lombok.extern.slf4j.Slf4j;
-import org.apache.commons.beanutils.ConvertUtils;
 import org.jeecg.common.api.vo.Result;
 import org.jeecg.modules.bytedance.advertise.dockapi.MarketingService;
 import org.jeecg.modules.bytedance.advertise.entity.AiBytedanceAdvertiserStrategy;
@@ -16,7 +13,6 @@ import org.jeecg.modules.bytedance.advertise.service.IByteDanceAdvertisePlanServ
 import org.jeecg.modules.bytedance.advertise.vo.PlanSearchVo;
 import org.jeecg.modules.bytedance.common.entity.CtopOauthToken;
 import org.jeecg.modules.bytedance.common.service.ICtopOauthTokenService;
-import org.jeecg.modules.bytedance.common.service.IMaterialInfoService;
 import org.jeecg.modules.bytedance.common.utils.Check;
 import org.jeecg.modules.bytedance.report.service.IBytedanceAdvertiserHourlyReportService;
 import org.jeecg.modules.bytedance.report.service.IBytedancePlanHourlyReportService;
@@ -28,9 +24,11 @@ import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RequestParam;
 import org.springframework.web.bind.annotation.RestController;
 
-import javax.annotation.Resource;
 import java.math.BigDecimal;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
 
 /**
  * 投放数据
@@ -135,11 +133,12 @@ public class BytedanceReportController {
 	}
 
 
-	@ApiOperation(value="投放数据-更新计划出价", notes="投放数据-更新计划出价")
+
+	@ApiOperation(value="投放数据-更新计划出价-bid", notes="投放数据-更新计划出价")
 	@GetMapping(value = "/updateADBid")
 	public Result updateADBid(@RequestParam("accountId") String accountId,
-									@RequestParam("adId") String adId,
-									@RequestParam("bid") BigDecimal bid) {
+							  @RequestParam("adId") String adId,
+							  @RequestParam("bid") BigDecimal bid) {
 		try {
 			CtopOauthToken token = tokenService.getOauthTokenByAccountId(accountId);
 			List<Map<String, Object>> listMap = new ArrayList<>();
@@ -156,9 +155,67 @@ public class BytedanceReportController {
 			byteDanceAdvertisePlan.setBid(bid);
 			//更新 表 定向包id
 			byteDanceAdvertisePlanService.updatePlanOrPackage(byteDanceAdvertisePlan);
-			return Result.successMsg("修改成功。",null);
+			return Result.successMsg("修改出价成功。",null);
+		}catch (Exception e){
+			log.error("投放数据-更新计划出价-bid异常",e);
+			return Result.error("请求失败,请联系开发人员!");
+		}
+	}
+
+
+	@ApiOperation(value="投放数据-更新计划出价-cpaBid-计划预算", notes="投放数据-更新计划出价-计划预算")
+	@GetMapping(value = "/updateADCpaBid")
+	public Result updateADCpaBid(@RequestParam("accountId") String accountId,
+									@RequestParam("adId") String adId,
+									@RequestParam(value = "cpaBid",required = false) BigDecimal cpaBid,
+									@RequestParam(value = "adScheduleTime",required = false) String adScheduleTime,
+									@RequestParam(value = "budgetMode",required = false) String budgetMode,
+									@RequestParam(value = "budget",required = false) BigDecimal budget,
+								 	@RequestParam(value = "downloadUrl",required = false) String downloadUrl) {
+		try {
+			CtopOauthToken token = tokenService.getOauthTokenByAccountId(accountId);
+			PlanSearchVo planSearchVo = new PlanSearchVo();
+			String[] ids = adId.split(",");
+			planSearchVo.setIds(ids);
+			//2 获取广告计划
+			Result result = marketingService.getPlanList(token,planSearchVo,1,1000);
+			if (!result.isSuccess()){
+				return Result.errorMsg(result.getMessage());
+			}
+			JSONObject jsonObject =JSONObject.parseObject(result.getResult().toString());
+			JSONArray array = jsonObject.getJSONArray("list");
+			List<Map<String,Object>> dataList = JSONArray.parseObject(array.toJSONString(),List.class);
+			for (Map<String, Object> map : dataList) {
+				//不需要传modifytime字段
+				//String modifyTime = map.get("modify_time").toString();
+				String modifyTime = null;
+				AiBytedanceAdvertiserStrategy strategy = new AiBytedanceAdvertiserStrategy();
+				strategy.setAccountId(Long.valueOf(accountId));
+				strategy.setAdCpaBid(cpaBid);
+				strategy.setAdScheduleTime(adScheduleTime);
+				if(null!=downloadUrl&&!downloadUrl.trim().equals("")){
+					strategy.setAdDownloadUrl(downloadUrl);
+				}
+				//strategy.setAdBudgetMode(budgetMode);
+				strategy.setAdBudget(budget);
+				//3 修改广告计划 中的 cpaBid
+				Result resultUpd = marketingService.updateAdvertiserPlan(token,adId,modifyTime,strategy);
+				if (!resultUpd.isSuccess()){
+					return Result.errorMsg(resultUpd.getMessage());
+				}
+				ByteDanceAdvertisePlan byteDanceAdvertisePlan = new ByteDanceAdvertisePlan();
+				byteDanceAdvertisePlan.setId(Long.valueOf(adId));
+				byteDanceAdvertisePlan.setCpaBid(cpaBid);
+				byteDanceAdvertisePlan.setScheduleTime(adScheduleTime);
+				byteDanceAdvertisePlan.setBudgetMode(budgetMode);
+				byteDanceAdvertisePlan.setBudget(Check.isNull(budget) ? null : budget);
+				//更新 表 bid || 定向包id || 状态
+				byteDanceAdvertisePlanService.updatePlanOrPackage(byteDanceAdvertisePlan);
+			}
+
+			return Result.successMsg("修改出价成功。",null);
 		}catch (Exception e){
-			log.error("投放数据-更新计划出价异常",e);
+			log.error("投放数据-更新计划出价-cpaBid-计划预算异常",e);
 			return Result.error("请求失败,请联系开发人员!");
 		}
 	}

+ 206 - 25
jeecg-boot-module-system/src/main/java/org/jeecg/modules/bytedance/advertise/controller/BytedanceVideoSlogenInfoController.java

@@ -1,6 +1,7 @@
 package org.jeecg.modules.bytedance.advertise.controller;
 
 import com.alibaba.fastjson.JSONArray;
+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;
@@ -11,17 +12,23 @@ import org.apache.shiro.SecurityUtils;
 import org.jeecg.common.api.vo.Result;
 import org.jeecg.common.system.query.QueryGenerator;
 import org.jeecg.common.system.vo.LoginUser;
+import org.jeecg.modules.bytedance.advertise.entity.ByteDanceCreativeWordPackage;
 import org.jeecg.modules.bytedance.advertise.entity.BytedanceVideoSlogenInfo;
+import org.jeecg.modules.bytedance.advertise.service.IByteDanceGeneralCopywriterService;
 import org.jeecg.modules.bytedance.advertise.service.IBytedanceVideoSlogenInfoService;
 import org.jeecg.modules.bytedance.advertise.service.impl.BytedanceVideoSlogenInfoServiceImpl;
+import org.jeecg.modules.bytedance.common.entity.MaterialInfo;
+import org.jeecg.modules.bytedance.common.service.IMaterialInfoService;
+import org.jeecg.modules.bytedance.common.utils.Check;
+import org.jeecg.modules.bytedance.common.utils.StringUtils;
 import org.jeecg.modules.system.service.ISysRoleService;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.*;
 
 import javax.servlet.http.HttpServletRequest;
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.List;
+import java.util.*;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 
 /**
  * 头条视频文案信息
@@ -36,9 +43,12 @@ import java.util.List;
 public class BytedanceVideoSlogenInfoController {
 	@Autowired
 	private IBytedanceVideoSlogenInfoService bytedanceVideoSlogenInfoService;
-
+	@Autowired
+	private IMaterialInfoService materialInfoService;
 	@Autowired
 	private ISysRoleService sysRoleService;
+	@Autowired
+	private IByteDanceGeneralCopywriterService byteDanceGeneralCopywriterService;
 	/**
 	  * 分页列表查询
 	 * @param slogenInfo
@@ -54,7 +64,7 @@ public class BytedanceVideoSlogenInfoController {
 																 @RequestParam(name="pageSize", defaultValue="10") Integer pageSize,
 																 HttpServletRequest req) {
 		Result<IPage<BytedanceVideoSlogenInfo>> result = new Result<>();
-		slogenInfo.setStatus(1);
+//		slogenInfo.setStatus(1);		//默认不传为所有,传了1是正常,传0是已删除
 		QueryWrapper<BytedanceVideoSlogenInfo> queryWrapper = QueryGenerator.initQueryWrapper(slogenInfo, req.getParameterMap());
 		Page<BytedanceVideoSlogenInfo> page = new Page<>(pageNo, pageSize);
 		IPage<BytedanceVideoSlogenInfo> pageList = bytedanceVideoSlogenInfoService.page(page, queryWrapper);
@@ -65,16 +75,26 @@ public class BytedanceVideoSlogenInfoController {
 
 	@ApiOperation(value="指定文案报表数据展示", notes="指定文案报表数据展示")
 	@GetMapping(value = "/queryPageListByText")
-	public Result queryPageListByText(@RequestParam("accountId") String accountId,
+	public Result queryPageListByText(@RequestParam("userId") String userId,
+									  @RequestParam(value = "projectId",defaultValue = "") String projectId,
 									  @RequestParam(value = "keyWord",defaultValue = "") String keyWord,
 									  @RequestParam(value = "startTime",defaultValue = "") String startTime,
 									  @RequestParam(value = "endTime",defaultValue = "") String endTime,
 									  @RequestParam(value = "pageNo", defaultValue="1") Integer pageNo,
-									  @RequestParam(value = "pageSize", defaultValue="10") Integer pageSize
+									  @RequestParam(value = "pageSize", defaultValue="10") Integer pageSize,
+									  @RequestParam(value = "status",required = false) Integer status
 									) {
 		try {
-			String roleCode = sysRoleService.getRoleCodeByUserId(accountId);
-			return bytedanceVideoSlogenInfoService.getVideoSlogenReport(accountId,keyWord, startTime,endTime,pageNo,pageSize);
+			//查询用户角色
+			String roleCode = sysRoleService.getRoleCodeByUserId(userId);
+			if (Check.isNull(roleCode)){
+				return Result.errorMsg("请输入正确的用户id。");
+			}
+			//角色为 管理员并且projectId是空表示:全量查询
+			if ("admin".equals(roleCode) && Check.isNull(projectId)) {
+				projectId = "admin";	//传递projectId为admin
+			}
+			return bytedanceVideoSlogenInfoService.getVideoSlogenReport(userId, projectId,keyWord,status, startTime,endTime,pageNo,pageSize);
 		}catch (Exception e){
 			log.error("指定文案-获取指定文案维度创意报表数据异常",e);
 			return Result.error("请求失败,请联系开发人员!");
@@ -105,20 +125,69 @@ public class BytedanceVideoSlogenInfoController {
 	 *   添加
 	 * @param
 	 * @param
-	 * @param userId
+	 * @param
 	 * @return
 	 */
 	@ApiOperation(value="头条视频文案信息-批量添加", notes="头条视频文案信息-批量添加")
 	@PostMapping(value = "/addList")
-	public Result<BytedanceVideoSlogenInfo> addList(@RequestParam String[] videoCodeArray,
-													@RequestParam JSONArray slogenArray,
-													@RequestParam String userId) {
+	public Result<BytedanceVideoSlogenInfo> addList(@RequestBody MaterialInfo materialInfo) {
 		Result<BytedanceVideoSlogenInfo> result = new Result<>();
 		try {
-			for (String videoCode: videoCodeArray) {
-                bytedanceVideoSlogenInfoService.insertSlogans(videoCode,slogenArray,userId);
+			String userId = materialInfo.getUserId();
+			JSONArray slogenArray = materialInfo.getSlogans();
+			for (int i = 0;i<slogenArray.size();i++) {
+				JSONObject slogenInfo = slogenArray.getJSONObject(i);
+				String title = slogenInfo.getString("title");
+				title = title.trim().replaceAll("[\\{]{2,}","{");
+				title = title.trim().replaceAll("[\\}]{2,}","}");
+                slogenInfo.put("title",title);
+				String reg = "\\{[\\u4e00-\\u9fa5\\-]{2,6}\\}";
+				Pattern pattern = Pattern.compile(reg);
+				Matcher matcher = pattern.matcher(title);
+				JSONArray creativeWordIdsArray = new JSONArray();
+
+				int len = StringUtils.lengthAsSlogan(title);
+				int left = title.indexOf("{");
+				int right = title.indexOf("}");
+				if(left >= 0 || right >= 0){
+				int times = 0;
+					while (matcher.find()) { //此处find()每次被调用后,会偏移到下一个匹配
+						times++;
+						if(times>=3){
+							return  Result.errorMsg("动态词包不合法,词包数量超过2个");
+						}
+						String matchStr = matcher.group();//获取当前匹配的值
+						title = title.replace(matchStr,"");
+
+						ByteDanceCreativeWordPackage creativeWordPackage = byteDanceGeneralCopywriterService.selectCreativeWordPackageByName(matchStr.substring(1,matchStr.length()-1));
+						if(Check.isNull(creativeWordPackage)){
+							return  Result.errorMsg("动态词包不合法,词包不存在或者含有单独的非词包大括号");
+						}
+						creativeWordIdsArray.add(creativeWordPackage.getCreativeWordId());
+						len = len - (right - left) + creativeWordPackage.getMaxWordLen();
+						left = title.indexOf("{");
+						right = title.indexOf("}");
+					}
+					if(title.contains("{") || title.contains("}")){
+						return result.error500("大括号单独出现或大括号中内容不合法");
+					}
+					slogenInfo.put("creative_word_ids",creativeWordIdsArray.toJSONString());
+				}
+				//校验标题长度,长度小于5和大于30的全部过滤
+				if(len<5 || len>30){
+					return result.error500("文案长度不合法,小于5或大于30");
+				}
+			}
+
+			JSONArray materialIds = materialInfo.getMaterialIds();
+			for(int i=0;i<materialIds.size();i++){
+				MaterialInfo materialInfo2 = materialInfoService.getById(materialIds.get(i).toString());
+				String videoCode = materialInfo2.getCode();
+				Long projectId = materialInfo2.getProjectId();
+				bytedanceVideoSlogenInfoService.insertSlogans(projectId,videoCode,slogenArray,userId);
 			}
 			result.success("添加成功!");
+			result.setCode(0);
 			return result;
 		} catch (Exception e) {
 			log.error(e.getMessage(),e);
@@ -136,17 +205,74 @@ public class BytedanceVideoSlogenInfoController {
 	@PostMapping(value = "/edit")
 	public Result<BytedanceVideoSlogenInfo> edit(@RequestBody BytedanceVideoSlogenInfo slogenInfo) {
 		Result<BytedanceVideoSlogenInfo> result = new Result<>();
-		BytedanceVideoSlogenInfo bytedanceVideoSlogenInfoEntity = bytedanceVideoSlogenInfoService.getById(slogenInfo.getId());
-		if(bytedanceVideoSlogenInfoEntity==null) {
-			result.error500("未找到对应实体");
-			return result;
+		try{
+			List<BytedanceVideoSlogenInfo> videoSlogenInfoList = bytedanceVideoSlogenInfoService.getVideoSlogenBySlogenAndProjectId(slogenInfo.getSlogan(),slogenInfo.getProjectId());
+		if(videoSlogenInfoList==null) {
+			return result.error500("未找到对应实体");
 		}
-		LoginUser user = (LoginUser) SecurityUtils.getSubject().getPrincipal();
-		slogenInfo.setUpdateBy(user.getId());
-		slogenInfo.setUpdateTime(new Date());
-		bytedanceVideoSlogenInfoService.updateById(slogenInfo);
-		result.success("修改成功!");
+
+
+		String title = slogenInfo.getNewSlogan();
+		title = title.trim().replaceAll("[\\{]{2,}", "{");
+		title = title.trim().replaceAll("[\\}]{2,}", "}");
+		slogenInfo.setNewSlogan(title);
+
+		String reg = "\\{[\\u4e00-\\u9fa5\\-]{2,6}\\}";
+		Pattern pattern = Pattern.compile(reg);
+		Matcher matcher = pattern.matcher(title);
+		JSONArray creativeWordIdsArray = new JSONArray();
+
+		int len = StringUtils.lengthAsSlogan(title);
+		int left = title.indexOf("{");
+		int right = title.indexOf("}");
+		if (left >= 0 || right >= 0) {
+			int times = 0;
+			while (matcher.find()) { //此处find()每次被调用后,会偏移到下一个匹配
+				times++;
+				if (times >= 3) {
+					return result.error500("动态词包不合法,词包数量超过2个");
+				}
+				String matchStr = matcher.group();//获取当前匹配的值
+				title = title.replace(matchStr,"");
+
+				ByteDanceCreativeWordPackage creativeWordPackage = byteDanceGeneralCopywriterService.selectCreativeWordPackageByName(matchStr.substring(1, matchStr.length() - 1));
+				if (Check.isNull(creativeWordPackage)) {
+					return result.error500("动态词包不合法,词包不存在或者含有单独的非词包大括号");
+				}
+				creativeWordIdsArray.add(creativeWordPackage.getCreativeWordId());
+				len = len - (right - left) + creativeWordPackage.getMaxWordLen();
+				left = title.indexOf("{");
+				right = title.indexOf("}");
+			}
+			if(title.contains("{") || title.contains("}")){
+				return result.error500("文案含有词包特殊字符,请检查");
+			}
+		}
+		//校验标题长度,长度小于5和大于30的全部过滤
+		if (len < 5 || len > 30) {
+			return result.error500("文案长度不合法,小于5或大于30");
+		}
+
+			LoginUser user = (LoginUser) SecurityUtils.getSubject().getPrincipal();
+			for (BytedanceVideoSlogenInfo videoSlogenInfo:videoSlogenInfoList
+				 ) {
+				videoSlogenInfo.setSlogan(slogenInfo.getNewSlogan());
+				videoSlogenInfo.setUpdateBy(user.getId());
+				videoSlogenInfo.setUpdateTime(new Date());
+				videoSlogenInfo.setCreativeWordIds(creativeWordIdsArray.toJSONString());
+			}
+
+		boolean ok = bytedanceVideoSlogenInfoService.updateBatchById(videoSlogenInfoList);
+			if(ok) {
+				result.success("修改成功!");
+				result.setCode(0);
+			}
 		return result;
+		} catch (Exception e) {
+			log.error(e.getMessage(),e);
+			result.error500("操作失败");
+			return result;
+		}
 	}
 
 	/**
@@ -155,7 +281,7 @@ public class BytedanceVideoSlogenInfoController {
 	 * @return
 	 */
 	@ApiOperation(value="头条视频文案信息-通过id删除", notes="头条视频文案信息-通过id删除")
-	@PostMapping(value = "/delete")
+	@DeleteMapping(value = "/delete")
 	public Result<?> delete(@RequestParam(name="id") String id) {
 		try {
 			BytedanceVideoSlogenInfo slogenInfo = bytedanceVideoSlogenInfoService.getById(id);
@@ -173,6 +299,37 @@ public class BytedanceVideoSlogenInfoController {
 			return Result.error("删除失败!");
 		}
 	}
+	/**
+	 *   通过id删除
+	 * @param id
+	 * @return
+	 */
+	@ApiOperation(value="头条视频文案信息-通过id删除", notes="头条视频文案信息-通过id删除")
+	@DeleteMapping(value = "/deleteBySlogenAndProjectId")
+	public Result<?> deleteBySlogenAndProjectId(@RequestParam(name="slogan") String slogan, @RequestParam(name="projectId") Long projectId) {
+		try {
+			Result result = new Result();
+			List<BytedanceVideoSlogenInfo> videoSlogenInfoList = bytedanceVideoSlogenInfoService.getVideoSlogenBySlogenAndProjectId(slogan,projectId);
+			if(Check.isNull(videoSlogenInfoList)) {
+				return result.ok("此文案不存在或者已经被删除");
+			}
+			LoginUser user = (LoginUser) SecurityUtils.getSubject().getPrincipal();
+			videoSlogenInfoList.forEach(videoSlogenInfo->{
+				videoSlogenInfo.setStatus(0);
+				videoSlogenInfo.setUpdateTime(new Date());
+				videoSlogenInfo.setCreateBy(user.getId());});
+
+			boolean ok = bytedanceVideoSlogenInfoService.updateBatchById(videoSlogenInfoList);
+			if(ok) {
+				result.success("删除成功!");
+				result.setCode(0);
+			}
+			return result;
+		} catch (Exception e) {
+			log.error("删除失败",e.getMessage());
+			return Result.error("删除失败!");
+		}
+	}
 
 	/**
 	 * 通过id查询
@@ -192,4 +349,28 @@ public class BytedanceVideoSlogenInfoController {
 		result.setSuccess(true);
 		return result;
 	}
+
+	/**
+	 * 通过slogen和projectId查询
+	 * @param id
+	 * @return
+	 */
+	@ApiOperation(value="头条视频文案信息-通过文案内容和项目id查询", notes="头条视频文案信息-通过文案内容和项目id查询")
+	@GetMapping(value = "/queryBySlogenAndProjectId")
+	public Result<BytedanceVideoSlogenInfo> queryBySlogenAndProjectId(@RequestParam(name="slogan") String slogan, @RequestParam(name="projectId") Long projectId) {
+
+		Result<BytedanceVideoSlogenInfo> result = new Result<>();
+		List<BytedanceVideoSlogenInfo> videoSlogenInfoList = bytedanceVideoSlogenInfoService.getVideoSlogenBySlogenAndProjectId(slogan,projectId);
+		if(Check.isNull(videoSlogenInfoList)) {
+			result.error500("未找到对应实体");
+			return result;
+		}
+        List<String> materialNameArray = new ArrayList<>();
+        videoSlogenInfoList.forEach(videoSlogenInfo->materialNameArray.add(videoSlogenInfo.getMaterialName()));
+        BytedanceVideoSlogenInfo bytedanceVideoSlogenInfo = videoSlogenInfoList.get(0);
+        bytedanceVideoSlogenInfo.setMaterialNameArray(materialNameArray);
+		result.setResult(bytedanceVideoSlogenInfo);
+		result.setSuccess(true);
+		return result;
+	}
 }

+ 124 - 8
jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysUserController.java

@@ -10,20 +10,26 @@ import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.github.pagehelper.PageHelper;
+import com.github.pagehelper.PageInfo;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang.StringUtils;
 import org.apache.shiro.SecurityUtils;
-import org.apache.shiro.authz.annotation.RequiresPermissions;
-import org.apache.shiro.authz.annotation.RequiresRoles;
 import org.jeecg.common.api.vo.Result;
 import org.jeecg.common.aspect.annotation.PermissionData;
 import org.jeecg.common.constant.CommonConstant;
 import org.jeecg.common.system.api.ISysBaseAPI;
-import org.jeecg.modules.base.service.BaseCommonService;
 import org.jeecg.common.system.query.QueryGenerator;
 import org.jeecg.common.system.util.JwtUtil;
 import org.jeecg.common.system.vo.LoginUser;
-import org.jeecg.common.util.*;
+import org.jeecg.common.util.ImportExcelUtil;
+import org.jeecg.common.util.PasswordUtil;
+import org.jeecg.common.util.RedisUtil;
+import org.jeecg.common.util.oConvertUtils;
+import org.jeecg.modules.base.service.BaseCommonService;
+import org.jeecg.modules.bytedance.common.utils.Check;
 import org.jeecg.modules.system.entity.*;
 import org.jeecg.modules.system.model.DepartIdModel;
 import org.jeecg.modules.system.model.SysUserSysDepartModel;
@@ -57,6 +63,7 @@ import java.util.stream.Collectors;
  * @Author scott
  * @since 2018-12-20
  */
+@Api(tags="用户管理")
 @Slf4j
 @RestController
 @RequestMapping("/sys/user")
@@ -76,9 +83,6 @@ public class SysUserController {
 	@Autowired
 	private ISysUserDepartService sysUserDepartService;
 
-	@Autowired
-	private ISysUserRoleService userRoleService;
-
     @Autowired
     private ISysDepartRoleUserService departRoleUserService;
 
@@ -93,7 +97,8 @@ public class SysUserController {
 
     @Resource
     private BaseCommonService baseCommonService;
-
+    @Autowired
+    private ISysRoleService sysRoleService;
     /**
      * 获取用户列表数据
      * @param user
@@ -129,6 +134,117 @@ public class SysUserController {
 		return result;
 	}
 
+
+    /**
+     * 获取用户列表数据
+     *
+     * @param user
+     * @param pageNo
+     * @param pageSize
+     * @param
+     * @return
+     */
+    @ApiOperation(value="用户管理(运营)", notes="用户管理(运营)")
+    @RequestMapping(value = "/listV2", method = RequestMethod.GET)
+    public Result<Object> queryPageListV2(SysUser user, @RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
+                                          @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize) {
+        try {
+
+            String userId = user.getId();
+            String roleCode = sysRoleService.getRoleCodeByUserId(userId);
+            if (Check.isNull(roleCode)){
+                return Result.errorMsg("请输入正确的用户id。");
+            }
+            //角色为 管理员并且projectId是空表示:全量查询
+
+            if (!"admin".equals(roleCode)) {
+                List<SysUser> list = sysUserService.queryPageList(user);
+                //1.根据搜索框过滤数据
+                if(!Check.isNull(user.getUsername())){
+                    Iterator<SysUser> it = list.iterator();
+                    while(it.hasNext()){
+                        if(!it.next().getUsername().contains(user.getUsername())) {
+                            it.remove();
+                        }
+                    }
+                }
+                if(!Check.isNull(user.getRealname())){
+                    Iterator<SysUser> it = list.iterator();
+                    while(it.hasNext()){
+                        if(!it.next().getRealname().contains(user.getRealname())) {
+                            it.remove();
+                        }
+                    }
+                }
+                if(!Check.isNull(user.getLeaderName())){
+                    Iterator<SysUser> it = list.iterator();
+                    while(it.hasNext()){
+                        if(!it.next().getLeaderName().contains(user.getLeaderName())) {
+                            it.remove();
+                        }
+                    }
+                }
+                if(!Check.isNull(user.getRoleName())){
+                    Iterator<SysUser> it = list.iterator();
+                    while(it.hasNext()){
+                        if(!it.next().getRoleName().contains(user.getRoleName())) {
+                            it.remove();
+                        }
+                    }
+                }
+                if(!Check.isNull(user.getDepartId())){
+                    Iterator<SysUser> it = list.iterator();
+                    while(it.hasNext()){
+                        SysUser user2 = it.next();
+                        if(Check.isNull(user2.getDepartId2()) || !user2.getDepartId2().equals(user.getDepartId())) {
+                            it.remove();
+                        }
+                    }
+                }
+                if(!Check.isNull(user.getEmail())){
+                    Iterator<SysUser> it = list.iterator();
+                    while(it.hasNext()){
+                        if(!it.next().getEmail().contains(user.getEmail())) {
+                            it.remove();
+                        }
+                    }
+                }
+                if(!Check.isNull(user.getStatus())){
+                    Iterator<SysUser> it = list.iterator();
+                    while(it.hasNext()){
+                        if(!it.next().getStatus().equals(user.getStatus())) {
+                            it.remove();
+                        }
+                    }
+                }
+                //2.根据分页页数和条数来筛选数据
+                int total = list.size();
+                int beginIndex = (pageNo - 1) * pageSize + 1;
+                int endIndex = beginIndex + pageSize;
+                if(list.size() > beginIndex){
+                    list = list.subList(beginIndex-1,list.size() > endIndex ? endIndex : list.size());
+                }
+
+                PageInfo<SysUser> pageInfo = new PageInfo<>(list);
+                pageInfo.setTotal(total);
+                return Result.ok(pageInfo);
+            }else{
+                user.setId(null);
+                PageHelper.startPage(pageNo, pageSize);
+                List<SysUser> list = sysUserService.queryAdminPageList(user);
+                PageInfo<SysUser> pageInfo = new PageInfo<>(list);
+                return Result.ok(pageInfo);
+            }
+
+
+        } catch (Exception e) {
+            log.error("获取用户列表数据-分页列表查询异常", e);
+        }
+        return Result.error("查询失败");
+    }
+
+
+
     //@RequiresRoles({"admin"})
     //@RequiresPermissions("user:add")
 	@RequestMapping(value = "/add", method = RequestMethod.POST)

+ 30 - 0
jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/entity/SysUser.java

@@ -2,6 +2,7 @@ package org.jeecg.modules.system.entity;
 
 import java.util.Date;
 
+import com.baomidou.mybatisplus.annotation.TableField;
 import com.baomidou.mybatisplus.annotation.TableLogic;
 import com.fasterxml.jackson.annotation.JsonIgnore;
 import com.fasterxml.jackson.annotation.JsonProperty;
@@ -40,6 +41,10 @@ public class SysUser implements Serializable {
     @TableId(type = IdType.ASSIGN_ID)
     private String id;
 
+    private String departId;
+
+    private String departId2;
+
     /**
      * 登录账号
      */
@@ -182,4 +187,29 @@ public class SysUser implements Serializable {
 
     /**设备id uniapp推送用*/
     private String clientId;
+
+    /**
+     * 领导 ID
+     */
+    private String leaderId;
+
+    /**
+     * 领导姓名
+     */
+    private String leaderName;
+
+    /**
+     * 角色
+     */
+    @TableField(exist = false)
+    private String roleName;
+
+    /**
+     * 组织机构名称
+     */
+    @TableField(exist = false)
+    private String departName;
+
+
+
 }

+ 4 - 0
jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/mapper/SysUserMapper.java

@@ -139,4 +139,8 @@ public interface SysUserMapper extends BaseMapper<SysUser> {
 	 * @return
 	 */
 	List<SysUser> queryByDepIds(@Param("departIds")List<String> departIds,@Param("username") String username);
+
+	List<SysUser> queryPageList(SysUser user);
+
+	List<SysUser> selectAllUser();
 }

+ 56 - 0
jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/mapper/xml/SysUserMapper.xml

@@ -162,4 +162,60 @@
 			and username != #{username}
 		</if>
 	</select>
+
+	<!-- 查询用户列表-->
+	<select id="queryPageList" resultType="org.jeecg.modules.system.entity.SysUser">
+		SELECT t4.* from (
+		SELECT t1.*,t3.depart_name ,role.role_name,t2.create_time AS updTime,t3.id as departId2
+		FROM sys_user t1
+		LEFT JOIN sys_user_depart t2 ON t1.id = t2.user_id
+		LEFT JOIN sys_depart t3 ON t2.dep_id = t3.id
+		LEFT JOIN sys_user_role userRole ON t1.id = userRole.user_id
+		LEFT JOIN sys_role role ON userRole.role_id = role.id
+		where t1.del_flag = 0
+		<if test="realname != null and realname != ''">
+			AND t1.realname LIKE CONCAT(CONCAT('%',#{realname}),'%')
+		</if>
+		<if test="username != null and username != ''">
+			AND t1.username LIKE CONCAT(CONCAT('%',#{username}),'%')
+		</if>
+		<if test="email != null and email != ''">
+			AND t1.email LIKE CONCAT(CONCAT('%',#{email}),'%')
+		</if>
+		<if test="phone != null and phone != ''">
+			AND t1.phone LIKE CONCAT(CONCAT('%',#{phone}),'%')
+		</if>
+		<if test="status != null and status != ''">
+			AND t1.`status` = #{status}
+		</if>
+		<if test="leaderName != null and leaderName != ''">
+			AND t1.leader_name LIKE CONCAT(CONCAT('%',#{leaderName}),'%')
+		</if>
+		<if test="departId != null and departId != ''">
+			AND t3.id =#{departId}
+		</if>
+		<if test="roleName != null and roleName != ''">
+			AND role.role_name LIKE CONCAT(CONCAT('%',#{roleName}),'%')
+		</if>
+		<if test="sex != null and sex != ''">
+			AND t1.sex =#{sex}
+		</if>
+		<if test="id != null and id!=''">
+			and t1.id = #{id}
+		</if>
+
+		) t4
+		GROUP BY t4.id
+	</select>
+
+	<select id="selectAllUser" resultType="org.jeecg.modules.system.entity.SysUser">
+		SELECT t1.*,t3.depart_name ,role.role_name,t2.create_time AS updTime,t3.id as departId2
+		FROM sys_user t1
+		LEFT JOIN sys_user_depart t2 ON t1.id = t2.user_id
+		LEFT JOIN sys_depart t3 ON t2.dep_id = t3.id
+		LEFT JOIN sys_user_role userRole ON t1.id = userRole.user_id
+		LEFT JOIN sys_role role ON userRole.role_id = role.id
+		where t1.del_flag = 0
+	</select>
+
 </mapper>

+ 5 - 0
jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/ISysUserService.java

@@ -233,4 +233,9 @@ public interface ISysUserService extends IService<SysUser> {
 	 * @return
 	 */
 	List<SysUser> queryByDepIds(List<String> departIds, String username);
+
+	List<SysUser> queryPageList(SysUser user);
+
+	List<SysUser> queryAdminPageList(SysUser user);
+
 }

+ 43 - 0
jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/SysUserServiceImpl.java

@@ -5,6 +5,8 @@ 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.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.github.pagehelper.PageHelper;
+import com.github.pagehelper.PageInfo;
 import lombok.extern.slf4j.Slf4j;
 import org.jeecg.common.api.vo.Result;
 import org.jeecg.common.constant.CacheConstant;
@@ -16,6 +18,7 @@ import org.jeecg.common.system.vo.SysUserCacheInfo;
 import org.jeecg.common.util.PasswordUtil;
 import org.jeecg.common.util.UUIDGenerator;
 import org.jeecg.common.util.oConvertUtils;
+import org.jeecg.modules.bytedance.common.utils.Check;
 import org.jeecg.modules.system.entity.*;
 import org.jeecg.modules.system.mapper.*;
 import org.jeecg.modules.system.model.SysUserSysDepartModel;
@@ -439,4 +442,44 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
 		return userMapper.queryByDepIds(departIds,username);
 	}
 
+
+	@Override
+	public List<SysUser> queryPageList(SysUser user) {
+		SysUser sysUser = queryUserInfoById(user.getId());
+		if(Check.isNull(sysUser.getLeaderId())){
+			List<SysUser>  mulUserList = new ArrayList<>();
+			mulUserList.add(sysUser);
+			return mulUserList;
+		}
+		List<SysUser> allList = userMapper.selectAllUser();
+		List<SysUser>  mulUserList = treeCategoryData(allList, sysUser.getId());
+		mulUserList.add(sysUser);
+		return mulUserList;
+	}
+
+	@Override
+	public List<SysUser> queryAdminPageList(SysUser user) {
+		return userMapper.queryPageList(user);
+	}
+
+
+	public SysUser queryUserInfoById(String id){
+		SysUser nullValueUser = new SysUser();
+		nullValueUser.setId(id);
+		List<SysUser> mulUserList = userMapper.queryPageList(nullValueUser);
+		return Check.isNull(mulUserList) ? null : mulUserList.get(0);
+	}
+
+	public List<SysUser> treeCategoryData(List<SysUser> allList, String leaderId) {
+		List<SysUser> mapList = new ArrayList<>();
+		for (SysUser vo : allList) {
+			if (leaderId.equals(vo.getLeaderId())){
+				mapList.add(vo);
+				mapList.addAll(treeCategoryData(allList,vo.getId()));
+			}
+		}
+		return mapList;
+
+	}
+
 }

+ 37 - 1
jeecg-boot-module-system/src/main/resources/application-dev.yml

@@ -1,5 +1,5 @@
 server:
-  port: 8080
+  port: 8808
   tomcat:
     max-swallow-size: -1
   error:
@@ -287,3 +287,39 @@ justauth:
     type: default
     prefix: 'demo::'
     timeout: 1h
+
+bytedance:
+  appId: 1635316529903624
+  secret: 0c51523e90d6166418fc8421a4896808e90e26f4
+  url:
+    auth-prefix: https://ad.oceanengine.com/openapi
+    api-prefix: https://ad.oceanengine.com/open_api
+    callback-url: http://adsp.c-top.com.cn:8080/jeecg-boot/bytedance
+    refresh-token: /oauth2/refresh_token
+    advertiser-info: /2/advertiser/public_info/
+    ad-get: /2/ad/get/
+    ad-create: /2/ad/create/
+    ad-update: /2/ad/update/
+    ad-update-status: /2/ad/update/status/
+    ad-update-bid: /2/ad/update/bid/
+    ad-update-budget: /2/ad/update/budget/
+    ad-update-reject-reason: 2/ad/reject_reason/
+    campaign-get: /2/campaign/get/
+    campaign-create: /2/campaign/create/
+    campaign-update-status: /2/campaign/update/status/
+    campaign-update: /2/campaign/update/
+    dmp-custom-audience-select: /2/dmp/custom_audience/select/
+    file-video-ad: /2/file/video/ad/
+    file-image-ad: /2/file/image/ad/
+    creative-update-status: /2/creative/update/status/
+    creative-material-get: /2/creative/material/read/
+    creative-create-v2: /2/creative/create_v2/
+    creative-get: /2/creative/get/
+    creative-read: /2/creative/read_v2/
+    creative-update: /2/creative/update_v2/
+    creative-reject-reason: /2/creative/reject_reason/
+    advertiser-report-get: /2/report/advertiser/get/
+    campaign-report-get: /2/report/campaign/get/
+    ad-report-get: /2/report/ad/get/
+    ad-creative-get: /2/report/creative/get/
+    advertiser-fund-daily-stat: /2/advertiser/fund/daily_stat/

+ 329 - 0
jeecg-boot-module-system/src/main/resources/application-pre.yml

@@ -0,0 +1,329 @@
+server:
+  port: 8808
+  tomcat:
+    max-swallow-size: -1
+  error:
+    include-exception: true
+    include-stacktrace: ALWAYS
+    include-message: ALWAYS
+  servlet:
+    context-path: /bytedance-api
+  compression:
+    enabled: true
+    min-response-size: 1024
+    mime-types: application/javascript,application/json,application/xml,text/html,text/xml,text/plain,text/css,image/*
+
+management:
+ endpoints:
+  web:
+   exposure:
+    include: metrics,httptrace
+
+spring:
+  servlet:
+     multipart:
+        max-file-size: 10MB
+        max-request-size: 10MB
+  mail:
+    host: smtp.163.com
+    username: jeecgos@163.com
+    password: ??
+    properties:
+      mail:
+        smtp:
+          auth: true
+          starttls:
+            enable: true
+            required: true
+  ## quartz定时任务,采用数据库方式
+  quartz:
+    job-store-type: jdbc
+    initialize-schema: embedded
+    #设置自动启动,默认为 true
+    auto-startup: true
+    #启动时更新己存在的Job
+    overwrite-existing-jobs: true
+    properties:
+      org:
+        quartz:
+          scheduler:
+            instanceName: MyScheduler
+            instanceId: AUTO
+          jobStore:
+            class: org.quartz.impl.jdbcjobstore.JobStoreTX
+            driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegate
+            tablePrefix: QRTZ_
+            isClustered: true
+            misfireThreshold: 60000
+            clusterCheckinInterval: 10000
+          threadPool:
+            class: org.quartz.simpl.SimpleThreadPool
+            threadCount: 10
+            threadPriority: 5
+            threadsInheritContextClassLoaderOfInitializingThread: true
+  #json 时间戳统一转换
+  jackson:
+    date-format:   yyyy-MM-dd HH:mm:ss
+    time-zone:   GMT+8
+  jpa:
+    open-in-view: false
+  activiti:
+    check-process-definitions: false
+    #启用作业执行器
+    async-executor-activate: false
+    #启用异步执行器
+    job-executor-activate: false
+  aop:
+    proxy-target-class: true
+  #配置freemarker
+  freemarker:
+    # 设置模板后缀名
+    suffix: .ftl
+    # 设置文档类型
+    content-type: text/html
+    # 设置页面编码格式
+    charset: UTF-8
+    # 设置页面缓存
+    cache: false
+    prefer-file-system-access: false
+    # 设置ftl文件路径
+    template-loader-path:
+      - classpath:/templates
+  # 设置静态文件路径,js,css等
+  mvc:
+    static-path-pattern: /**
+  resource:
+    static-locations: classpath:/static/,classpath:/public/
+  autoconfigure:
+    exclude: com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure
+  datasource:
+    druid:
+      stat-view-servlet:
+        enabled: true
+        loginUsername: admin
+        loginPassword: 123456
+        allow:
+      web-stat-filter:
+        enabled: true
+    dynamic:
+      druid: # 全局druid参数,绝大部分值和默认保持一致。(现已支持的参数如下,不清楚含义不要乱设置)
+        # 连接池的配置信息
+        # 初始化大小,最小,最大
+        initial-size: 5
+        min-idle: 5
+        maxActive: 1000
+        # 配置获取连接等待超时的时间
+        maxWait: 60000
+        # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
+        timeBetweenEvictionRunsMillis: 60000
+        # 配置一个连接在池中最小生存的时间,单位是毫秒
+        minEvictableIdleTimeMillis: 300000
+        validationQuery: SELECT 1 FROM DUAL
+        testWhileIdle: true
+        testOnBorrow: false
+        testOnReturn: false
+        # 打开PSCache,并且指定每个连接上PSCache的大小
+        poolPreparedStatements: true
+        maxPoolPreparedStatementPerConnectionSize: 20
+        # 配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙
+        filters: stat,wall,slf4j
+        # 通过connectProperties属性来打开mergeSql功能;慢SQL记录
+        connectionProperties: druid.stat.mergeSql\=true;druid.stat.slowSqlMillis\=5000
+      datasource:
+        master:
+          url: jdbc:mysql://139.186.27.96:3390/jeecg-boot?characterEncoding=UTF-8&useUnicode=true&useSSL=false&tinyInt1isBit=false&allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai
+          username: data
+          password: hcst@2021
+          driver-class-name: com.mysql.cj.jdbc.Driver
+          # 多数据源配置
+          #multi-datasource1:
+          #url: jdbc:mysql://localhost:3306/jeecg-boot2?useUnicode=true&characterEncoding=utf8&autoReconnect=true&zeroDateTimeBehavior=convertToNull&transformedBitIsBoolean=true&allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai
+          #username: root
+          #password: root
+          #driver-class-name: com.mysql.cj.jdbc.Driver
+  #redis 配置
+  redis:
+    database: 0
+    host: 172.30.0.17
+    lettuce:
+      pool:
+        max-active: 8   #最大连接数据库连接数,设 0 为没有限制
+        max-idle: 8     #最大等待连接中的数量,设 0 为没有限制
+        max-wait: -1ms  #最大建立连接等待时间。如果超过此时间将接到异常。设为-1表示无限制。
+        min-idle: 0     #最小等待连接中的数量,设 0 为没有限制
+      shutdown-timeout: 100ms
+    password: hcst@2021..
+    port: 6379
+#mybatis plus 设置
+mybatis-plus:
+  mapper-locations: classpath*:org/jeecg/modules/**/xml/*Mapper.xml
+  global-config:
+    # 关闭MP3.0自带的banner
+    banner: false
+    db-config:
+      #主键类型  0:"数据库ID自增",1:"该类型为未设置主键类型", 2:"用户输入ID",3:"全局唯一ID (数字类型唯一ID)", 4:"全局唯一ID UUID",5:"字符串全局唯一ID (idWorker 的字符串表示)";
+      id-type: ASSIGN_ID
+      # 默认数据库表下划线命名
+      table-underline: true
+  configuration:
+    # 这个配置会将执行的sql打印出来,在开发或测试的时候可以用
+    #log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
+    # 返回类型为Map,显示null对应的字段
+    call-setters-on-nulls: true
+#minidao 设置
+minidao :
+  base-package: org.jeecg.modules.jmreport.*
+  db-type: mysql
+#jeecg专用配置
+jeecg :
+  # 本地:local\Minio:minio\阿里云:alioss
+  uploadType: alioss
+  path :
+    #文件上传根目录 设置
+    upload: /opt/jeecg-boot/upload
+    #webapp文件路径
+    webapp: /opt/jeecg-boot/webapp
+  shiro:
+     excludeUrls: /test/jeecgDemo/demo3,/test/jeecgDemo/redisDemo/**,/category/**,/visual/**,/map/**,/jmreport/bigscreen2/**
+  #阿里云oss存储配置
+  oss:
+    endpoint: oss-cn-beijing.aliyuncs.com
+    accessKey: ??
+    secretKey: ??
+    bucketName: jeecgos
+    staticDomain: https://static.jeecg.com
+  # ElasticSearch 设置
+  elasticsearch:
+    cluster-name: jeecg-ES
+    cluster-nodes: 111.225.222.176:9200
+    check-enabled: true
+  # 表单设计器配置
+  desform:
+    # 主题颜色(仅支持 16进制颜色代码)
+    theme-color: "#1890ff"
+    # 文件、图片上传方式,可选项:qiniu(七牛云)、system(跟随系统配置)
+    upload-type: system
+  # 在线预览文件服务器地址配置
+  file-view-domain: http://fileview.jeecg.com
+  # minio文件上传
+  minio:
+    minio_url: http://minio.jeecg.com
+    minio_name: ??
+    minio_pass: ??
+    bucketName: otatest
+  #大屏报表参数设置
+  jmreport:
+    mode: prod
+    #数据字典是否进行saas数据隔离,自己看自己的字典
+    saas: false
+    #是否需要校验token
+    is_verify_token: true
+    #必须校验方法
+    verify_methods: remove,delete,save,add,update
+  #Wps在线文档
+  wps:
+    domain: https://wwo.wps.cn/office/
+    appid: ??
+    appsecret: ??
+  #xxl-job配置
+  xxljob:
+    enabled: false
+    adminAddresses: http://127.0.0.1:9080/xxl-job-admin
+    appname: ${spring.application.name}
+    accessToken: ''
+    address: 127.0.0.1:30007
+    ip: 127.0.0.1
+    port: 30007
+    logPath: logs/jeecg/job/jobhandler/
+    logRetentionDays: 30
+   #自定义路由配置 yml nacos database
+  route:
+    config:
+      data-id: jeecg-gateway-router
+      group: DEFAULT_GROUP
+      data-type: yml
+  #分布式锁配置
+  redisson:
+    address: 127.0.0.1:6379
+    password:
+    type: STANDALONE
+    enabled: true
+#cas单点登录
+cas:
+  prefixUrl: http://cas.example.org:8443/cas
+#Mybatis输出sql日志
+logging:
+  level:
+    org.jeecg.modules.system.mapper : info
+#swagger
+knife4j:
+  production: false
+  basic:
+    enable: false
+    username: jeecg
+    password: jeecg1314
+#第三方登录
+justauth:
+  enabled: true
+  type:
+    GITHUB:
+      client-id: ??
+      client-secret: ??
+      redirect-uri: http://sso.test.com:8080/jeecg-boot/sys/thirdLogin/github/callback
+    WECHAT_ENTERPRISE:
+      client-id: ??
+      client-secret: ??
+      redirect-uri: http://sso.test.com:8080/jeecg-boot/sys/thirdLogin/wechat_enterprise/callback
+      agent-id: 1000002
+    DINGTALK:
+      client-id: ??
+      client-secret: ??
+      redirect-uri: http://sso.test.com:8080/jeecg-boot/sys/thirdLogin/dingtalk/callback
+    WECHAT_OPEN:
+      client-id: ??
+      client-secret: ??
+      redirect-uri: http://sso.test.com:8080/jeecg-boot/sys/thirdLogin/wechat_open/callback
+  cache:
+    type: default
+    prefix: 'demo::'
+    timeout: 1h
+
+
+
+
+
+bytedance:
+  appId: 1635316529903624
+  secret: 0c51523e90d6166418fc8421a4896808e90e26f4
+  url:
+    auth-prefix: https://ad.oceanengine.com/openapi
+    api-prefix: https://ad.oceanengine.com/open_api
+    callback-url: http://adsp.c-top.com.cn:8080/jeecg-boot/bytedance
+    refresh-token: /oauth2/refresh_token
+    advertiser-info: /2/advertiser/public_info/
+    ad-get: /2/ad/get/
+    ad-create: /2/ad/create/
+    ad-update: /2/ad/update/
+    ad-update-status: /2/ad/update/status/
+    ad-update-bid: /2/ad/update/bid/
+    ad-update-budget: /2/ad/update/budget/
+    ad-update-reject-reason: 2/ad/reject_reason/
+    campaign-get: /2/campaign/get/
+    campaign-create: /2/campaign/create/
+    campaign-update-status: /2/campaign/update/status/
+    campaign-update: /2/campaign/update/
+    dmp-custom-audience-select: /2/dmp/custom_audience/select/
+    file-video-ad: /2/file/video/ad/
+    file-image-ad: /2/file/image/ad/
+    creative-update-status: /2/creative/update/status/
+    creative-material-get: /2/creative/material/read/
+    creative-create-v2: /2/creative/create_v2/
+    creative-get: /2/creative/get/
+    creative-read: /2/creative/read_v2/
+    creative-update: /2/creative/update_v2/
+    creative-reject-reason: /2/creative/reject_reason/
+    advertiser-report-get: /2/report/advertiser/get/
+    campaign-report-get: /2/report/campaign/get/
+    ad-report-get: /2/report/ad/get/
+    ad-creative-get: /2/report/creative/get/
+    advertiser-fund-daily-stat: /2/advertiser/fund/daily_stat/

+ 43 - 10
jeecg-boot-module-system/src/main/resources/application-prod.yml

@@ -1,5 +1,5 @@
 server:
-  port: 8080
+  port: 8808
   tomcat:
     max-swallow-size: -1
   error:
@@ -131,16 +131,10 @@ spring:
         connectionProperties: druid.stat.mergeSql\=true;druid.stat.slowSqlMillis\=5000
       datasource:
         master:
-          url: jdbc:mysql://139.186.27.96:4000/jeecg-boot?characterEncoding=UTF-8&useUnicode=true&useSSL=false&tinyInt1isBit=false&allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai
+          url: jdbc:mysql://172.30.0.6:4000/jeecg-boot?characterEncoding=UTF-8&useUnicode=true&useSSL=false&tinyInt1isBit=false&allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai
           username: data
           password: hcst@2021
           driver-class-name: com.mysql.cj.jdbc.Driver
-          # 多数据源配置
-          #multi-datasource1:
-          #url: jdbc:mysql://localhost:3306/jeecg-boot2?useUnicode=true&characterEncoding=utf8&autoReconnect=true&zeroDateTimeBehavior=convertToNull&transformedBitIsBoolean=true&allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai
-          #username: root
-          #password: root
-          #driver-class-name: com.mysql.cj.jdbc.Driver
   #redis 配置
   redis:
     database: 0
@@ -152,7 +146,7 @@ spring:
         max-wait: -1ms  #最大建立连接等待时间。如果超过此时间将接到异常。设为-1表示无限制。
         min-idle: 0     #最小等待连接中的数量,设 0 为没有限制
       shutdown-timeout: 100ms
-    password: foobared
+    password: hcst@2021..
     port: 6379
 #mybatis plus 设置
 mybatis-plus:
@@ -286,4 +280,43 @@ justauth:
   cache:
     type: default
     prefix: 'demo::'
-    timeout: 1h
+    timeout: 1h
+
+
+
+
+bytedance:
+  appId: 1635316529903624
+  secret: 0c51523e90d6166418fc8421a4896808e90e26f4
+  url:
+    auth-prefix: https://ad.oceanengine.com/openapi
+    api-prefix: https://ad.oceanengine.com/open_api
+    callback-url: http://adsp.c-top.com.cn:8080/jeecg-boot/bytedance
+    refresh-token: /oauth2/refresh_token
+    advertiser-info: /2/advertiser/public_info/
+    ad-get: /2/ad/get/
+    ad-create: /2/ad/create/
+    ad-update: /2/ad/update/
+    ad-update-status: /2/ad/update/status/
+    ad-update-bid: /2/ad/update/bid/
+    ad-update-budget: /2/ad/update/budget/
+    ad-update-reject-reason: 2/ad/reject_reason/
+    campaign-get: /2/campaign/get/
+    campaign-create: /2/campaign/create/
+    campaign-update-status: /2/campaign/update/status/
+    campaign-update: /2/campaign/update/
+    dmp-custom-audience-select: /2/dmp/custom_audience/select/
+    file-video-ad: /2/file/video/ad/
+    file-image-ad: /2/file/image/ad/
+    creative-update-status: /2/creative/update/status/
+    creative-material-get: /2/creative/material/read/
+    creative-create-v2: /2/creative/create_v2/
+    creative-get: /2/creative/get/
+    creative-read: /2/creative/read_v2/
+    creative-update: /2/creative/update_v2/
+    creative-reject-reason: /2/creative/reject_reason/
+    advertiser-report-get: /2/report/advertiser/get/
+    campaign-report-get: /2/report/campaign/get/
+    ad-report-get: /2/report/ad/get/
+    ad-creative-get: /2/report/creative/get/
+    advertiser-fund-daily-stat: /2/advertiser/fund/daily_stat/

+ 38 - 2
jeecg-boot-module-system/src/main/resources/application-test.yml

@@ -1,5 +1,5 @@
 server:
-  port: 8080
+  port: 8808
   tomcat:
     max-swallow-size: -1
   error:
@@ -152,7 +152,7 @@ spring:
          max-wait: -1ms  #最大建立连接等待时间。如果超过此时间将接到异常。设为-1表示无限制。
          min-idle: 0     #最小等待连接中的数量,设 0 为没有限制
        shutdown-timeout: 100ms
-     password: ''
+     password: hcst@2020
      port: 6379
 #mybatis plus 设置
 mybatis-plus:
@@ -287,3 +287,39 @@ justauth:
     type: default
     prefix: 'demo::'
     timeout: 1h
+
+bytedance:
+  appId: 1635316529903624
+  secret: 0c51523e90d6166418fc8421a4896808e90e26f4
+  url:
+    auth-prefix: https://ad.oceanengine.com/openapi
+    api-prefix: https://ad.oceanengine.com/open_api
+    callback-url: http://adsp.c-top.com.cn:8080/jeecg-boot/bytedance
+    refresh-token: /oauth2/refresh_token
+    advertiser-info: /2/advertiser/public_info/
+    ad-get: /2/ad/get/
+    ad-create: /2/ad/create/
+    ad-update: /2/ad/update/
+    ad-update-status: /2/ad/update/status/
+    ad-update-bid: /2/ad/update/bid/
+    ad-update-budget: /2/ad/update/budget/
+    ad-update-reject-reason: 2/ad/reject_reason/
+    campaign-get: /2/campaign/get/
+    campaign-create: /2/campaign/create/
+    campaign-update-status: /2/campaign/update/status/
+    campaign-update: /2/campaign/update/
+    dmp-custom-audience-select: /2/dmp/custom_audience/select/
+    file-video-ad: /2/file/video/ad/
+    file-image-ad: /2/file/image/ad/
+    creative-update-status: /2/creative/update/status/
+    creative-material-get: /2/creative/material/read/
+    creative-create-v2: /2/creative/create_v2/
+    creative-get: /2/creative/get/
+    creative-read: /2/creative/read_v2/
+    creative-update: /2/creative/update_v2/
+    creative-reject-reason: /2/creative/reject_reason/
+    advertiser-report-get: /2/report/advertiser/get/
+    campaign-report-get: /2/report/campaign/get/
+    ad-report-get: /2/report/ad/get/
+    ad-creative-get: /2/report/creative/get/
+    advertiser-fund-daily-stat: /2/advertiser/fund/daily_stat/