Browse Source

Merge remote-tracking branch 'origin/master'

xuzuoyun 5 years ago
parent
commit
9e616fd81a
49 changed files with 4163 additions and 124 deletions
  1. 3 3
      jeecg-boot-module-system/src/main/java/org/jeecg/config/ShiroConfig.java
  2. 75 53
      jeecg-boot-module-system/src/main/java/org/jeecg/modules/ctop/controller/AuthController.java
  3. 277 0
      jeecg-boot-module-system/src/main/java/org/jeecg/modules/ctop/controller/BindAccountController.java
  4. 150 11
      jeecg-boot-module-system/src/main/java/org/jeecg/modules/ctop/controller/ByteDanceAdvertiserPostController.java
  5. 253 0
      jeecg-boot-module-system/src/main/java/org/jeecg/modules/ctop/controller/ByteDanceImageInfoController.java
  6. 253 0
      jeecg-boot-module-system/src/main/java/org/jeecg/modules/ctop/controller/ByteDanceVideoInfoController.java
  7. 11 5
      jeecg-boot-module-system/src/main/java/org/jeecg/modules/ctop/controller/CallbackController.java
  8. 88 0
      jeecg-boot-module-system/src/main/java/org/jeecg/modules/ctop/entity/BindAccount.java
  9. 260 1
      jeecg-boot-module-system/src/main/java/org/jeecg/modules/ctop/entity/ByteDanceAdvertisePlan.java
  10. 20 4
      jeecg-boot-module-system/src/main/java/org/jeecg/modules/ctop/entity/ByteDanceCampaign.java
  11. 125 0
      jeecg-boot-module-system/src/main/java/org/jeecg/modules/ctop/entity/ByteDanceImageInfo.java
  12. 119 0
      jeecg-boot-module-system/src/main/java/org/jeecg/modules/ctop/entity/ByteDanceVideoInfo.java
  13. 6 22
      jeecg-boot-module-system/src/main/java/org/jeecg/modules/ctop/entity/BytedanceAdvertisePlanTemplate.java
  14. 17 3
      jeecg-boot-module-system/src/main/java/org/jeecg/modules/ctop/entity/CTopOauthToken.java
  15. 14 0
      jeecg-boot-module-system/src/main/java/org/jeecg/modules/ctop/entity/FileInfo.java
  16. 14 0
      jeecg-boot-module-system/src/main/java/org/jeecg/modules/ctop/mapper/BindAccountMapper.java
  17. 17 0
      jeecg-boot-module-system/src/main/java/org/jeecg/modules/ctop/mapper/ByteDanceImageInfoMapper.java
  18. 17 0
      jeecg-boot-module-system/src/main/java/org/jeecg/modules/ctop/mapper/ByteDanceVideoInfoMapper.java
  19. 5 0
      jeecg-boot-module-system/src/main/java/org/jeecg/modules/ctop/mapper/xml/BindAccountMapper.xml
  20. 5 0
      jeecg-boot-module-system/src/main/java/org/jeecg/modules/ctop/mapper/xml/ByteDanceImageInfoMapper.xml
  21. 5 0
      jeecg-boot-module-system/src/main/java/org/jeecg/modules/ctop/mapper/xml/ByteDanceVideoInfoMapper.xml
  22. 25 0
      jeecg-boot-module-system/src/main/java/org/jeecg/modules/ctop/service/IBindAccountService.java
  23. 3 0
      jeecg-boot-module-system/src/main/java/org/jeecg/modules/ctop/service/IByteDanceAdvertisePlanService.java
  24. 5 0
      jeecg-boot-module-system/src/main/java/org/jeecg/modules/ctop/service/IByteDanceAdvertiserDataService.java
  25. 3 0
      jeecg-boot-module-system/src/main/java/org/jeecg/modules/ctop/service/IByteDanceCreativeService.java
  26. 14 0
      jeecg-boot-module-system/src/main/java/org/jeecg/modules/ctop/service/IByteDanceImageInfoService.java
  27. 14 0
      jeecg-boot-module-system/src/main/java/org/jeecg/modules/ctop/service/IByteDanceVideoInfoService.java
  28. 7 0
      jeecg-boot-module-system/src/main/java/org/jeecg/modules/ctop/service/IFileInfoService.java
  29. 140 0
      jeecg-boot-module-system/src/main/java/org/jeecg/modules/ctop/service/impl/BindAccountServiceImpl.java
  30. 97 0
      jeecg-boot-module-system/src/main/java/org/jeecg/modules/ctop/service/impl/ByteDanceAdvertisePlanServiceImpl.java
  31. 98 16
      jeecg-boot-module-system/src/main/java/org/jeecg/modules/ctop/service/impl/ByteDanceAdvertiserDataServiceImpl.java
  32. 4 3
      jeecg-boot-module-system/src/main/java/org/jeecg/modules/ctop/service/impl/ByteDanceCampaignTemplateServiceImpl.java
  33. 89 0
      jeecg-boot-module-system/src/main/java/org/jeecg/modules/ctop/service/impl/ByteDanceCreativeServiceImpl.java
  34. 19 0
      jeecg-boot-module-system/src/main/java/org/jeecg/modules/ctop/service/impl/ByteDanceImageInfoServiceImpl.java
  35. 19 0
      jeecg-boot-module-system/src/main/java/org/jeecg/modules/ctop/service/impl/ByteDanceVideoInfoServiceImpl.java
  36. 260 1
      jeecg-boot-module-system/src/main/java/org/jeecg/modules/ctop/service/impl/FileInfoServiceImpl.java
  37. 193 0
      jeecg-boot-module-system/src/main/java/org/jeecg/modules/ctop/vue/BindAccountList.vue
  38. 213 0
      jeecg-boot-module-system/src/main/java/org/jeecg/modules/ctop/vue/ByteDanceImageInfoList.vue
  39. 203 0
      jeecg-boot-module-system/src/main/java/org/jeecg/modules/ctop/vue/ByteDanceVideoInfoList.vue
  40. 154 0
      jeecg-boot-module-system/src/main/java/org/jeecg/modules/ctop/vue/modules/BindAccountModal.vue
  41. 161 0
      jeecg-boot-module-system/src/main/java/org/jeecg/modules/ctop/vue/modules/BindAccountModal__Style#Drawer.vue
  42. 170 0
      jeecg-boot-module-system/src/main/java/org/jeecg/modules/ctop/vue/modules/ByteDanceImageInfoModal.vue
  43. 177 0
      jeecg-boot-module-system/src/main/java/org/jeecg/modules/ctop/vue/modules/ByteDanceImageInfoModal__Style#Drawer.vue
  44. 158 0
      jeecg-boot-module-system/src/main/java/org/jeecg/modules/ctop/vue/modules/ByteDanceVideoInfoModal.vue
  45. 165 0
      jeecg-boot-module-system/src/main/java/org/jeecg/modules/ctop/vue/modules/ByteDanceVideoInfoModal__Style#Drawer.vue
  46. 1 1
      jeecg-boot-module-system/src/main/java/org/jeecg/modules/kuaishou/service/impl/KuaishouInterfaceServiceImpl.java
  47. 26 0
      module-common/src/main/java/cn/com/ctop/common/utils/MD5Utils.java
  48. 6 0
      module-kuaishou/src/main/java/constant/KuaishouInterfaceConstant.java
  49. 5 1
      module-toutiao/src/main/resources/bytedance_config.properties

+ 3 - 3
jeecg-boot-module-system/src/main/java/org/jeecg/config/ShiroConfig.java

@@ -73,6 +73,7 @@ public class ShiroConfig {
 		filterChainDefinitionMap.put("/webjars/**", "anon");
 		filterChainDefinitionMap.put("/webjars/**", "anon");
 		filterChainDefinitionMap.put("/v2/**", "anon");
 		filterChainDefinitionMap.put("/v2/**", "anon");
 		filterChainDefinitionMap.put("/kuaishou/**", "anon");
 		filterChainDefinitionMap.put("/kuaishou/**", "anon");
+		filterChainDefinitionMap.put("/ctop/bindAccount/**", "anon");
 		filterChainDefinitionMap.put("/**/*.mp4", "anon");
 		filterChainDefinitionMap.put("/**/*.mp4", "anon");
 
 
 
 
@@ -84,14 +85,13 @@ public class ShiroConfig {
 		filterChainDefinitionMap.put("/test/jeecgDemo/redisDemo/**", "anon"); //redis测试
 		filterChainDefinitionMap.put("/test/jeecgDemo/redisDemo/**", "anon"); //redis测试
 
 
 		//oauth接口
 		//oauth接口
-		filterChainDefinitionMap.put("/auth/kuaishou", "anon");
-		filterChainDefinitionMap.put("/auth/bytedance", "anon");
-		filterChainDefinitionMap.put("/auth/begin", "anon");
+        filterChainDefinitionMap.put("/auth/**", "anon");
 		filterChainDefinitionMap.put("/ctop/syncdata/**", "anon");
 		filterChainDefinitionMap.put("/ctop/syncdata/**", "anon");
 		//头条接口
 		//头条接口
 		filterChainDefinitionMap.put("/kuaishou", "anon");
 		filterChainDefinitionMap.put("/kuaishou", "anon");
 		filterChainDefinitionMap.put("/toutiao/dictitem/list", "anon");
 		filterChainDefinitionMap.put("/toutiao/dictitem/list", "anon");
 		filterChainDefinitionMap.put("/toutiao/advertiser/**", "anon");
 		filterChainDefinitionMap.put("/toutiao/advertiser/**", "anon");
+        filterChainDefinitionMap.put("/toutiao/industry/list", "anon");
         filterChainDefinitionMap.put("/template/**", "user");
         filterChainDefinitionMap.put("/template/**", "user");
 		//文件上传接口
 		//文件上传接口
 		filterChainDefinitionMap.put("/upload/**", "anon");
 		filterChainDefinitionMap.put("/upload/**", "anon");

+ 75 - 53
jeecg-boot-module-system/src/main/java/org/jeecg/modules/ctop/controller/AuthController.java

@@ -1,5 +1,6 @@
 package org.jeecg.modules.ctop.controller;
 package org.jeecg.modules.ctop.controller;
 
 
+import cn.com.ctop.common.utils.Check;
 import cn.com.ctop.common.utils.HttpUtils;
 import cn.com.ctop.common.utils.HttpUtils;
 import cn.com.ctop.common.utils.PropertiesUtils;
 import cn.com.ctop.common.utils.PropertiesUtils;
 import cn.com.ctop.toutiao.common.BytedanceInterfaceConstant;
 import cn.com.ctop.toutiao.common.BytedanceInterfaceConstant;
@@ -9,6 +10,8 @@ import constant.KuaishouInterfaceConstant;
 import org.apache.commons.lang.StringUtils;
 import org.apache.commons.lang.StringUtils;
 import org.jeecg.modules.ctop.entity.CTopOauthToken;
 import org.jeecg.modules.ctop.entity.CTopOauthToken;
 import org.jeecg.modules.ctop.mapper.CTopOauthTokenMapper;
 import org.jeecg.modules.ctop.mapper.CTopOauthTokenMapper;
+import org.jeecg.modules.ctop.service.ICTopOauthTokenService;
+import org.jeecg.modules.ctop.service.IBindAccountService;
 import org.jeecg.modules.kuaishou.service.IKuaishouInterfaceService;
 import org.jeecg.modules.kuaishou.service.IKuaishouInterfaceService;
 import org.slf4j.Logger;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.slf4j.LoggerFactory;
@@ -21,8 +24,6 @@ import org.springframework.web.bind.annotation.ResponseBody;
 
 
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import javax.servlet.http.HttpServletResponse;
-import java.io.UnsupportedEncodingException;
-import java.net.URLEncoder;
 import java.util.HashMap;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Map;
 import java.util.UUID;
 import java.util.UUID;
@@ -33,99 +34,120 @@ public class AuthController {
     private static final Logger logger = LoggerFactory.getLogger(AuthController.class);
     private static final Logger logger = LoggerFactory.getLogger(AuthController.class);
     @Autowired
     @Autowired
     private IKuaishouInterfaceService kuaishouInterfaceService;
     private IKuaishouInterfaceService kuaishouInterfaceService;
+    @Autowired
+    private IBindAccountService bindAccountService;
+
+    @Autowired
+    private CTopOauthTokenMapper cTopOauthTokenMapper;
+
     @RequestMapping("/begin")
     @RequestMapping("/begin")
     public String authBegin(HttpServletRequest request,
     public String authBegin(HttpServletRequest request,
                             HttpServletResponse response,
                             HttpServletResponse response,
-                            @RequestParam("auth_type")String authType){
-        try{
+                            @RequestParam("auth_type") String authType) {
+        try {
             String codeUrl = "";
             String codeUrl = "";
-            switch (authType)
-            {
+            switch (authType) {
                 case "bytedance":
                 case "bytedance":
-                    codeUrl = this.getByteDanceCodeUrl(UUID.randomUUID().toString());
+                    codeUrl = bindAccountService.getByteDanceCodeUrl(UUID.randomUUID().toString());
                     System.out.println(codeUrl);
                     System.out.println(codeUrl);
-                    return "redirect:"+codeUrl;
+                    return "redirect:" + codeUrl;
                 case "kuaishou":
                 case "kuaishou":
-                    codeUrl = this.getKuaishouCodeUrl(UUID.randomUUID().toString());
+                    codeUrl = bindAccountService.getKuaishouCodeUrl(UUID.randomUUID().toString());
                     System.out.println(codeUrl);
                     System.out.println(codeUrl);
-                    return "redirect:"+codeUrl;
+                    return "redirect:" + codeUrl;
                 default:
                 default:
                     System.out.println("");
                     System.out.println("");
 
 
             }
             }
-        }catch (Exception e){
+        } catch (Exception e) {
             e.printStackTrace();
             e.printStackTrace();
         }
         }
 
 
         return "auth_error";
         return "auth_error";
     }
     }
+
     @RequestMapping("/bytedance")
     @RequestMapping("/bytedance")
     @ResponseBody
     @ResponseBody
     public String bytedance(HttpServletRequest request,
     public String bytedance(HttpServletRequest request,
                             HttpServletResponse response,
                             HttpServletResponse response,
-                            @RequestParam("auth_code")String authCode,
-                            @RequestParam("state")String state,@RequestParam("accountId")String accountId) {
+                            @RequestParam("auth_code") String authCode,
+                            @RequestParam("state") String state, @RequestParam("accountId") String accountId) {
         System.out.println(request.getQueryString());
         System.out.println(request.getQueryString());
-        if(StringUtils.isNotBlank(authCode)){
-            System.out.println(this.getByteDanceAccessToken(authCode,accountId));
+        if (StringUtils.isNotBlank(authCode)) {
+            System.out.println(this.getByteDanceAccessToken(authCode, accountId, state));
             return "auth_success";
             return "auth_success";
         }
         }
         return "auth_fail";
         return "auth_fail";
     }
     }
 
 
     @GetMapping("bytedance/refreshtoken")
     @GetMapping("bytedance/refreshtoken")
+    @ResponseBody
+    public Map<String, Object> refreshToken(String accountId) {
+        Map<String, Object> resultMap = new HashMap<>();
+        CTopOauthToken token = tokenService.getOAuthTokenByAccountId(accountId);
+        if (null == token) {
+            resultMap.put("message", "token信息不存在");
+            resultMap.put("code", -1);
+            return resultMap;
+        }
+        String url = PropertiesUtils.getValue("bytedance_config", "bytedance_api_url") + BytedanceInterfaceConstant.REFRESH_TOKEN;
+        Map<String, Object> param = new HashMap<String, Object>();
+        param.put("app_id", PropertiesUtils.getValue("bytedance_config", "bytedance_appid"));
+        param.put("secret", PropertiesUtils.getValue("bytedance_config", "bytedance_secret"));
+        param.put("grant_type", "refresh_token");
+        param.put("refresh_token", token.getRefreshToken());
 
 
+        String result = HttpUtils.httpPostRequest(url, param, new HashMap<>());
+        JSONObject resultObject = JSONObject.parseObject(result);
+        Integer code = resultObject.getInteger("status");
+        if (null == code || code != 0) {
+            logger.info("刷新token异常;accountId:{}", accountId);
+            resultMap.put("message", "刷新token异常");
+            resultMap.put("code", -1);
+            return resultMap;
+        }
+        JSONObject data = resultObject.getJSONObject("data");
+        CTopOauthToken refreshToken = new CTopOauthToken(token, data);
+        cTopOauthTokenMapper.deleteById(token.getId());
+        cTopOauthTokenMapper.insert(refreshToken);
+        resultMap.put("message", "token刷新成功");
+        resultMap.put("code", 0);
+        return resultMap;
+    }
 
 
-    public String getByteDanceAccessToken(String authCode, String accountId) {
+    @Autowired
+    private ICTopOauthTokenService tokenService;
+
+    public String getByteDanceAccessToken(String authCode, String accountId, String state) {
         Map<String, Object> param = new HashMap<String, Object>();
         Map<String, Object> param = new HashMap<String, Object>();
-        param.put("app_id",PropertiesUtils.getValue("bytedance_config","bytedance_appid"));
-        param.put("secret",PropertiesUtils.getValue("bytedance_config","bytedance_secret"));
-        param.put("grant_type","auth_code");
-        param.put("auth_code",authCode);
+        param.put("app_id", PropertiesUtils.getValue("bytedance_config", "bytedance_appid"));
+        param.put("secret", PropertiesUtils.getValue("bytedance_config", "bytedance_secret"));
+        param.put("grant_type", "auth_code");
+        param.put("auth_code", authCode);
 
 
         Gson gson = new Gson();
         Gson gson = new Gson();
         String result = "";
         String result = "";
-        try{
-            System.out.println(PropertiesUtils.getValue("bytedance_config","bytedance_api_url")+ BytedanceInterfaceConstant.AUTH_TOKEN);
-            result = HttpUtils.httpPostRequest(PropertiesUtils.getValue("bytedance_config","bytedance_api_url")+BytedanceInterfaceConstant.AUTH_TOKEN,param,new HashMap<>());
-            System.out.println(result);
+        try {
+            result = HttpUtils.httpPostRequest(PropertiesUtils.getValue("bytedance_config", "bytedance_api_url") + BytedanceInterfaceConstant.AUTH_TOKEN, param, new HashMap<>());
             JSONObject resultObject = JSONObject.parseObject(result);
             JSONObject resultObject = JSONObject.parseObject(result);
             Integer code = resultObject.getInteger("code");
             Integer code = resultObject.getInteger("code");
             String message = resultObject.getString("message");
             String message = resultObject.getString("message");
-            if(null == code||code!=0){
-                logger.info("获取token失败,accountId:{},message:{}",accountId,message);
+            if (null == code || code != 0) {
+                logger.info("获取token失败,accountId:{},message:{}", accountId, message);
             }
             }
             JSONObject data = resultObject.getJSONObject("data");
             JSONObject data = resultObject.getJSONObject("data");
-            CTopOauthToken token = new CTopOauthToken(accountId,data);
-            cTopOauthTokenMapper.insert(token);
+            CTopOauthToken token = new CTopOauthToken(accountId, data);
+            if (Check.isNull(token)) {
+                Map<String, Object> deleteMap = new HashMap<>();
+                deleteMap.put("advertiser_id", state);
+                deleteMap.put("account_id", token.getAccountId());
+                cTopOauthTokenMapper.deleteByMap(deleteMap); //删除 广告主id下的相关授权信息
+                cTopOauthTokenMapper.insert(token);
+                bindAccountService.addBindAccount(token.getAccountId(), KuaishouInterfaceConstant.TYPE_AUTHORIZATION, state, KuaishouInterfaceConstant.LOGIN_TYPE_BYTEDANCE); //账号绑定
+            }
         }catch (Exception e){
         }catch (Exception e){
             e.printStackTrace();
             e.printStackTrace();
         }
         }
         return result;
         return result;
     }
     }
-
-    @Autowired
-    private CTopOauthTokenMapper cTopOauthTokenMapper;
-
-    public String getKuaishouCodeUrl(String state) throws UnsupportedEncodingException {
-        StringBuffer sb = new StringBuffer();
-        sb.append(PropertiesUtils.getValue("kuaishou_config","kuaishou_auth_url"))
-                .append(KuaishouInterfaceConstant.AUTH_PATH)
-                .append("?app_id="+PropertiesUtils.getValue("kuaishou_config","kuaishou_appid"))
-                .append("&state="+state)
-                .append("&scope=%5B%22report_service%22%2C%22ad_query%22%2C%22ad_manage%22%5D")
-                .append("&redirect_uri="+ URLEncoder.encode(PropertiesUtils.getValue("kuaishou_config","kuaishou_callback_url"),"UTF-8"));
-        return sb.toString();
-    }
-
-
-    public String getByteDanceCodeUrl(String state) throws UnsupportedEncodingException {
-        StringBuffer sb = new StringBuffer();
-        sb.append(PropertiesUtils.getValue("bytedance_config","bytedance_auth_url"))
-                .append(BytedanceInterfaceConstant.AUTH_PATH)
-                .append("?app_id="+PropertiesUtils.getValue("bytedance_config","bytedance_appid"))
-                .append("&state="+state)
-                .append("&redirect_uri="+ URLEncoder.encode(PropertiesUtils.getValue("bytedance_config","bytedance_callback_url"),"UTF-8"));
-        return sb.toString();
-    }
 }
 }

+ 277 - 0
jeecg-boot-module-system/src/main/java/org/jeecg/modules/ctop/controller/BindAccountController.java

@@ -0,0 +1,277 @@
+package org.jeecg.modules.ctop.controller;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.net.URLDecoder;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.jeecg.common.api.vo.Result;
+import org.jeecg.common.system.query.QueryGenerator;
+import org.jeecg.common.aspect.annotation.AutoLog;
+import org.jeecg.common.util.oConvertUtils;
+import org.jeecg.modules.ctop.entity.BindAccount;
+import org.jeecg.modules.ctop.service.IBindAccountService;
+
+import java.util.Date;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import lombok.extern.slf4j.Slf4j;
+
+import org.jeecgframework.poi.excel.ExcelImportUtil;
+import org.jeecgframework.poi.excel.def.NormalExcelConstants;
+import org.jeecgframework.poi.excel.entity.ExportParams;
+import org.jeecgframework.poi.excel.entity.ImportParams;
+import org.jeecgframework.poi.excel.view.JeecgEntityExcelView;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
+import org.springframework.web.multipart.MultipartHttpServletRequest;
+import org.springframework.web.servlet.ModelAndView;
+import com.alibaba.fastjson.JSON;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+
+/**
+ * @Description: 账户绑定
+ * @Author: jeecg-boot
+ * @Date: 2019-07-30
+ * @Version: V1.0
+ */
+@Slf4j
+@Api(tags = "账户绑定")
+@RestController
+@RequestMapping("/ctop/bindAccount")
+public class BindAccountController {
+    @Autowired
+    private IBindAccountService bindAccountService;
+
+
+    @GetMapping(value = "/login")
+    public Result<IPage<BindAccount>> login(String advertiserId, String accountName, String password, String loginType) {
+        Result<IPage<BindAccount>> result = new Result<IPage<BindAccount>>();
+        boolean trueOrFalse = bindAccountService.bindLogin(advertiserId, accountName, password, loginType);
+        result.setSuccess(trueOrFalse);
+        return result;
+    }
+
+    @GetMapping(value = "/authorization")
+    public Result<IPage<BindAccount>> authorization(String advertiserId, String authorizationType) {
+        Result<IPage<BindAccount>> result = new Result<IPage<BindAccount>>();
+        String codeUrl = null;
+        try {
+            codeUrl = bindAccountService.bindAuthorization(advertiserId, authorizationType);
+        } catch (UnsupportedEncodingException e) {
+            e.printStackTrace();
+        }
+        result.setMessage(codeUrl);
+        result.setSuccess(true);
+        return result;
+    }
+
+
+    /**
+     * 分页列表查询
+     *
+     * @param bindAccount
+     * @param pageNo
+     * @param pageSize
+     * @param req
+     * @return
+     */
+    @AutoLog(value = "账户绑定-分页列表查询")
+    @ApiOperation(value = "账户绑定-分页列表查询", notes = "账户绑定-分页列表查询")
+    @GetMapping(value = "/list")
+    public Result<IPage<BindAccount>> queryPageList(BindAccount bindAccount,
+                                                    @RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
+                                                    @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize,
+                                                    HttpServletRequest req) {
+        Result<IPage<BindAccount>> result = new Result<IPage<BindAccount>>();
+        QueryWrapper<BindAccount> queryWrapper = QueryGenerator.initQueryWrapper(bindAccount, req.getParameterMap());
+        Page<BindAccount> page = new Page<BindAccount>(pageNo, pageSize);
+        IPage<BindAccount> pageList = bindAccountService.page(page, queryWrapper);
+        result.setSuccess(true);
+        result.setResult(pageList);
+        return result;
+    }
+
+    /**
+     * 添加
+     *
+     * @param bindAccount
+     * @return
+     */
+    @AutoLog(value = "账户绑定-添加")
+    @ApiOperation(value = "账户绑定-添加", notes = "账户绑定-添加")
+    @PostMapping(value = "/add")
+    public Result<BindAccount> add(@RequestBody BindAccount bindAccount) {
+        Result<BindAccount> result = new Result<BindAccount>();
+        try {
+            bindAccountService.save(bindAccount);
+            result.success("添加成功!");
+        } catch (Exception e) {
+            log.error(e.getMessage(), e);
+            result.error500("操作失败");
+        }
+        return result;
+    }
+
+    /**
+     * 编辑
+     *
+     * @param bindAccount
+     * @return
+     */
+    @AutoLog(value = "账户绑定-编辑")
+    @ApiOperation(value = "账户绑定-编辑", notes = "账户绑定-编辑")
+    @PutMapping(value = "/edit")
+    public Result<BindAccount> edit(@RequestBody BindAccount bindAccount) {
+        Result<BindAccount> result = new Result<BindAccount>();
+        BindAccount bindAccountEntity = bindAccountService.getById(bindAccount.getId());
+        if (bindAccountEntity == null) {
+            result.error500("未找到对应实体");
+        } else {
+            boolean ok = bindAccountService.updateById(bindAccount);
+            //TODO 返回false说明什么?
+            if (ok) {
+                result.success("修改成功!");
+            }
+        }
+
+        return result;
+    }
+
+    /**
+     * 通过id删除
+     *
+     * @param id
+     * @return
+     */
+    @AutoLog(value = "账户绑定-通过id删除")
+    @ApiOperation(value = "账户绑定-通过id删除", notes = "账户绑定-通过id删除")
+    @DeleteMapping(value = "/delete")
+    public Result<?> delete(@RequestParam(name = "id", required = true) String id) {
+        try {
+            bindAccountService.removeById(id);
+        } catch (Exception e) {
+            log.error("删除失败", e.getMessage());
+            return Result.error("删除失败!");
+        }
+        return Result.ok("删除成功!");
+    }
+
+    /**
+     * 批量删除
+     *
+     * @param ids
+     * @return
+     */
+    @AutoLog(value = "账户绑定-批量删除")
+    @ApiOperation(value = "账户绑定-批量删除", notes = "账户绑定-批量删除")
+    @DeleteMapping(value = "/deleteBatch")
+    public Result<BindAccount> deleteBatch(@RequestParam(name = "ids", required = true) String ids) {
+        Result<BindAccount> result = new Result<BindAccount>();
+        if (ids == null || "".equals(ids.trim())) {
+            result.error500("参数不识别!");
+        } else {
+            this.bindAccountService.removeByIds(Arrays.asList(ids.split(",")));
+            result.success("删除成功!");
+        }
+        return result;
+    }
+
+    /**
+     * 通过id查询
+     *
+     * @param id
+     * @return
+     */
+    @AutoLog(value = "账户绑定-通过id查询")
+    @ApiOperation(value = "账户绑定-通过id查询", notes = "账户绑定-通过id查询")
+    @GetMapping(value = "/queryById")
+    public Result<BindAccount> queryById(@RequestParam(name = "id", required = true) String id) {
+        Result<BindAccount> result = new Result<BindAccount>();
+        BindAccount bindAccount = bindAccountService.getById(id);
+        if (bindAccount == null) {
+            result.error500("未找到对应实体");
+        } else {
+            result.setResult(bindAccount);
+            result.setSuccess(true);
+        }
+        return result;
+    }
+
+    /**
+     * 导出excel
+     *
+     * @param request
+     * @param response
+     */
+    @RequestMapping(value = "/exportXls")
+    public ModelAndView exportXls(HttpServletRequest request, HttpServletResponse response) {
+        // Step.1 组装查询条件
+        QueryWrapper<BindAccount> queryWrapper = null;
+        try {
+            String paramsStr = request.getParameter("paramsStr");
+            if (oConvertUtils.isNotEmpty(paramsStr)) {
+                String deString = URLDecoder.decode(paramsStr, "UTF-8");
+                BindAccount bindAccount = JSON.parseObject(deString, BindAccount.class);
+                queryWrapper = QueryGenerator.initQueryWrapper(bindAccount, request.getParameterMap());
+            }
+        } catch (UnsupportedEncodingException e) {
+            e.printStackTrace();
+        }
+
+        //Step.2 AutoPoi 导出Excel
+        ModelAndView mv = new ModelAndView(new JeecgEntityExcelView());
+        List<BindAccount> pageList = bindAccountService.list(queryWrapper);
+        //导出文件名称
+        mv.addObject(NormalExcelConstants.FILE_NAME, "账户绑定列表");
+        mv.addObject(NormalExcelConstants.CLASS, BindAccount.class);
+        mv.addObject(NormalExcelConstants.PARAMS, new ExportParams("账户绑定列表数据", "导出人:Jeecg", "导出信息"));
+        mv.addObject(NormalExcelConstants.DATA_LIST, pageList);
+        return mv;
+    }
+
+    /**
+     * 通过excel导入数据
+     *
+     * @param request
+     * @param response
+     * @return
+     */
+    @RequestMapping(value = "/importExcel", method = RequestMethod.POST)
+    public Result<?> importExcel(HttpServletRequest request, HttpServletResponse response) {
+        MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
+        Map<String, MultipartFile> fileMap = multipartRequest.getFileMap();
+        for (Map.Entry<String, MultipartFile> entity : fileMap.entrySet()) {
+            MultipartFile file = entity.getValue();// 获取上传文件对象
+            ImportParams params = new ImportParams();
+            params.setTitleRows(2);
+            params.setHeadRows(1);
+            params.setNeedSave(true);
+            try {
+                List<BindAccount> listBindAccounts = ExcelImportUtil.importExcel(file.getInputStream(), BindAccount.class, params);
+                bindAccountService.saveBatch(listBindAccounts);
+                return Result.ok("文件导入成功!数据行数:" + listBindAccounts.size());
+            } catch (Exception e) {
+                log.error(e.getMessage(), e);
+                return Result.error("文件导入失败:" + e.getMessage());
+            } finally {
+                try {
+                    file.getInputStream().close();
+                } catch (IOException e) {
+                    e.printStackTrace();
+                }
+            }
+        }
+        return Result.ok("文件导入失败!");
+    }
+
+}

+ 150 - 11
jeecg-boot-module-system/src/main/java/org/jeecg/modules/ctop/controller/ByteDanceAdvertiserPostController.java

@@ -1,5 +1,7 @@
 package org.jeecg.modules.ctop.controller;
 package org.jeecg.modules.ctop.controller;
 
 
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
@@ -29,7 +31,8 @@ public class ByteDanceAdvertiserPostController {
     private IByteDanceAdvertiserDataService advertiserDataService;
     private IByteDanceAdvertiserDataService advertiserDataService;
 
 
     /**
     /**
-     * 1:获取广告主信息 @param accountId 本平台广告主id
+     * 1:获取广告主信息
+     * @param accountId 本平台广告主id
      */
      */
     @RequestMapping("/advertiser/info")
     @RequestMapping("/advertiser/info")
     public Map<String, Object> advertiserInfo(String accountId) {
     public Map<String, Object> advertiserInfo(String accountId) {
@@ -37,7 +40,8 @@ public class ByteDanceAdvertiserPostController {
     }
     }
 
 
     /**
     /**
-     * 2:获取广告主广告计划信息 @param accountId 本平台广告主id
+     * 2:获取广告主广告计划信息
+     * @param accountId 本平台广告主id
      */
      */
     @RequestMapping("/advertiser/plan/get")
     @RequestMapping("/advertiser/plan/get")
     public Map<String, Object> advertiserPlan(String accountId, String ids) {
     public Map<String, Object> advertiserPlan(String accountId, String ids) {
@@ -45,7 +49,8 @@ public class ByteDanceAdvertiserPostController {
     }
     }
 
 
     /**
     /**
-     * 3:修改广告计划信息状态 @param accountId 本平台广告主id
+     * 3:修改广告计划信息状态
+     * @param accountId 本平台广告主id
      */
      */
     @RequestMapping("/advertiser/plan/update/status")
     @RequestMapping("/advertiser/plan/update/status")
     public Map<String, Object> advertiserPlanUpdateStatus(String accountId, String adIds, String optStatus) {
     public Map<String, Object> advertiserPlanUpdateStatus(String accountId, String adIds, String optStatus) {
@@ -53,7 +58,8 @@ public class ByteDanceAdvertiserPostController {
     }
     }
 
 
     /**
     /**
-     * 4:修改广告计划信息状态 @param accountId 本平台广告主id
+     * 4:修改广告计划信息状态
+     * @param accountId 本平台广告主id
      */
      */
     @RequestMapping("/advertiser/plan/update/bid")
     @RequestMapping("/advertiser/plan/update/bid")
     public Map<String, Object> advertiserPlanUpdateBid(String accountId, String adIds, String bids) {
     public Map<String, Object> advertiserPlanUpdateBid(String accountId, String adIds, String bids) {
@@ -61,7 +67,8 @@ public class ByteDanceAdvertiserPostController {
     }
     }
 
 
     /**
     /**
-     * 5:修改广告计划信息状态 @param accountId 本平台广告主id
+     * 5:修改广告计划信息状态
+     * @param accountId 本平台广告主id
      */
      */
     @RequestMapping("/advertiser/plan/update/budget")
     @RequestMapping("/advertiser/plan/update/budget")
     public Map<String, Object> advertiserPlanUpdateBudget(String accountId, String adIds, String budgets) {
     public Map<String, Object> advertiserPlanUpdateBudget(String accountId, String adIds, String budgets) {
@@ -69,7 +76,8 @@ public class ByteDanceAdvertiserPostController {
     }
     }
 
 
     /**
     /**
-     * 6:获取广告主广告预算信息 @param accountId 本平台广告主id
+     * 6:获取广告主广告预算信息
+     * @param accountId 本平台广告主id
      */
      */
     @RequestMapping("/advertiser/budget/get/")
     @RequestMapping("/advertiser/budget/get/")
     public Map<String, Object> advertiserBudget(String accountId) {
     public Map<String, Object> advertiserBudget(String accountId) {
@@ -77,7 +85,8 @@ public class ByteDanceAdvertiserPostController {
     }
     }
 
 
     /**
     /**
-     * 7:获取广告主广告组信息 @param accountId 本平台广告主id
+     * 7:获取广告主广告组信息
+     * @param accountId 本平台广告主id
      */
      */
     @RequestMapping("/advertiser/campaign/get")
     @RequestMapping("/advertiser/campaign/get")
     public Map<String, Object> advertiserCampaign(String accountId, String ids) {
     public Map<String, Object> advertiserCampaign(String accountId, String ids) {
@@ -85,7 +94,8 @@ public class ByteDanceAdvertiserPostController {
     }
     }
 
 
     /**
     /**
-     * 8:获取广告主广告创意信息 @param accountId 本平台广告主id
+     * 8:获取广告主广告创意信息
+     * @param accountId 本平台广告主id
      */
      */
     @RequestMapping("/advertiser/creative/get")
     @RequestMapping("/advertiser/creative/get")
     public Map<String, Object> getAdvertiserCreative(String accountId, String ids) {
     public Map<String, Object> getAdvertiserCreative(String accountId, String ids) {
@@ -93,7 +103,8 @@ public class ByteDanceAdvertiserPostController {
     }
     }
 
 
     /**
     /**
-     * 9:修改广告创意信息状态 @param accountId 本平台广告主id
+     * 9:修改广告创意信息状态
+     * @param accountId 本平台广告主id
      */
      */
     @RequestMapping("/advertiser/update/status/")
     @RequestMapping("/advertiser/update/status/")
     public Map<String, Object> advertiserCreativeUpdateStatus(String accountId, String creativeIds, String optStatus) {
     public Map<String, Object> advertiserCreativeUpdateStatus(String accountId, String creativeIds, String optStatus) {
@@ -101,7 +112,9 @@ public class ByteDanceAdvertiserPostController {
     }
     }
 
 
     /**
     /**
-     * 10:获取广告主广告创意素材信息 @param accountId 本平台广告主id @param creativeIds 广告创意id
+     * 10:获取广告主广告创意素材信息
+     * @param accountId 本平台广告主id
+     * @param creativeIds 广告创意id
      */
      */
     @RequestMapping("/advertiser/creative/material/read")
     @RequestMapping("/advertiser/creative/material/read")
     public Map<String, Object> advertiserCreativeMaterial(String accountId, String creativeIds) {
     public Map<String, Object> advertiserCreativeMaterial(String accountId, String creativeIds) {
@@ -109,13 +122,107 @@ public class ByteDanceAdvertiserPostController {
     }
     }
 
 
     /**
     /**
-     * 11:创建广告组信息 @param accountId 本平台广告主id
+     * 11:创建广告组信息
+     * @param accountId 本平台广告主id
      */
      */
     @RequestMapping("/advertiser/campaign/create")
     @RequestMapping("/advertiser/campaign/create")
     public Map<String, Object> advertiserCampaignCreate(String accountId, String campaignName, String budgetMode, Integer budget, String landingType) {
     public Map<String, Object> advertiserCampaignCreate(String accountId, String campaignName, String budgetMode, Integer budget, String landingType) {
         return advertiserDataService.advertiserCampaignCreate(accountId, campaignName, budgetMode, budget, landingType);
         return advertiserDataService.advertiserCampaignCreate(accountId, campaignName, budgetMode, budget, landingType);
     }
     }
 
 
+//    /**
+//     * 11:创建广告计划信息
+//     * @param accountId 本平台广告主id
+//     */
+//    @RequestMapping("/advertiser/plan/create")
+//    public Map<String, Object> advertiserPlanCreate(String accountId, Long campaignId, String deliveryRange, String budgetMode, String budget,String startTime,String endTime,
+//                                                    Integer bid,String pricing,String scheduleType,String scheduleTime,String flowControlMode,String openUrl,String downloadType,String externalUrl,String downloadUrl,
+//                                                    String name,String appType,String packageName,String hideIfConverted,String advertiserStoreIds,String storeType,String hideIfExists,String cpaBid,String convertId,String externalActions,
+//                                                    String unionVideoType,String deepBidType,String deepCpabid,String smartBidType,String adjustCpa,String retargetingTagsInclude,String retargetingTagsExclude,String gender,String age,String androidOsv,
+//                                                    String iosOsv,String carrier,String ac,String deviceBrand,String articleCategory,String activateType,String platform,String city,String businessIds,String district,String locationType,String adTag,String interestTags,String appBehaviorTarget,
+//                                                    String appCategory,String appIds,String productPlatformId,String externalUrlParams,String openUrlParams,String dpaLocalAudience,String includeCustomActions,String excludeCustomActions,String superiorPopularityType,String flowPackage,String excludeFlowPackage,
+//                                                    String dpaCategories,String dpaProducts,String dpaAdtype,String paramsType,String dpaExternalUrls,String dpa_externalUrlField,String dpaOpenUrlType,String dpaOpenUrls,String dpaOpenUrlField,String dpaProductTarget,String title,String type,String rule,String value) {
+//        return advertisePlanService.advertiserPlanCreate(accountId,campaignId,deliveryRange,budgetMode,budget,startTime,endTime,
+//                bid,pricing,scheduleType,scheduleTime,flowControlMode,openUrl,downloadType,externalUrl,downloadUrl,
+//                name,appType,packageName,hideIfConverted,advertiserStoreIds,storeType,hideIfExists,cpaBid,convertId,externalActions,
+//                unionVideoType,deepBidType,deepCpabid,smartBidType,adjustCpa,retargetingTagsInclude,retargetingTagsExclude,gender,age,androidOsv,
+//                iosOsv,carrier,ac,deviceBrand,articleCategory,activateType,platform,city,businessIds,district,locationType,adTag,interestTags,appBehaviorTarget,
+//                appCategory,appIds,productPlatformId,externalUrlParams,openUrlParams,dpaLocalAudience,includeCustomActions,excludeCustomActions,superiorPopularityType,flowPackage,excludeFlowPackage,
+//                dpaCategories,dpaProducts,dpaAdtype,paramsType,dpaExternalUrls,dpa_externalUrlField,dpaOpenUrlType,dpaOpenUrls,dpaOpenUrlField,dpaProductTarget,title,type,rule,value);
+//    }
+
+    /**
+     * 11:创建广告计划信息
+     */
+    @RequestMapping("/advertiser/plan/create")
+    public Map<String, Object> advertiserPlanCreate() {
+        String accountId = "e9ca23d68d884d4ebb19d07889727dae";
+        Long campaignId = 1640397758132260L;
+        JSONObject data = new JSONObject();
+        data.put("campaign_id", campaignId);
+        data.put("delivery_range", "DEFAULT");
+        data.put("budget_mode", "BUDGET_MODE_DAY");
+        data.put("budget", 2000);//需要大于bid
+        data.put("bid", 100);
+        data.put("start_time", "2019-07-30 01:00");
+        data.put("end_time", "2019-07-31 01:00");
+        data.put("pricing", "PRICING_CPM");
+        data.put("schedule_type", "SCHEDULE_FROM_NOW");
+        data.put("flow_control_mode", "FLOW_CONTROL_MODE_FAST");
+        data.put("name", "测试计划名称");
+        data.put("external_url", "https://lordsmobile.176.com/download.php");
+        data.put("download_url", "https://lordsmobile.176.com/download.php");
+        data.put("download_type", "DOWNLOAD_URL");//坑
+        data.put("package", "com.igg.android.lordsmobile_cn");//坑
+        data.put("app_type", "APP_ANDROID");//坑
+        return advertisePlanService.advertiserPlanCreate(accountId, campaignId, data.toJSONString());
+    }
+
+    /**
+     * 11:创建广告创意信息
+     *
+     * @param accountId 本平台广告主id
+     */
+    @RequestMapping("/advertiser/creative/create")
+    public Map<String, Object> advertiserCreativeCreate(String accountId, Long campaignId, String dataString) {
+        String getAccountId = "e9ca23d68d884d4ebb19d07889727dae";
+        Long adId = 1640445647618076L;
+        JSONObject data = new JSONObject();
+        JSONArray jsonArray = new JSONArray();
+        jsonArray.add("INVENTORY_FEED");
+        jsonArray.add("INVENTORY_VIDEO_FEED");
+        jsonArray.add("INVENTORY_HOTSOON_FEED");
+        jsonArray.add("INVENTORY_AWEME_FEED");
+        jsonArray.add("INVENTORY_UNION_SLOT");
+        data.put("inventory_type", jsonArray);
+
+        data.put("ad_id", adId);
+
+        data.put("app_name", "asdasd");
+
+        data.put("web_url", "http://www.chengzijianzhan.com/tetris/page/1593177139994627/");
+        JSONArray keywords = new JSONArray();
+        keywords.add("游戏");
+        keywords.add("娱乐");
+        keywords.add("塔防");
+        keywords.add("养成");
+        data.put("ad_keywords", keywords);
+        JSONArray creatives = new JSONArray();
+        JSONObject creative = new JSONObject();
+
+        creative.put("image_mode", "CREATIVE_IMAGE_MODE_VIDEO_VERTICAL");
+        creative.put("image_id", "71d10006f7067d0be514");
+        creative.put("video_id", "v020334a0000bkvbakj6936tng75j6ag");
+        creative.put("title", "测试标题11");
+        creatives.add(creative);
+        data.put("creatives", creatives);
+        data.put("third_industry_id", 19050501);
+        data.put("title", "测试创意标题123");
+        return creativeService.creativeCreate(getAccountId, adId, data.toJSONString());
+    }
+
+    @Autowired
+    private IByteDanceCreativeService creativeService;
     /**
     /**
      * 12:广告组更新状态信息 @param accountId 本平台广告主id
      * 12:广告组更新状态信息 @param accountId 本平台广告主id
      */
      */
@@ -141,6 +248,36 @@ public class ByteDanceAdvertiserPostController {
     }
     }
 
 
     /**
     /**
+     * 15:上传视频信息
+     *
+     * @param accountId 本平台广告主id
+     * @
+     */
+    @RequestMapping("/advertiser/video/add")
+    public Map<String, Object> advertiserVideoAdd(String accountId, Long videoFileId) {
+        return fileInfoService.uploadVideoToTemplate(accountId, videoFileId, "bytedance");
+    }
+
+    /**
+     * 15:上传图片信息
+     *
+     * @param accountId 本平台广告主id
+     * @
+     */
+    @RequestMapping("/advertiser/image/add")
+    public Map<String, Object> advertiserImageAdd(String accountId, Long imageFileId) {
+        return fileInfoService.uploadImageToTemplate(accountId, imageFileId, "bytedance");
+    }
+
+    @RequestMapping("/industry/list")
+    public Map<String, Object> industryList(String accountId) {
+        return fileInfoService.getIndustryList(accountId);
+    }
+
+    @Autowired
+    private IFileInfoService fileInfoService;
+
+    /**
      * @param audience
      * @param audience
      * @param pageNo
      * @param pageNo
      * @param pageSize
      * @param pageSize
@@ -190,4 +327,6 @@ public class ByteDanceAdvertiserPostController {
 
 
     @Autowired
     @Autowired
     private ISysDictItemService sysDictItemService;
     private ISysDictItemService sysDictItemService;
+    @Autowired
+    private IByteDanceAdvertisePlanService advertisePlanService;
 }
 }

+ 253 - 0
jeecg-boot-module-system/src/main/java/org/jeecg/modules/ctop/controller/ByteDanceImageInfoController.java

@@ -0,0 +1,253 @@
+package org.jeecg.modules.ctop.controller;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.net.URLDecoder;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.jeecg.common.api.vo.Result;
+import org.jeecg.common.system.query.QueryGenerator;
+import org.jeecg.common.aspect.annotation.AutoLog;
+import org.jeecg.common.util.oConvertUtils;
+import org.jeecg.modules.ctop.entity.ByteDanceImageInfo;
+import org.jeecg.modules.ctop.service.IByteDanceImageInfoService;
+
+import java.util.Date;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import lombok.extern.slf4j.Slf4j;
+
+import org.jeecgframework.poi.excel.ExcelImportUtil;
+import org.jeecgframework.poi.excel.def.NormalExcelConstants;
+import org.jeecgframework.poi.excel.entity.ExportParams;
+import org.jeecgframework.poi.excel.entity.ImportParams;
+import org.jeecgframework.poi.excel.view.JeecgEntityExcelView;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
+import org.springframework.web.multipart.MultipartHttpServletRequest;
+import org.springframework.web.servlet.ModelAndView;
+import com.alibaba.fastjson.JSON;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+
+/**
+ * @Description: 头条图片素材信息
+ * @Author: jeecg-boot
+ * @Date: 2019-07-29
+ * @Version: V1.0
+ */
+@Slf4j
+@Api(tags = "头条图片素材信息")
+@RestController
+@RequestMapping("/ctop/byteDanceImageInfo")
+public class ByteDanceImageInfoController {
+    @Autowired
+    private IByteDanceImageInfoService byteDanceImageInfoService;
+
+    /**
+     * 分页列表查询
+     *
+     * @param byteDanceImageInfo
+     * @param pageNo
+     * @param pageSize
+     * @param req
+     * @return
+     */
+    @AutoLog(value = "头条图片素材信息-分页列表查询")
+    @ApiOperation(value = "头条图片素材信息-分页列表查询", notes = "头条图片素材信息-分页列表查询")
+    @GetMapping(value = "/list")
+    public Result<IPage<ByteDanceImageInfo>> queryPageList(ByteDanceImageInfo byteDanceImageInfo,
+                                                           @RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
+                                                           @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize,
+                                                           HttpServletRequest req) {
+        Result<IPage<ByteDanceImageInfo>> result = new Result<IPage<ByteDanceImageInfo>>();
+        QueryWrapper<ByteDanceImageInfo> queryWrapper = QueryGenerator.initQueryWrapper(byteDanceImageInfo, req.getParameterMap());
+        Page<ByteDanceImageInfo> page = new Page<ByteDanceImageInfo>(pageNo, pageSize);
+        IPage<ByteDanceImageInfo> pageList = byteDanceImageInfoService.page(page, queryWrapper);
+        result.setSuccess(true);
+        result.setResult(pageList);
+        return result;
+    }
+
+    /**
+     * 添加
+     *
+     * @param byteDanceImageInfo
+     * @return
+     */
+    @AutoLog(value = "头条图片素材信息-添加")
+    @ApiOperation(value = "头条图片素材信息-添加", notes = "头条图片素材信息-添加")
+    @PostMapping(value = "/add")
+    public Result<ByteDanceImageInfo> add(@RequestBody ByteDanceImageInfo byteDanceImageInfo) {
+        Result<ByteDanceImageInfo> result = new Result<ByteDanceImageInfo>();
+        try {
+            byteDanceImageInfoService.save(byteDanceImageInfo);
+            result.success("添加成功!");
+        } catch (Exception e) {
+            log.error(e.getMessage(), e);
+            result.error500("操作失败");
+        }
+        return result;
+    }
+
+    /**
+     * 编辑
+     *
+     * @param byteDanceImageInfo
+     * @return
+     */
+    @AutoLog(value = "头条图片素材信息-编辑")
+    @ApiOperation(value = "头条图片素材信息-编辑", notes = "头条图片素材信息-编辑")
+    @PutMapping(value = "/edit")
+    public Result<ByteDanceImageInfo> edit(@RequestBody ByteDanceImageInfo byteDanceImageInfo) {
+        Result<ByteDanceImageInfo> result = new Result<ByteDanceImageInfo>();
+        ByteDanceImageInfo byteDanceImageInfoEntity = byteDanceImageInfoService.getById(byteDanceImageInfo.getId());
+        if (byteDanceImageInfoEntity == null) {
+            result.error500("未找到对应实体");
+        } else {
+            boolean ok = byteDanceImageInfoService.updateById(byteDanceImageInfo);
+            //TODO 返回false说明什么?
+            if (ok) {
+                result.success("修改成功!");
+            }
+        }
+
+        return result;
+    }
+
+    /**
+     * 通过id删除
+     *
+     * @param id
+     * @return
+     */
+    @AutoLog(value = "头条图片素材信息-通过id删除")
+    @ApiOperation(value = "头条图片素材信息-通过id删除", notes = "头条图片素材信息-通过id删除")
+    @DeleteMapping(value = "/delete")
+    public Result<?> delete(@RequestParam(name = "id", required = true) String id) {
+        try {
+            byteDanceImageInfoService.removeById(id);
+        } catch (Exception e) {
+            log.error("删除失败", e.getMessage());
+            return Result.error("删除失败!");
+        }
+        return Result.ok("删除成功!");
+    }
+
+    /**
+     * 批量删除
+     *
+     * @param ids
+     * @return
+     */
+    @AutoLog(value = "头条图片素材信息-批量删除")
+    @ApiOperation(value = "头条图片素材信息-批量删除", notes = "头条图片素材信息-批量删除")
+    @DeleteMapping(value = "/deleteBatch")
+    public Result<ByteDanceImageInfo> deleteBatch(@RequestParam(name = "ids", required = true) String ids) {
+        Result<ByteDanceImageInfo> result = new Result<ByteDanceImageInfo>();
+        if (ids == null || "".equals(ids.trim())) {
+            result.error500("参数不识别!");
+        } else {
+            this.byteDanceImageInfoService.removeByIds(Arrays.asList(ids.split(",")));
+            result.success("删除成功!");
+        }
+        return result;
+    }
+
+    /**
+     * 通过id查询
+     *
+     * @param id
+     * @return
+     */
+    @AutoLog(value = "头条图片素材信息-通过id查询")
+    @ApiOperation(value = "头条图片素材信息-通过id查询", notes = "头条图片素材信息-通过id查询")
+    @GetMapping(value = "/queryById")
+    public Result<ByteDanceImageInfo> queryById(@RequestParam(name = "id", required = true) String id) {
+        Result<ByteDanceImageInfo> result = new Result<ByteDanceImageInfo>();
+        ByteDanceImageInfo byteDanceImageInfo = byteDanceImageInfoService.getById(id);
+        if (byteDanceImageInfo == null) {
+            result.error500("未找到对应实体");
+        } else {
+            result.setResult(byteDanceImageInfo);
+            result.setSuccess(true);
+        }
+        return result;
+    }
+
+    /**
+     * 导出excel
+     *
+     * @param request
+     * @param response
+     */
+    @RequestMapping(value = "/exportXls")
+    public ModelAndView exportXls(HttpServletRequest request, HttpServletResponse response) {
+        // Step.1 组装查询条件
+        QueryWrapper<ByteDanceImageInfo> queryWrapper = null;
+        try {
+            String paramsStr = request.getParameter("paramsStr");
+            if (oConvertUtils.isNotEmpty(paramsStr)) {
+                String deString = URLDecoder.decode(paramsStr, "UTF-8");
+                ByteDanceImageInfo byteDanceImageInfo = JSON.parseObject(deString, ByteDanceImageInfo.class);
+                queryWrapper = QueryGenerator.initQueryWrapper(byteDanceImageInfo, request.getParameterMap());
+            }
+        } catch (UnsupportedEncodingException e) {
+            e.printStackTrace();
+        }
+
+        //Step.2 AutoPoi 导出Excel
+        ModelAndView mv = new ModelAndView(new JeecgEntityExcelView());
+        List<ByteDanceImageInfo> pageList = byteDanceImageInfoService.list(queryWrapper);
+        //导出文件名称
+        mv.addObject(NormalExcelConstants.FILE_NAME, "头条图片素材信息列表");
+        mv.addObject(NormalExcelConstants.CLASS, ByteDanceImageInfo.class);
+        mv.addObject(NormalExcelConstants.PARAMS, new ExportParams("头条图片素材信息列表数据", "导出人:Jeecg", "导出信息"));
+        mv.addObject(NormalExcelConstants.DATA_LIST, pageList);
+        return mv;
+    }
+
+    /**
+     * 通过excel导入数据
+     *
+     * @param request
+     * @param response
+     * @return
+     */
+    @RequestMapping(value = "/importExcel", method = RequestMethod.POST)
+    public Result<?> importExcel(HttpServletRequest request, HttpServletResponse response) {
+        MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
+        Map<String, MultipartFile> fileMap = multipartRequest.getFileMap();
+        for (Map.Entry<String, MultipartFile> entity : fileMap.entrySet()) {
+            MultipartFile file = entity.getValue();// 获取上传文件对象
+            ImportParams params = new ImportParams();
+            params.setTitleRows(2);
+            params.setHeadRows(1);
+            params.setNeedSave(true);
+            try {
+                List<ByteDanceImageInfo> listByteDanceImageInfos = ExcelImportUtil.importExcel(file.getInputStream(), ByteDanceImageInfo.class, params);
+                byteDanceImageInfoService.saveBatch(listByteDanceImageInfos);
+                return Result.ok("文件导入成功!数据行数:" + listByteDanceImageInfos.size());
+            } catch (Exception e) {
+                log.error(e.getMessage(), e);
+                return Result.error("文件导入失败:" + e.getMessage());
+            } finally {
+                try {
+                    file.getInputStream().close();
+                } catch (IOException e) {
+                    e.printStackTrace();
+                }
+            }
+        }
+        return Result.ok("文件导入失败!");
+    }
+
+}

+ 253 - 0
jeecg-boot-module-system/src/main/java/org/jeecg/modules/ctop/controller/ByteDanceVideoInfoController.java

@@ -0,0 +1,253 @@
+package org.jeecg.modules.ctop.controller;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.net.URLDecoder;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.jeecg.common.api.vo.Result;
+import org.jeecg.common.system.query.QueryGenerator;
+import org.jeecg.common.aspect.annotation.AutoLog;
+import org.jeecg.common.util.oConvertUtils;
+import org.jeecg.modules.ctop.entity.ByteDanceVideoInfo;
+import org.jeecg.modules.ctop.service.IByteDanceVideoInfoService;
+
+import java.util.Date;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import lombok.extern.slf4j.Slf4j;
+
+import org.jeecgframework.poi.excel.ExcelImportUtil;
+import org.jeecgframework.poi.excel.def.NormalExcelConstants;
+import org.jeecgframework.poi.excel.entity.ExportParams;
+import org.jeecgframework.poi.excel.entity.ImportParams;
+import org.jeecgframework.poi.excel.view.JeecgEntityExcelView;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
+import org.springframework.web.multipart.MultipartHttpServletRequest;
+import org.springframework.web.servlet.ModelAndView;
+import com.alibaba.fastjson.JSON;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+
+/**
+ * @Description: 今日头条视频素材信息
+ * @Author: jeecg-boot
+ * @Date: 2019-07-29
+ * @Version: V1.0
+ */
+@Slf4j
+@Api(tags = "今日头条视频素材信息")
+@RestController
+@RequestMapping("/ctop/byteDanceVideoInfo")
+public class ByteDanceVideoInfoController {
+    @Autowired
+    private IByteDanceVideoInfoService byteDanceVideoInfoService;
+
+    /**
+     * 分页列表查询
+     *
+     * @param byteDanceVideoInfo
+     * @param pageNo
+     * @param pageSize
+     * @param req
+     * @return
+     */
+    @AutoLog(value = "今日头条视频素材信息-分页列表查询")
+    @ApiOperation(value = "今日头条视频素材信息-分页列表查询", notes = "今日头条视频素材信息-分页列表查询")
+    @GetMapping(value = "/list")
+    public Result<IPage<ByteDanceVideoInfo>> queryPageList(ByteDanceVideoInfo byteDanceVideoInfo,
+                                                           @RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
+                                                           @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize,
+                                                           HttpServletRequest req) {
+        Result<IPage<ByteDanceVideoInfo>> result = new Result<IPage<ByteDanceVideoInfo>>();
+        QueryWrapper<ByteDanceVideoInfo> queryWrapper = QueryGenerator.initQueryWrapper(byteDanceVideoInfo, req.getParameterMap());
+        Page<ByteDanceVideoInfo> page = new Page<ByteDanceVideoInfo>(pageNo, pageSize);
+        IPage<ByteDanceVideoInfo> pageList = byteDanceVideoInfoService.page(page, queryWrapper);
+        result.setSuccess(true);
+        result.setResult(pageList);
+        return result;
+    }
+
+    /**
+     * 添加
+     *
+     * @param byteDanceVideoInfo
+     * @return
+     */
+    @AutoLog(value = "今日头条视频素材信息-添加")
+    @ApiOperation(value = "今日头条视频素材信息-添加", notes = "今日头条视频素材信息-添加")
+    @PostMapping(value = "/add")
+    public Result<ByteDanceVideoInfo> add(@RequestBody ByteDanceVideoInfo byteDanceVideoInfo) {
+        Result<ByteDanceVideoInfo> result = new Result<ByteDanceVideoInfo>();
+        try {
+            byteDanceVideoInfoService.save(byteDanceVideoInfo);
+            result.success("添加成功!");
+        } catch (Exception e) {
+            log.error(e.getMessage(), e);
+            result.error500("操作失败");
+        }
+        return result;
+    }
+
+    /**
+     * 编辑
+     *
+     * @param byteDanceVideoInfo
+     * @return
+     */
+    @AutoLog(value = "今日头条视频素材信息-编辑")
+    @ApiOperation(value = "今日头条视频素材信息-编辑", notes = "今日头条视频素材信息-编辑")
+    @PutMapping(value = "/edit")
+    public Result<ByteDanceVideoInfo> edit(@RequestBody ByteDanceVideoInfo byteDanceVideoInfo) {
+        Result<ByteDanceVideoInfo> result = new Result<ByteDanceVideoInfo>();
+        ByteDanceVideoInfo byteDanceVideoInfoEntity = byteDanceVideoInfoService.getById(byteDanceVideoInfo.getId());
+        if (byteDanceVideoInfoEntity == null) {
+            result.error500("未找到对应实体");
+        } else {
+            boolean ok = byteDanceVideoInfoService.updateById(byteDanceVideoInfo);
+            //TODO 返回false说明什么?
+            if (ok) {
+                result.success("修改成功!");
+            }
+        }
+
+        return result;
+    }
+
+    /**
+     * 通过id删除
+     *
+     * @param id
+     * @return
+     */
+    @AutoLog(value = "今日头条视频素材信息-通过id删除")
+    @ApiOperation(value = "今日头条视频素材信息-通过id删除", notes = "今日头条视频素材信息-通过id删除")
+    @DeleteMapping(value = "/delete")
+    public Result<?> delete(@RequestParam(name = "id", required = true) String id) {
+        try {
+            byteDanceVideoInfoService.removeById(id);
+        } catch (Exception e) {
+            log.error("删除失败", e.getMessage());
+            return Result.error("删除失败!");
+        }
+        return Result.ok("删除成功!");
+    }
+
+    /**
+     * 批量删除
+     *
+     * @param ids
+     * @return
+     */
+    @AutoLog(value = "今日头条视频素材信息-批量删除")
+    @ApiOperation(value = "今日头条视频素材信息-批量删除", notes = "今日头条视频素材信息-批量删除")
+    @DeleteMapping(value = "/deleteBatch")
+    public Result<ByteDanceVideoInfo> deleteBatch(@RequestParam(name = "ids", required = true) String ids) {
+        Result<ByteDanceVideoInfo> result = new Result<ByteDanceVideoInfo>();
+        if (ids == null || "".equals(ids.trim())) {
+            result.error500("参数不识别!");
+        } else {
+            this.byteDanceVideoInfoService.removeByIds(Arrays.asList(ids.split(",")));
+            result.success("删除成功!");
+        }
+        return result;
+    }
+
+    /**
+     * 通过id查询
+     *
+     * @param id
+     * @return
+     */
+    @AutoLog(value = "今日头条视频素材信息-通过id查询")
+    @ApiOperation(value = "今日头条视频素材信息-通过id查询", notes = "今日头条视频素材信息-通过id查询")
+    @GetMapping(value = "/queryById")
+    public Result<ByteDanceVideoInfo> queryById(@RequestParam(name = "id", required = true) String id) {
+        Result<ByteDanceVideoInfo> result = new Result<ByteDanceVideoInfo>();
+        ByteDanceVideoInfo byteDanceVideoInfo = byteDanceVideoInfoService.getById(id);
+        if (byteDanceVideoInfo == null) {
+            result.error500("未找到对应实体");
+        } else {
+            result.setResult(byteDanceVideoInfo);
+            result.setSuccess(true);
+        }
+        return result;
+    }
+
+    /**
+     * 导出excel
+     *
+     * @param request
+     * @param response
+     */
+    @RequestMapping(value = "/exportXls")
+    public ModelAndView exportXls(HttpServletRequest request, HttpServletResponse response) {
+        // Step.1 组装查询条件
+        QueryWrapper<ByteDanceVideoInfo> queryWrapper = null;
+        try {
+            String paramsStr = request.getParameter("paramsStr");
+            if (oConvertUtils.isNotEmpty(paramsStr)) {
+                String deString = URLDecoder.decode(paramsStr, "UTF-8");
+                ByteDanceVideoInfo byteDanceVideoInfo = JSON.parseObject(deString, ByteDanceVideoInfo.class);
+                queryWrapper = QueryGenerator.initQueryWrapper(byteDanceVideoInfo, request.getParameterMap());
+            }
+        } catch (UnsupportedEncodingException e) {
+            e.printStackTrace();
+        }
+
+        //Step.2 AutoPoi 导出Excel
+        ModelAndView mv = new ModelAndView(new JeecgEntityExcelView());
+        List<ByteDanceVideoInfo> pageList = byteDanceVideoInfoService.list(queryWrapper);
+        //导出文件名称
+        mv.addObject(NormalExcelConstants.FILE_NAME, "今日头条视频素材信息列表");
+        mv.addObject(NormalExcelConstants.CLASS, ByteDanceVideoInfo.class);
+        mv.addObject(NormalExcelConstants.PARAMS, new ExportParams("今日头条视频素材信息列表数据", "导出人:Jeecg", "导出信息"));
+        mv.addObject(NormalExcelConstants.DATA_LIST, pageList);
+        return mv;
+    }
+
+    /**
+     * 通过excel导入数据
+     *
+     * @param request
+     * @param response
+     * @return
+     */
+    @RequestMapping(value = "/importExcel", method = RequestMethod.POST)
+    public Result<?> importExcel(HttpServletRequest request, HttpServletResponse response) {
+        MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
+        Map<String, MultipartFile> fileMap = multipartRequest.getFileMap();
+        for (Map.Entry<String, MultipartFile> entity : fileMap.entrySet()) {
+            MultipartFile file = entity.getValue();// 获取上传文件对象
+            ImportParams params = new ImportParams();
+            params.setTitleRows(2);
+            params.setHeadRows(1);
+            params.setNeedSave(true);
+            try {
+                List<ByteDanceVideoInfo> listByteDanceVideoInfos = ExcelImportUtil.importExcel(file.getInputStream(), ByteDanceVideoInfo.class, params);
+                byteDanceVideoInfoService.saveBatch(listByteDanceVideoInfos);
+                return Result.ok("文件导入成功!数据行数:" + listByteDanceVideoInfos.size());
+            } catch (Exception e) {
+                log.error(e.getMessage(), e);
+                return Result.error("文件导入失败:" + e.getMessage());
+            } finally {
+                try {
+                    file.getInputStream().close();
+                } catch (IOException e) {
+                    e.printStackTrace();
+                }
+            }
+        }
+        return Result.ok("文件导入失败!");
+    }
+
+}

+ 11 - 5
jeecg-boot-module-system/src/main/java/org/jeecg/modules/ctop/controller/CallbackController.java

@@ -3,9 +3,11 @@ package org.jeecg.modules.ctop.controller;
 import cn.com.ctop.kuaishou.modules.material.entity.KuaishouAccessToken;
 import cn.com.ctop.kuaishou.modules.material.entity.KuaishouAccessToken;
 import cn.com.ctop.kuaishou.modules.material.entity.KuaishouResultToken;
 import cn.com.ctop.kuaishou.modules.material.entity.KuaishouResultToken;
 import cn.com.ctop.kuaishou.modules.material.service.IKuaishouAccessTokenService;
 import cn.com.ctop.kuaishou.modules.material.service.IKuaishouAccessTokenService;
+import constant.KuaishouInterfaceConstant;
 import org.apache.commons.lang.StringUtils;
 import org.apache.commons.lang.StringUtils;
 import org.jeecg.modules.ctop.entity.CTopOauthToken;
 import org.jeecg.modules.ctop.entity.CTopOauthToken;
 import org.jeecg.modules.ctop.mapper.CTopOauthTokenMapper;
 import org.jeecg.modules.ctop.mapper.CTopOauthTokenMapper;
+import org.jeecg.modules.ctop.service.IBindAccountService;
 import org.jeecg.modules.kuaishou.service.IKuaishouInterfaceService;
 import org.jeecg.modules.kuaishou.service.IKuaishouInterfaceService;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Controller;
 import org.springframework.stereotype.Controller;
@@ -28,6 +30,8 @@ public class CallbackController {
     private IKuaishouAccessTokenService kuaishouAccessTokenService;
     private IKuaishouAccessTokenService kuaishouAccessTokenService;
     @Autowired
     @Autowired
     private CTopOauthTokenMapper cTopOauthTokenMapper;
     private CTopOauthTokenMapper cTopOauthTokenMapper;
+    @Autowired
+    private IBindAccountService bindAccountService;
 
 
     @RequestMapping("/kuaishou")
     @RequestMapping("/kuaishou")
     @ResponseBody
     @ResponseBody
@@ -41,7 +45,11 @@ public class CallbackController {
             if (token != null) {
             if (token != null) {
                 CTopOauthToken topOauthToken = new CTopOauthToken();
                 CTopOauthToken topOauthToken = new CTopOauthToken();
                 Long accountId = token.getAccountId();
                 Long accountId = token.getAccountId();
-                topOauthToken.setAccountId(token.getAccountId());
+                Map<String, Object> deleteMap = new HashMap<>();
+                deleteMap.put("advertiser_id", state);
+                deleteMap.put("account_id", accountId);
+                cTopOauthTokenMapper.deleteByMap(deleteMap); //删除 广告主id下的相关授权信息
+                topOauthToken.setAccountId(accountId);
                 topOauthToken.setMediaId("2");
                 topOauthToken.setMediaId("2");
                 topOauthToken.setAdvertiserId(state);
                 topOauthToken.setAdvertiserId(state);
                 topOauthToken.setAccessToken(token.getAccessToken());
                 topOauthToken.setAccessToken(token.getAccessToken());
@@ -53,10 +61,8 @@ public class CallbackController {
                 long refreshTokenExpireIn = token.getRefreshTokenExpiresIn() * 1000L;
                 long refreshTokenExpireIn = token.getRefreshTokenExpiresIn() * 1000L;
                 Date refreshTokenExpireInDate = new Date(now + refreshTokenExpireIn);
                 Date refreshTokenExpireInDate = new Date(now + refreshTokenExpireIn);
                 topOauthToken.setRefreshTokenExpiresIn(refreshTokenExpireInDate);
                 topOauthToken.setRefreshTokenExpiresIn(refreshTokenExpireInDate);
-
-                Map<String, Object> map = new HashMap<>();
-                map.put("account_id", accountId);
-
+                cTopOauthTokenMapper.insert(topOauthToken);
+                bindAccountService.addBindAccount(accountId, KuaishouInterfaceConstant.TYPE_AUTHORIZATION, state, KuaishouInterfaceConstant.LOGIN_TYPE_KUAISHOU); //账号绑定
             }
             }
             return "auth_success";
             return "auth_success";
         }
         }

+ 88 - 0
jeecg-boot-module-system/src/main/java/org/jeecg/modules/ctop/entity/BindAccount.java

@@ -0,0 +1,88 @@
+package org.jeecg.modules.ctop.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.fasterxml.jackson.annotation.JsonFormat;
+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 org.springframework.format.annotation.DateTimeFormat;
+
+import java.util.Date;
+
+/**
+ * @Description: 账户绑定
+ * @Author: jeecg-boot
+ * @Date: 2019-07-30
+ * @Version: V1.0
+ */
+@Data
+@TableName("ctop_bind_account")
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+@ApiModel(value = "ctop_bind_account对象", description = "账户绑定")
+public class BindAccount {
+
+    /**
+     * 主键ID
+     */
+    @TableId(type = IdType.AUTO)
+    @ApiModelProperty(value = "主键ID")
+    private Long id;
+    /**
+     * 广告id
+     */
+    @Excel(name = "广告id", width = 15)
+    @ApiModelProperty(value = "广告id")
+    private String advertiserId;
+    /**
+     * 账号
+     */
+    @Excel(name = "账号", width = 15)
+    @ApiModelProperty(value = "账号")
+    private String accountName;
+    /**
+     * 密码
+     */
+    @Excel(name = "密码", width = 15)
+    @ApiModelProperty(value = "密码")
+    private String password;
+    /**
+     * 登录/授权方式
+     */
+    @Excel(name = "登录/授权方式", width = 15)
+    @ApiModelProperty(value = "登录/授权方式")
+    private String loginType;
+    /**
+     * 方式:登录或授权
+     */
+    @Excel(name = "方式:登录或授权", width = 15)
+    @ApiModelProperty(value = "方式:登录或授权")
+    private String type;
+    /**
+     * 回调返回广告主id
+     */
+    @Excel(name = "回调返回广告主id", width = 15)
+    @ApiModelProperty(value = "回调返回广告主id")
+    private Long accountId;
+    /**
+     * 创建时间
+     */
+    @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;
+    /**
+     * 修改时间
+     */
+    @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 updateTime;
+}

+ 260 - 1
jeecg-boot-module-system/src/main/java/org/jeecg/modules/ctop/entity/ByteDanceAdvertisePlan.java

@@ -424,8 +424,267 @@ public class ByteDanceAdvertisePlan {
         }
         }
     }
     }
 
 
-    public ByteDanceAdvertisePlan() {
+    public ByteDanceAdvertisePlan(JSONObject dataObject, String accountId, Long adId, JSONObject params) {
+        this.id = adId;
+        this.advertiserId = accountId;
+        String name = params.getString("name");
+        if (null != name && !"".equals(name.trim())) {
+            this.name = name;
+        }
+
+        Long advertiserId = params.getLong("advertiser_id");
+        if (null != advertiserId) {
+            this.toutiaoId = advertiserId;
+        }
+        Long campaignId = params.getLong("campaign_id");
+        if (null != campaignId) {
+            this.campaignId = campaignId;
+        }
+
+        String budget_mode = params.getString("budget_mode");
+        if (null != budget_mode && !"".equals(budget_mode.trim())) {
+            this.budgetMode = budget_mode;
+        }
+
+        String open_url = params.getString("open_url");
+        if (null != open_url && !"".equals(open_url.trim())) {
+            this.openUrl = open_url;
+        }
+
+        String ad_create_time = params.getString("ad_create_time");
+        if (null != ad_create_time && !"".equals(ad_create_time.trim())) {
+            this.adCreateTime = ad_create_time;
+        }
+
+        String ad_modify_time = params.getString("ad_modify_time");
+        if (null != ad_modify_time && !"".equals(ad_modify_time.trim())) {
+            this.adModifyTime = ad_modify_time;
+        }
+
+        String audit_reject_reason = params.getString("audit_reject_reason");
+        if (null != audit_reject_reason && !"".equals(audit_reject_reason.trim())) {
+            this.auditRejectReason = audit_reject_reason;
+        }
+
+//        String dpa_open_url_field = dataObject.getString("dpa_open_url_field");
+//        if (null!=dpa_open_url_field&&!"".equals(dpa_open_url_field.trim())){
+//            this.dpa =dpa_open_url_field;
+//        }
+
+//        String external_url_params = dataObject.getString("external_url_params");
+//        if (null!=external_url_params&&!"".equals(external_url_params.trim())){
+//            this.externalUrlParams =external_url_params;
+//        }
+
+        String pricing = params.getString("pricing");
+        if (null != pricing && !"".equals(pricing.trim())) {
+            this.pricing = pricing;
+        }
+
+//        String dpa_open_url_type = dataObject.getString("dpa_open_url_type");
+//        if (null!=dpa_open_url_type&&!"".equals(dpa_open_url_type.trim())){
+//            this.dpaOpenUrlType =dpa_open_url_type;
+//        }
+
+//        String dpa_categories = dataObject.getString("dpa_categories");
+//        if (null!=dpa_categories&&!"".equals(dpa_categories.trim())){
+//            this.dpaCategories =dpa_categories;
+//        }
+
+        Integer hide_if_exists = params.getInteger("hide_if_exists");
+        if (null != hide_if_exists) {
+            this.hideIfExists = hide_if_exists;
+        }
+
+//        String open_url_params = dataObject.getString("open_url_params");
+//        if (null!=open_url_params&&!"".equals(open_url_params.trim())){
+//            this.openUrlParams =open_url_params;
+//        }
+
+//        String dpa_open_urls = dataObject.getString("dpa_open_urls");
+//        if (null!=dpa_open_urls&&!"".equals(dpa_open_urls.trim())){
+//            this.dpaOpenUrls =dpa_open_urls;
+//        }
+
+//        String deep_cpabid = dataObject.getString("deep_cpabid");
+//        if (null!=deep_cpabid&&!"".equals(deep_cpabid.trim())){
+//            this.deepCpaaid =deep_cpabid;
+//        }
+
+        String app_type = params.getString("app_type");
+        if (null != app_type && !"".equals(app_type.trim())) {
+            this.appType = app_type;
+        }
+
+        String flow_control_mode = params.getString("flow_control_mode");
+        if (null != flow_control_mode && !"".equals(flow_control_mode.trim())) {
+            this.flowControlMode = flow_control_mode;
+        }
+
+//        String union_video_type = dataObject.getString("union_video_type");
+//        if (null!=union_video_type&&!"".equals(union_video_type.trim())){
+//            this.unionVideoType =union_video_type;
+//        }
+
+//        String download_url = dataObject.getString("download_url");
+//        if (null!=download_url&&!"".equals(download_url.trim())){
+//            this.downloadUrl =download_url;
+//        }
+
+        BigDecimal cpa_bid = params.getBigDecimal("cpa_bid");
+        if (null != cpa_bid) {
+            this.cpaBid = cpa_bid;
+        }
+
+//        String dpa_products = dataObject.getString("dpa_products");
+//        if (null!=dpa_products&&!"".equals(dpa_products.trim())){
+//            this.dpaProducts =dpa_products;
+//        }
+
+//        String category_type = dataObject.getString("category_type");
+//        if (null!=category_type&&!"".equals(category_type.trim())){
+//            this.categoryType =category_type;
+//        }
+
+//        String dpa_external_url_field = dataObject.getString("dpa_external_url_field");
+//        if (null!=dpa_external_url_field&&!"".equals(dpa_external_url_field.trim())){
+//            this.dpaExternalUrlField =dpa_external_url_field;
+//        }
+
+//        String smart_bid_type = dataObject.getString("smart_bid_type");
+//        if (null!=smart_bid_type&&!"".equals(smart_bid_type.trim())){
+//            this.smartBidType =smart_bid_type;
+//        }
+
+//        String dpa_external_urls = dataObject.getString("dpa_external_urls");
+//        if (null!=dpa_external_urls&&!"".equals(dpa_external_urls.trim())){
+//            this.dpaExternalUrls =dpa_external_urls;
+//        }
+
+        String start_time = params.getString("start_time");
+        if (null != start_time && !"".equals(start_time.trim())) {
+            this.startTime = start_time;
+        }
+
+        String opt_status = params.getString("opt_status");
+        if (null != opt_status && !"".equals(opt_status.trim())) {
+            this.optStatus = opt_status;
+        }
+
+        String end_time = params.getString("end_time");
+        if (null != end_time && !"".equals(end_time.trim())) {
+            this.endTime = end_time;
+        }
+
+        String status = params.getString("status");
+        if (null != status && !"".equals(status.trim())) {
+            this.toutiaoStatus = status;
+        }
+
+//        String dpa_product_target = dataObject.getString("dpa_product_target");
+//        if (null!=dpa_product_target&&!"".equals(dpa_product_target.trim())){
+//            this.dpaProductTarget =dpa_product_target;
+//        }
+
+//        Long ad_id = dataObject.getLong("ad_id");
+//        if (null!=ad_id){
+//            this.openUrl =open_url;
+//        }
+
+        Long convert_id = params.getLong("convert_id");
+        if (null != convert_id) {
+            this.convertId = convert_id;
+        }
+
+//        String adjust_cpa = dataObject.getString("adjust_cpa");
+//        if (null!=adjust_cpa&&!"".equals(adjust_cpa.trim())){
+//            this.adjustCpa =adjust_cpa;
+//        }
+
+        BigDecimal bid = params.getBigDecimal("bid");
+        if (null != bid) {
+            this.bid = bid;
+        }
+
+//        Long advertiser_id = dataObject.getLong("advertiser_id");
+//        if (null!=advertiser_id){
+//            this.asdasd =open_url;
+//        }
+
+//        String deep_bid_type = dataObject.getString("deep_bid_type");
+//        if (null!=deep_bid_type&&!"".equals(deep_bid_type.trim())){
+//            this.deepBidType =deep_bid_type;
+//        }
+//
+//        String dpa_adtype = dataObject.getString("dpa_adtype");
+//        if (null!=dpa_adtype&&!"".equals(dpa_adtype.trim())){
+//            this.dpaAdtype =dpa_adtype;
+//        }
 
 
+//        String external_actions = dataObject.getString("external_actions");
+//        if (null!=external_actions&&!"".equals(external_actions.trim())){
+//            this.externalActions =external_actions;
+//        }
+
+        String hide_if_converted = params.getString("hide_if_converted");
+        if (null != hide_if_converted && !"".equals(hide_if_converted.trim())) {
+            this.hideIfConverted = hide_if_converted;
+        }
+
+        String toutiaoPackage = params.getString("package");
+        if (null != toutiaoPackage && !"".equals(toutiaoPackage.trim())) {
+            this.toutiaoPackage = toutiaoPackage;
+        }
+
+        String delivery_range = params.getString("delivery_range");
+        if (null != delivery_range && !"".equals(delivery_range.trim())) {
+            this.deliveryRange = delivery_range;
+        }
+
+//        String params_type = dataObject.getString("params_type");
+//        if (null!=params_type&&!"".equals(params_type.trim())){
+//            this.paramsType =params_type;
+//        }
+
+        BigDecimal budget = params.getBigDecimal("budget");
+        if (null != budget) {
+            this.budget = budget;
+        }
+
+        String schedule_type = params.getString("schedule_type");
+        if (null != schedule_type && !"".equals(schedule_type.trim())) {
+            this.scheduleType = schedule_type;
+        }
+
+        String schedule_time = params.getString("schedule_time");
+        if (null != schedule_time && !"".equals(schedule_time.trim())) {
+            this.scheduleTime = schedule_time;
+        }
+//
+//        String modify_time = dataObject.getString("modify_time");
+//        if (null!=modify_time&&!"".equals(modify_time.trim())){
+//            this.modifyTime =modify_time;
+//        }
+//
+//        String advertiser_store_ids = dataObject.getString("advertiser_store_ids");
+//        if (null!=advertiser_store_ids&&!"".equals(advertiser_store_ids.trim())){
+//            this.advertiserStoreIds =advertiser_store_ids;
+//        }
+
+//        String product_platform_id = dataObject.getString("product_platform_id");
+//        if (null!=product_platform_id&&!"".equals(product_platform_id.trim())){
+//            this.productPlatformId =product_platform_id;
+//        }
+
+        String download_type = params.getString("download_type");
+        if (null != download_type && !"".equals(download_type.trim())) {
+            this.downloadType = download_type;
+        }
+
+        String external_url = params.getString("external_url");
+        if (null != external_url && !"".equals(external_url.trim())) {
+            this.externalUrl = external_url;
+        }
     }
     }
 
 
 
 

+ 20 - 4
jeecg-boot-module-system/src/main/java/org/jeecg/modules/ctop/entity/ByteDanceCampaign.java

@@ -32,7 +32,7 @@ import org.jeecgframework.poi.excel.annotation.Excel;
 public class ByteDanceCampaign {
 public class ByteDanceCampaign {
     
     
 	/**今日头条广告组id*/
 	/**今日头条广告组id*/
-    @TableId(type = IdType.AUTO)
+	@TableId
     @ApiModelProperty(value = "今日头条广告组id")
     @ApiModelProperty(value = "今日头条广告组id")
 	private Long id;
 	private Long id;
 	/**平台用户id*/
 	/**平台用户id*/
@@ -43,6 +43,12 @@ public class ByteDanceCampaign {
 	@Excel(name = "头条账号id", width = 15)
 	@Excel(name = "头条账号id", width = 15)
     @ApiModelProperty(value = "头条账号id")
     @ApiModelProperty(value = "头条账号id")
 	private Long toutiaoId;
 	private Long toutiaoId;
+	/**
+	 * 头条账号id
+	 */
+	@Excel(name = "模板id", width = 15)
+	@ApiModelProperty(value = "模板id")
+	private Long templateId;
 	/**广告组名称*/
 	/**广告组名称*/
 	@Excel(name = "广告组名称", width = 15)
 	@Excel(name = "广告组名称", width = 15)
     @ApiModelProperty(value = "广告组名称")
     @ApiModelProperty(value = "广告组名称")
@@ -82,10 +88,10 @@ public class ByteDanceCampaign {
 	private java.lang.String campaignModifyTime;
 	private java.lang.String campaignModifyTime;
 	/**createTime*/
 	/**createTime*/
     @ApiModelProperty(value = "createTime")
     @ApiModelProperty(value = "createTime")
-	private java.util.Date createTime;
+	private Date createTime;
 	/**updateTime*/
 	/**updateTime*/
     @ApiModelProperty(value = "updateTime")
     @ApiModelProperty(value = "updateTime")
-	private java.util.Date updateTime;
+	private Date updateTime;
 
 
     public ByteDanceCampaign() {
     public ByteDanceCampaign() {
     }
     }
@@ -153,7 +159,7 @@ public class ByteDanceCampaign {
         }
         }
     }
     }
 
 
-    public ByteDanceCampaign(Long id, CTopOauthToken oauthToken, String campaignName, String budgetMode, Integer budget, String landingType) {
+	public ByteDanceCampaign(Long id, CTopOauthToken oauthToken, String campaignName, String budgetMode, Integer budget, String landingType) {
 		this.id = id;
 		this.id = id;
 		this.advertiserId = oauthToken.getAdvertiserId();
 		this.advertiserId = oauthToken.getAdvertiserId();
 		this.name = campaignName;
 		this.name = campaignName;
@@ -162,4 +168,14 @@ public class ByteDanceCampaign {
 		this.landingType = landingType;
 		this.landingType = landingType;
 		this.toutiaoId = oauthToken.getAccountId();
 		this.toutiaoId = oauthToken.getAccountId();
 	}
 	}
+
+	public ByteDanceCampaign(Long id, CTopOauthToken token, ByteDanceCampaignTemplate template) {
+		this.id = id;
+		this.advertiserId = token.getAdvertiserId();
+		this.name = template.getCampaignName();
+		this.budgetMode = template.getCampaignBudget();
+		this.budget = new BigDecimal(template.getBudgetDaily());
+		this.landingType = template.getPromotionPurpuse();
+		this.toutiaoId = token.getAccountId();
+	}
 }
 }

+ 125 - 0
jeecg-boot-module-system/src/main/java/org/jeecg/modules/ctop/entity/ByteDanceImageInfo.java

@@ -0,0 +1,125 @@
+package org.jeecg.modules.ctop.entity;
+
+import java.io.Serializable;
+import java.util.Date;
+
+import com.alibaba.fastjson.JSONObject;
+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;
+
+/**
+ * @Description: 头条图片素材信息
+ * @Author: jeecg-boot
+ * @Date: 2019-07-29
+ * @Version: V1.0
+ */
+@Data
+@TableName("ctop_bytedance_image_info")
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+@ApiModel(value = "ctop_bytedance_image_info对象", description = "头条图片素材信息")
+public class ByteDanceImageInfo {
+
+    /**
+     * id
+     */
+    @TableId
+    @ApiModelProperty(value = "id")
+    private String id;
+    /**
+     * 文件id
+     */
+    @Excel(name = "文件id", width = 15)
+    @ApiModelProperty(value = "文件id")
+    private Long fileId;
+    /**
+     * 头条平台账号id
+     */
+    @Excel(name = "头条平台账号id", width = 15)
+    @ApiModelProperty(value = "头条平台账号id")
+    private Long accountId;
+    @Excel(name = "平台账号id", width = 15)
+    @ApiModelProperty(value = "平台账号id")
+    private String advertiserId;
+
+    /**
+     * 图片大小
+     */
+    @Excel(name = "图片大小", width = 15)
+    @ApiModelProperty(value = "图片大小")
+    private Long size;
+    /**
+     * 图片宽度
+     */
+    @Excel(name = "图片宽度", width = 15)
+    @ApiModelProperty(value = "图片宽度")
+    private Integer width;
+    /**
+     * 图片高度
+     */
+    @Excel(name = "图片高度", width = 15)
+    @ApiModelProperty(value = "图片高度")
+    private Integer height;
+    /**
+     * 预览地址
+     */
+    @Excel(name = "预览地址", width = 15)
+    @ApiModelProperty(value = "预览地址")
+    private String url;
+    /**
+     * 图片格式
+     */
+    @Excel(name = "图片格式", width = 15)
+    @ApiModelProperty(value = "图片格式")
+    private String format;
+    /**
+     * 图片Md5
+     */
+    @Excel(name = "图片Md5", width = 15)
+    @ApiModelProperty(value = "图片Md5")
+    private String signature;
+    /**
+     * status
+     */
+    @Excel(name = "status", width = 15)
+    @ApiModelProperty(value = "status")
+    private Integer status;
+    /**
+     * createTime
+     */
+    @ApiModelProperty(value = "createTime")
+    private Date createTime;
+    /**
+     * updateTime
+     */
+    @ApiModelProperty(value = "updateTime")
+    private Date updateTime;
+
+    public ByteDanceImageInfo(JSONObject data, CTopOauthToken token, Long imageFileId) {
+        this.id = data.getString("video_id");
+        this.fileId = imageFileId;
+        this.accountId = token.getAccountId();
+        this.advertiserId = token.getAdvertiserId();
+        this.width = data.getInteger("width");
+        this.height = data.getInteger("width");
+        this.size = data.getLong("size");
+        this.url = data.getString("url");
+        this.format = data.getString("format");
+        this.signature = data.getString("signature");
+        this.status = 1;
+    }
+
+    public ByteDanceImageInfo() {
+
+    }
+}

+ 119 - 0
jeecg-boot-module-system/src/main/java/org/jeecg/modules/ctop/entity/ByteDanceVideoInfo.java

@@ -0,0 +1,119 @@
+package org.jeecg.modules.ctop.entity;
+
+import java.io.Serializable;
+import java.util.Date;
+
+import com.alibaba.fastjson.JSONObject;
+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;
+
+/**
+ * @Description: 今日头条视频素材信息
+ * @Author: jeecg-boot
+ * @Date: 2019-07-29
+ * @Version: V1.0
+ */
+@Data
+@TableName("ctop_bytedance_video_info")
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+@ApiModel(value = "ctop_bytedance_video_info对象", description = "今日头条视频素材信息")
+public class ByteDanceVideoInfo {
+
+    /**
+     * id
+     */
+    @TableId()
+    @ApiModelProperty(value = "id")
+    private String id;
+    /**
+     * 对应本文件id
+     */
+    @Excel(name = "对应本文件id", width = 15)
+    @ApiModelProperty(value = "对应本文件id")
+    private Long fileId;
+    /**
+     * 平台账号id
+     */
+    @Excel(name = "平台账号id", width = 15)
+    @ApiModelProperty(value = "平台账号id")
+    private String advertiserId;
+    /**
+     * 对应本文件id
+     */
+    @Excel(name = "头条账号id", width = 15)
+    @ApiModelProperty(value = "头条账号id")
+    private Long accountId;
+    /**
+     * 视频宽度
+     */
+    @Excel(name = "视频宽度", width = 15)
+    @ApiModelProperty(value = "视频宽度")
+    private Integer width;
+    /**
+     * 视频高度
+     */
+    @Excel(name = "视频高度", width = 15)
+    @ApiModelProperty(value = "视频高度")
+    private Integer height;
+    /**
+     * 视频时长
+     */
+    @Excel(name = "视频时长", width = 15)
+    @ApiModelProperty(value = "视频时长")
+    private Double duration;
+    /**
+     * 视频大小
+     */
+    @Excel(name = "视频大小", width = 15)
+    @ApiModelProperty(value = "视频大小")
+    private Long size;
+    /**
+     * 视频地址
+     */
+    @Excel(name = "视频地址", width = 15)
+    @ApiModelProperty(value = "视频地址")
+    private String videoUrl;
+    /**
+     * status
+     */
+    @Excel(name = "status", width = 15)
+    @ApiModelProperty(value = "status")
+    private Integer status;
+    /**
+     * createTime
+     */
+    @ApiModelProperty(value = "createTime")
+    private Date createTime;
+    /**
+     * updateTime
+     */
+    @ApiModelProperty(value = "updateTime")
+    private Date updateTime;
+
+    public ByteDanceVideoInfo(JSONObject data, CTopOauthToken token, Long fileId) {
+        this.id = data.getString("video_id");
+        this.fileId = fileId;
+        this.accountId = token.getAccountId();
+        this.advertiserId = token.getAdvertiserId();
+        this.width = data.getInteger("width");
+        this.height = data.getInteger("width");
+        this.size = data.getLong("size");
+        this.duration = data.getDouble("duration");
+        this.videoUrl = data.getString("video_url");
+        this.status = 1;
+    }
+
+    public ByteDanceVideoInfo() {
+    }
+}

+ 6 - 22
jeecg-boot-module-system/src/main/java/org/jeecg/modules/ctop/entity/BytedanceAdvertisePlanTemplate.java

@@ -77,30 +77,14 @@ public class BytedanceAdvertisePlanTemplate {
     @Excel(name = "投放目标模板id", width = 15)
     @Excel(name = "投放目标模板id", width = 15)
     @ApiModelProperty(value = "投放目标模板id")
     @ApiModelProperty(value = "投放目标模板id")
     private Integer deliveryTargetTemplateId;
     private Integer deliveryTargetTemplateId;
+
     /**
     /**
-     * 指定视频id
-     */
-    @Excel(name = "指定视频id", width = 15)
-    @ApiModelProperty(value = "指定视频id")
-    private Integer videoId;
-    /**
-     * 指定封面图id
-     */
-    @Excel(name = "指定封面图id", width = 15)
-    @ApiModelProperty(value = "指定封面图id")
-    private Integer imageId;
-    /**
-     * 创意文案信息
-     */
-    @Excel(name = "创意文案信息", width = 15)
-    @ApiModelProperty(value = "创意文案信息")
-    private String creativeText;
-    /**
-     * 迭代数量
+     * 模板状态
      */
      */
-    @Excel(name = "迭代数量", width = 15)
-    @ApiModelProperty(value = "迭代数量")
-    private Integer iteratorNum;
+    @Excel(name = "模板状态", width = 15)
+    @ApiModelProperty(value = "模板状态")
+    private Integer status;
+
     /**
     /**
      * createTime
      * createTime
      */
      */

+ 17 - 3
jeecg-boot-module-system/src/main/java/org/jeecg/modules/ctop/entity/CTopOauthToken.java

@@ -101,9 +101,8 @@ public class CTopOauthToken {
     public CTopOauthToken(String accountId, JSONObject data) {
     public CTopOauthToken(String accountId, JSONObject data) {
         this.advertiserId = accountId;
         this.advertiserId = accountId;
         this.mediaId = "toutiao";
         this.mediaId = "toutiao";
-        Long advertiserId = data.getLong("advertiser_id");
-        this.accountId = advertiserId;
-        String advertiserName = data.getString("advertiser_name");
+        this.accountId = data.getLong("advertiser_id");
+        ;
         String accessToken = data.getString("access_token");
         String accessToken = data.getString("access_token");
         Integer refreshTokenExpiresIn = data.getInteger("refresh_token_expires_in");
         Integer refreshTokenExpiresIn = data.getInteger("refresh_token_expires_in");
         Integer expiresIn = data.getInteger("expires_in");
         Integer expiresIn = data.getInteger("expires_in");
@@ -117,4 +116,19 @@ public class CTopOauthToken {
 
 
     public CTopOauthToken() {
     public CTopOauthToken() {
     }
     }
+
+    public CTopOauthToken(CTopOauthToken token, JSONObject data) {
+        this.advertiserId = token.getAdvertiserId();
+        this.mediaId = "toutiao";
+        this.accountId = token.getAccountId();
+        String accessToken = data.getString("access_token");
+        Integer refreshTokenExpiresIn = data.getInteger("refresh_token_expires_in");
+        Integer expiresIn = data.getInteger("expires_in");
+        String refreshToken = data.getString("refresh_token");
+        this.accessToken = accessToken;
+        this.refreshToken = refreshToken;
+        Date now = new Date();
+        this.accessTokenExpiresIn = DateUtils.addSecond(now, expiresIn);
+        this.refreshTokenExpiresIn = DateUtils.addSecond(now, refreshTokenExpiresIn);
+    }
 }
 }

+ 14 - 0
jeecg-boot-module-system/src/main/java/org/jeecg/modules/ctop/entity/FileInfo.java

@@ -74,4 +74,18 @@ public class FileInfo {
      */
      */
     @ApiModelProperty(value = "updateTime")
     @ApiModelProperty(value = "updateTime")
     private Date updateTime;
     private Date updateTime;
+
+    @Override
+    public String toString() {
+        return "FileInfo{" +
+                "id=" + id +
+                ", fileName='" + fileName + '\'' +
+                ", type='" + type + '\'' +
+                ", platformType='" + platformType + '\'' +
+                ", path='" + path + '\'' +
+                ", fileUrl='" + fileUrl + '\'' +
+                ", createTime=" + createTime +
+                ", updateTime=" + updateTime +
+                '}';
+    }
 }
 }

+ 14 - 0
jeecg-boot-module-system/src/main/java/org/jeecg/modules/ctop/mapper/BindAccountMapper.java

@@ -0,0 +1,14 @@
+package org.jeecg.modules.ctop.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.jeecg.modules.ctop.entity.BindAccount;
+
+/**
+ * @Description: 账户绑定
+ * @Author: jeecg-boot
+ * @Date: 2019-07-30
+ * @Version: V1.0
+ */
+public interface BindAccountMapper extends BaseMapper<BindAccount> {
+
+}

+ 17 - 0
jeecg-boot-module-system/src/main/java/org/jeecg/modules/ctop/mapper/ByteDanceImageInfoMapper.java

@@ -0,0 +1,17 @@
+package org.jeecg.modules.ctop.mapper;
+
+import java.util.List;
+
+import org.apache.ibatis.annotations.Param;
+import org.jeecg.modules.ctop.entity.ByteDanceImageInfo;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+/**
+ * @Description: 头条图片素材信息
+ * @Author: jeecg-boot
+ * @Date: 2019-07-29
+ * @Version: V1.0
+ */
+public interface ByteDanceImageInfoMapper extends BaseMapper<ByteDanceImageInfo> {
+
+}

+ 17 - 0
jeecg-boot-module-system/src/main/java/org/jeecg/modules/ctop/mapper/ByteDanceVideoInfoMapper.java

@@ -0,0 +1,17 @@
+package org.jeecg.modules.ctop.mapper;
+
+import java.util.List;
+
+import org.apache.ibatis.annotations.Param;
+import org.jeecg.modules.ctop.entity.ByteDanceVideoInfo;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+/**
+ * @Description: 今日头条视频素材信息
+ * @Author: jeecg-boot
+ * @Date: 2019-07-29
+ * @Version: V1.0
+ */
+public interface ByteDanceVideoInfoMapper extends BaseMapper<ByteDanceVideoInfo> {
+
+}

+ 5 - 0
jeecg-boot-module-system/src/main/java/org/jeecg/modules/ctop/mapper/xml/BindAccountMapper.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.ctop.mapper.BindAccountMapper">
+
+</mapper>

+ 5 - 0
jeecg-boot-module-system/src/main/java/org/jeecg/modules/ctop/mapper/xml/ByteDanceImageInfoMapper.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.ctop.mapper.ByteDanceImageInfoMapper">
+
+</mapper>

+ 5 - 0
jeecg-boot-module-system/src/main/java/org/jeecg/modules/ctop/mapper/xml/ByteDanceVideoInfoMapper.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.ctop.mapper.ByteDanceVideoInfoMapper">
+
+</mapper>

+ 25 - 0
jeecg-boot-module-system/src/main/java/org/jeecg/modules/ctop/service/IBindAccountService.java

@@ -0,0 +1,25 @@
+package org.jeecg.modules.ctop.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import org.jeecg.modules.ctop.entity.BindAccount;
+
+import java.io.UnsupportedEncodingException;
+
+/**
+ * @Description: 账户绑定
+ * @Author: jeecg-boot
+ * @Date: 2019-07-30
+ * @Version: V1.0
+ */
+public interface IBindAccountService extends IService<BindAccount> {
+    boolean bindLogin(String advertiserId, String accountName, String password, String loginType);
+
+    String bindAuthorization(String advertiserId, String authorizationType) throws UnsupportedEncodingException;
+
+    String getKuaishouCodeUrl(String state) throws UnsupportedEncodingException;
+
+    String getByteDanceCodeUrl(String state) throws UnsupportedEncodingException;
+
+
+    void addBindAccount(Long accountId, String type, String state, String loginType);
+}

+ 3 - 0
jeecg-boot-module-system/src/main/java/org/jeecg/modules/ctop/service/IByteDanceAdvertisePlanService.java

@@ -3,6 +3,8 @@ package org.jeecg.modules.ctop.service;
 import org.jeecg.modules.ctop.entity.ByteDanceAdvertisePlan;
 import org.jeecg.modules.ctop.entity.ByteDanceAdvertisePlan;
 import com.baomidou.mybatisplus.extension.service.IService;
 import com.baomidou.mybatisplus.extension.service.IService;
 
 
+import java.util.Map;
+
 /**
 /**
  * @Description: 今日头条广告计划信息
  * @Description: 今日头条广告计划信息
  * @Author: jeecg-boot
  * @Author: jeecg-boot
@@ -11,4 +13,5 @@ import com.baomidou.mybatisplus.extension.service.IService;
  */
  */
 public interface IByteDanceAdvertisePlanService extends IService<ByteDanceAdvertisePlan> {
 public interface IByteDanceAdvertisePlanService extends IService<ByteDanceAdvertisePlan> {
 
 
+    Map<String, Object> advertiserPlanCreate(String accountId, Long campaignId, String dataString);
 }
 }

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

@@ -1,5 +1,8 @@
 package org.jeecg.modules.ctop.service;
 package org.jeecg.modules.ctop.service;
 
 
+import org.jeecg.modules.ctop.entity.ByteDanceCampaignTemplate;
+import org.jeecg.modules.ctop.entity.CTopOauthToken;
+
 import java.util.Map;
 import java.util.Map;
 
 
 public interface IByteDanceAdvertiserDataService {
 public interface IByteDanceAdvertiserDataService {
@@ -30,4 +33,6 @@ public interface IByteDanceAdvertiserDataService {
     Map<String, Object> advertiserCreativeUpdateStatus(String accountId, String ids, String optStatus);
     Map<String, Object> advertiserCreativeUpdateStatus(String accountId, String ids, String optStatus);
 
 
     Map<String, Object> advertiserCustomAudienceSelect(String accountId);
     Map<String, Object> advertiserCustomAudienceSelect(String accountId);
+
+    Map<String, Object> campaignCreate(CTopOauthToken token, ByteDanceCampaignTemplate template);
 }
 }

+ 3 - 0
jeecg-boot-module-system/src/main/java/org/jeecg/modules/ctop/service/IByteDanceCreativeService.java

@@ -3,6 +3,8 @@ package org.jeecg.modules.ctop.service;
 import org.jeecg.modules.ctop.entity.ByteDanceCreative;
 import org.jeecg.modules.ctop.entity.ByteDanceCreative;
 import com.baomidou.mybatisplus.extension.service.IService;
 import com.baomidou.mybatisplus.extension.service.IService;
 
 
+import java.util.Map;
+
 /**
 /**
  * @Description: 今日头条创意信息
  * @Description: 今日头条创意信息
  * @Author: jeecg-boot
  * @Author: jeecg-boot
@@ -11,4 +13,5 @@ import com.baomidou.mybatisplus.extension.service.IService;
  */
  */
 public interface IByteDanceCreativeService extends IService<ByteDanceCreative> {
 public interface IByteDanceCreativeService extends IService<ByteDanceCreative> {
 
 
+    Map<String, Object> creativeCreate(String accountId, Long campaignId, String dataString);
 }
 }

+ 14 - 0
jeecg-boot-module-system/src/main/java/org/jeecg/modules/ctop/service/IByteDanceImageInfoService.java

@@ -0,0 +1,14 @@
+package org.jeecg.modules.ctop.service;
+
+import org.jeecg.modules.ctop.entity.ByteDanceImageInfo;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+/**
+ * @Description: 头条图片素材信息
+ * @Author: jeecg-boot
+ * @Date: 2019-07-29
+ * @Version: V1.0
+ */
+public interface IByteDanceImageInfoService extends IService<ByteDanceImageInfo> {
+
+}

+ 14 - 0
jeecg-boot-module-system/src/main/java/org/jeecg/modules/ctop/service/IByteDanceVideoInfoService.java

@@ -0,0 +1,14 @@
+package org.jeecg.modules.ctop.service;
+
+import org.jeecg.modules.ctop.entity.ByteDanceVideoInfo;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+/**
+ * @Description: 今日头条视频素材信息
+ * @Author: jeecg-boot
+ * @Date: 2019-07-29
+ * @Version: V1.0
+ */
+public interface IByteDanceVideoInfoService extends IService<ByteDanceVideoInfo> {
+
+}

+ 7 - 0
jeecg-boot-module-system/src/main/java/org/jeecg/modules/ctop/service/IFileInfoService.java

@@ -3,6 +3,8 @@ package org.jeecg.modules.ctop.service;
 import org.jeecg.modules.ctop.entity.FileInfo;
 import org.jeecg.modules.ctop.entity.FileInfo;
 import com.baomidou.mybatisplus.extension.service.IService;
 import com.baomidou.mybatisplus.extension.service.IService;
 
 
+import java.util.Map;
+
 /**
 /**
  * @Description: 文件信息
  * @Description: 文件信息
  * @Author: jeecg-boot
  * @Author: jeecg-boot
@@ -11,4 +13,9 @@ import com.baomidou.mybatisplus.extension.service.IService;
  */
  */
 public interface IFileInfoService extends IService<FileInfo> {
 public interface IFileInfoService extends IService<FileInfo> {
 
 
+    Map<String, Object> uploadVideoToTemplate(String accountId, Long videoFileId, String templatename);
+
+    Map<String, Object> uploadImageToTemplate(String accountId, Long imageFileId, String templatename);
+
+    Map<String, Object> getIndustryList(String accountId);
 }
 }

+ 140 - 0
jeecg-boot-module-system/src/main/java/org/jeecg/modules/ctop/service/impl/BindAccountServiceImpl.java

@@ -0,0 +1,140 @@
+package org.jeecg.modules.ctop.service.impl;
+
+import cn.com.ctop.common.utils.Check;
+import cn.com.ctop.common.utils.PropertiesUtils;
+import cn.com.ctop.toutiao.common.BytedanceInterfaceConstant;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import constant.KuaishouInterfaceConstant;
+import org.jeecg.modules.ctop.entity.BindAccount;
+import org.jeecg.modules.ctop.mapper.BindAccountMapper;
+import org.jeecg.modules.ctop.service.IBindAccountService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @Description: 账户绑定
+ * @Author: jeecg-boot
+ * @Date: 2019-07-30
+ * @Version: V1.0
+ */
+@Service
+public class BindAccountServiceImpl extends ServiceImpl<BindAccountMapper, BindAccount> implements IBindAccountService {
+    private static final Logger logger = LoggerFactory.getLogger(BindAccountServiceImpl.class);
+
+
+    @Autowired
+    BindAccountMapper bindAccountMapper;
+
+    @Override
+    public boolean bindLogin(String advertiserId, String accountName, String password, String loginType) {
+        Map<String, Object> requestMap = new HashMap<>();
+        requestMap.put("advertiser_id", advertiserId);
+        requestMap.put("account_name", accountName);
+        requestMap.put("login_type", loginType);
+        List<BindAccount> bindAccounts = bindAccountMapper.selectByMap(requestMap);
+        if (!Check.isNull(bindAccounts)) {
+            return false;
+        }
+        BindAccount bindAccount = new BindAccount();
+        bindAccount.setAdvertiserId(advertiserId);
+        bindAccount.setAccountName(accountName);
+        bindAccount.setPassword(password);
+        bindAccount.setType(KuaishouInterfaceConstant.TYPE_LOGIN);
+        bindAccount.setLoginType(loginType);
+        int i = bindAccountMapper.insert(bindAccount);
+        if (i > 0) {
+            logger.info("登录账号绑定成功,广告主id:{}", bindAccount.getAdvertiserId());
+            return true;
+        }
+
+        return false;
+    }
+
+    /**
+     * 授权
+     *
+     * @param advertiserId
+     * @param authorizationType
+     * @return
+     */
+    @Override
+    public String bindAuthorization(String advertiserId, String authorizationType) throws UnsupportedEncodingException {
+        BindAccount bindAccount = new BindAccount();
+        bindAccount.setAdvertiserId(advertiserId);
+
+        bindAccount.setType("login");
+        bindAccount.setType("authorization");
+        bindAccount.setLoginType(authorizationType);
+
+        String codeUrl = "";
+        if ("kuaishou".equals(authorizationType)) {
+            codeUrl = getKuaishouCodeUrl(advertiserId);
+        }
+        if ("toutiao".equals(authorizationType)) {
+            codeUrl = getByteDanceCodeUrl(advertiserId);
+        }
+        bindAccountMapper.insert(bindAccount);
+        return codeUrl;
+    }
+
+
+    /**
+     * 授权 绑定账号信息
+     *
+     * @param accountId
+     * @param type
+     * @param state
+     * @param loginType
+     */
+    @Override
+    public void addBindAccount(Long accountId, String type, String state, String loginType) {
+        Map<String, Object> deleteMap = new HashMap<>();
+        deleteMap.put("advertiser_id", state);
+        deleteMap.put("account_id", accountId);
+        deleteMap.put("type", type);
+        deleteMap.put("login_type", loginType);
+        bindAccountMapper.deleteByMap(deleteMap);
+        BindAccount bindAccount = new BindAccount();
+        bindAccount.setAccountId(accountId);
+        bindAccount.setLoginType(loginType);
+        bindAccount.setAdvertiserId(state);
+        bindAccount.setType(type);
+        int i = bindAccountMapper.insert(bindAccount);
+        if (i > 0) {
+            logger.info("授权账号绑定成功,本地id:{},accountId:{}", bindAccount.getAdvertiserId(), accountId);
+        }
+    }
+
+    @Override
+    public String getKuaishouCodeUrl(String state) throws UnsupportedEncodingException {
+        StringBuffer sb = new StringBuffer();
+        sb.append(PropertiesUtils.getValue("kuaishou_config", "kuaishou_auth_url"))
+                .append(KuaishouInterfaceConstant.AUTH_PATH)
+                .append("?app_id=" + PropertiesUtils.getValue("kuaishou_config", "kuaishou_appid"))
+                .append("&state=" + state)
+                .append("&scope=%5B%22report_service%22%2C%22ad_query%22%2C%22ad_manage%22%5D")
+                .append("&redirect_uri=" + URLEncoder.encode(PropertiesUtils.getValue("kuaishou_config", "kuaishou_callback_url"), "UTF-8"));
+        return sb.toString();
+    }
+
+
+    public String getByteDanceCodeUrl(String state) throws UnsupportedEncodingException {
+        StringBuffer sb = new StringBuffer();
+        sb.append(PropertiesUtils.getValue("bytedance_config", "bytedance_auth_url"))
+                .append(BytedanceInterfaceConstant.AUTH_PATH)
+                .append("?app_id=" + PropertiesUtils.getValue("bytedance_config", "bytedance_appid"))
+                .append("&state=" + state)
+                .append("&redirect_uri=" + URLEncoder.encode(PropertiesUtils.getValue("bytedance_config", "bytedance_callback_url"), "UTF-8"));
+        return sb.toString();
+    }
+
+
+}

+ 97 - 0
jeecg-boot-module-system/src/main/java/org/jeecg/modules/ctop/service/impl/ByteDanceAdvertisePlanServiceImpl.java

@@ -1,12 +1,33 @@
 package org.jeecg.modules.ctop.service.impl;
 package org.jeecg.modules.ctop.service.impl;
 
 
+import cn.com.ctop.common.utils.PropertiesUtils;
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import org.apache.http.client.ClientProtocolException;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.entity.ContentType;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClientBuilder;
 import org.jeecg.modules.ctop.entity.ByteDanceAdvertisePlan;
 import org.jeecg.modules.ctop.entity.ByteDanceAdvertisePlan;
+import org.jeecg.modules.ctop.entity.CTopOauthToken;
 import org.jeecg.modules.ctop.mapper.ByteDanceAdvertisePlanMapper;
 import org.jeecg.modules.ctop.mapper.ByteDanceAdvertisePlanMapper;
 import org.jeecg.modules.ctop.service.IByteDanceAdvertisePlanService;
 import org.jeecg.modules.ctop.service.IByteDanceAdvertisePlanService;
+import org.jeecg.modules.ctop.service.ICTopOauthTokenService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import org.springframework.stereotype.Service;
 
 
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 
 
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.HashMap;
+import java.util.Map;
+
 /**
 /**
  * @Description: 今日头条广告计划信息
  * @Description: 今日头条广告计划信息
  * @Author: jeecg-boot
  * @Author: jeecg-boot
@@ -15,5 +36,81 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
  */
  */
 @Service
 @Service
 public class ByteDanceAdvertisePlanServiceImpl extends ServiceImpl<ByteDanceAdvertisePlanMapper, ByteDanceAdvertisePlan> implements IByteDanceAdvertisePlanService {
 public class ByteDanceAdvertisePlanServiceImpl extends ServiceImpl<ByteDanceAdvertisePlanMapper, ByteDanceAdvertisePlan> implements IByteDanceAdvertisePlanService {
+    private static final Logger logger = LoggerFactory.getLogger(ByteDanceAdvertisePlanServiceImpl.class);
+
+    @Override
+    public Map<String, Object> advertiserPlanCreate(String accountId, Long campaignId, String dataString) {
+        Map<String, Object> resultMap = new HashMap<>();
+        //1:获取token
+        CTopOauthToken token = tokenService.getOAuthTokenByAccountId(accountId);
+        JSONObject data = JSONObject.parseObject(dataString);
+        data.put("advertiser_id", token.getAccountId());
+        data.put("campaign_id", campaignId);
+        JSONObject result = createAd(data, token.getAccessToken());
+        Integer code = result.getInteger("code");
+        String message = result.getString("message");
+        if (null == code || code != 0) {
+            logger.info("广告计划创建失败,accountId:{},message:{}", accountId, message);
+            resultMap.put("code", -1);
+            resultMap.put("message", "广告计划创建失败");
+            return resultMap;
+        }
+        JSONObject dataObject = result.getJSONObject("data");
+        Long adId = dataObject.getLong("ad_id");
+        System.out.println(adId);
+        System.out.println(dataObject.toJSONString());
+        ByteDanceAdvertisePlan plan = new ByteDanceAdvertisePlan(dataObject, accountId, adId, data);
+        planMapper.insert(plan);
+        resultMap.put("code", 0);
+        resultMap.put("message", "广告计划创建成功");
+        return resultMap;
+    }
+
+    @Autowired
+    private ByteDanceAdvertisePlanMapper planMapper;
+
+    public JSONObject createAd(JSONObject data, String token) {
+        // 请求地址
+        String url = PropertiesUtils.getValue("bytedance_config", "bytedance_api_url") + PropertiesUtils.getValue("bytedance_config", "bytedance_v2_ad_create");
+        // 构造请求
+        HttpPost httpEntity = new HttpPost(url);
+        httpEntity.setHeader("Access-Token", token);
+        CloseableHttpResponse response = null;
+        CloseableHttpClient client = null;
+
+        try {
+            client = HttpClientBuilder.create().build();
+            httpEntity.setEntity(new StringEntity(data.toJSONString(), ContentType.APPLICATION_JSON));
+
+            response = client.execute(httpEntity);
+            if (response != null && response.getStatusLine().getStatusCode() == 200) {
+                BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
+                StringBuffer result = new StringBuffer();
+                String line = "";
+                while ((line = bufferedReader.readLine()) != null) {
+                    result.append(line);
+                }
+                bufferedReader.close();
+                return JSONObject.parseObject(result.toString());
+            }
+
+        } catch (ClientProtocolException e) {
+            e.printStackTrace();
+        } catch (IOException e) {
+            e.printStackTrace();
+        } finally {
+            try {
+                if (response != null) {
+                    response.close();
+                }
+                client.close();
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+        }
+        return null;
+    }
 
 
+    @Autowired
+    private ICTopOauthTokenService tokenService;
 }
 }

+ 98 - 16
jeecg-boot-module-system/src/main/java/org/jeecg/modules/ctop/service/impl/ByteDanceAdvertiserDataServiceImpl.java

@@ -5,8 +5,13 @@ import cn.com.ctop.common.utils.PropertiesUtils;
 import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.JSONObject;
 import com.alibaba.fastjson.JSONObject;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
-import org.apache.shiro.SecurityUtils;
-import org.jeecg.common.system.vo.LoginUser;
+import org.apache.http.client.ClientProtocolException;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.entity.ContentType;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClientBuilder;
 import org.jeecg.modules.ctop.entity.*;
 import org.jeecg.modules.ctop.entity.*;
 import org.jeecg.modules.ctop.mapper.*;
 import org.jeecg.modules.ctop.mapper.*;
 import org.jeecg.modules.ctop.service.IByteDanceAdvertiserDataService;
 import org.jeecg.modules.ctop.service.IByteDanceAdvertiserDataService;
@@ -16,6 +21,9 @@ import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import org.springframework.stereotype.Service;
 
 
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
 import java.math.BigDecimal;
 import java.math.BigDecimal;
 import java.util.HashMap;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Map;
@@ -238,38 +246,32 @@ public class ByteDanceAdvertiserDataServiceImpl implements IByteDanceAdvertiserD
     @Override
     @Override
     public Map<String, Object> advertiserCampaignCreate(String accountId, String campaignName, String budgetMode, Integer budget, String landingType) {
     public Map<String, Object> advertiserCampaignCreate(String accountId, String campaignName, String budgetMode, Integer budget, String landingType) {
         Map<String,Object>resultMap = new HashMap<>();
         Map<String,Object>resultMap = new HashMap<>();
-        CTopOauthToken cTopOauthToken = getOAuthTokenByAccountId(accountId);
+        CTopOauthToken token = getOAuthTokenByAccountId(accountId);
         //2: 根据token以及用户id获取用户信息数据
         //2: 根据token以及用户id获取用户信息数据
-        String url = PropertiesUtils.getValue("bytedance_config","bytedance_api_url")+PropertiesUtils.getValue("bytedance_config","bytedance_v2_campaign_create");
-        Map<String,String> headers = new HashMap<>();
-        headers.put("Content-Type","application/json");
-        headers.put("Access-Token",cTopOauthToken.getAccessToken());
-
         JSONObject params = new JSONObject();
         JSONObject params = new JSONObject();
-        params.put("advertiser_id",cTopOauthToken.getAccountId());
+        params.put("advertiser_id", token.getAccountId());
         params.put("campaign_name",campaignName);
         params.put("campaign_name",campaignName);
         params.put("budget_mode",budgetMode);
         params.put("budget_mode",budgetMode);
         params.put("budget",budget);
         params.put("budget",budget);
         params.put("landing_type",landingType);
         params.put("landing_type",landingType);
-        String result = HttpUtils.httpPostRequest(url,params,headers);
-        JSONObject jsonObject = JSONObject.parseObject(result);
-        Integer code = jsonObject.getInteger("code");
+        JSONObject result = createCampaign(params, token.getAccessToken());
+        Integer code = result.getInteger("code");
 
 
         if(null==code||!code.equals(0)){
         if(null==code||!code.equals(0)){
-            logger.info("创建广告组接口异常==》accountId:{},message:{}",accountId,jsonObject.getString("message"));
+            logger.info("创建广告组接口异常==》accountId:{},message:{}", accountId, result.getString("message"));
             resultMap.put("code",-1);
             resultMap.put("code",-1);
             resultMap.put("message","创建广告组接口异常");
             resultMap.put("message","创建广告组接口异常");
             return resultMap;
             return resultMap;
         }
         }
-        JSONObject data = jsonObject.getJSONObject("data");
+        JSONObject data = result.getJSONObject("data");
         if(null==data){
         if(null==data){
-            logger.info("广告组创建异常==》accountId:{},message:{}",accountId,jsonObject.getString("message"));
+            logger.info("广告组创建异常==》accountId:{},message:{}", accountId, result.getString("message"));
             resultMap.put("code",-1);
             resultMap.put("code",-1);
             resultMap.put("message","广告组创建异常");
             resultMap.put("message","广告组创建异常");
             return resultMap;
             return resultMap;
         }
         }
         Long id =  data.getLong("campaign_id");
         Long id =  data.getLong("campaign_id");
-        ByteDanceCampaign campaign = new ByteDanceCampaign(id, cTopOauthToken, campaignName, budgetMode, budget, landingType);
+        ByteDanceCampaign campaign = new ByteDanceCampaign(id, token, campaignName, budgetMode, budget, landingType);
         //清除清数据,插入新数据
         //清除清数据,插入新数据
         campaignMapper.insert(campaign);
         campaignMapper.insert(campaign);
         resultMap.put("code",0);
         resultMap.put("code",0);
@@ -277,6 +279,51 @@ public class ByteDanceAdvertiserDataServiceImpl implements IByteDanceAdvertiserD
         return resultMap;
         return resultMap;
     }
     }
 
 
+    public JSONObject createCampaign(JSONObject data, String token) {
+        // 请求地址
+        String url = PropertiesUtils.getValue("bytedance_config", "bytedance_api_url") + PropertiesUtils.getValue("bytedance_config", "bytedance_v2_campaign_create");
+
+        // 构造请求
+        HttpPost httpEntity = new HttpPost(url);
+
+        httpEntity.setHeader("Access-Token", token);
+
+        CloseableHttpResponse response = null;
+        CloseableHttpClient client = null;
+
+        try {
+            client = HttpClientBuilder.create().build();
+            httpEntity.setEntity(new StringEntity(data.toJSONString(), ContentType.APPLICATION_JSON));
+
+            response = client.execute(httpEntity);
+            if (response != null && response.getStatusLine().getStatusCode() == 200) {
+                BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
+                StringBuffer result = new StringBuffer();
+                String line = "";
+                while ((line = bufferedReader.readLine()) != null) {
+                    result.append(line);
+                }
+                bufferedReader.close();
+                return JSONObject.parseObject(result.toString());
+            }
+
+        } catch (ClientProtocolException e) {
+            e.printStackTrace();
+        } catch (IOException e) {
+            e.printStackTrace();
+        } finally {
+            try {
+                if (response != null) {
+                    response.close();
+                }
+                client.close();
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+        }
+        return null;
+    }
+
     @Override
     @Override
     public Map<String, Object> advertiserCampaignUpdateStatus(String accountId, String campaignIds, String optStatus) {
     public Map<String, Object> advertiserCampaignUpdateStatus(String accountId, String campaignIds, String optStatus) {
         Map<String,Object>resultMap = new HashMap<>();
         Map<String,Object>resultMap = new HashMap<>();
@@ -646,6 +693,41 @@ public class ByteDanceAdvertiserDataServiceImpl implements IByteDanceAdvertiserD
         return resultMap;
         return resultMap;
     }
     }
 
 
+    @Override
+    public Map<String, Object> campaignCreate(CTopOauthToken token, ByteDanceCampaignTemplate template) {
+        Map<String, Object> resultMap = new HashMap<>();
+        //2: 根据token以及用户id获取用户信息数据
+        JSONObject params = new JSONObject();
+        params.put("advertiser_id", token.getAccountId());
+        params.put("campaign_name", template.getCampaignName());
+        params.put("budget_mode", template.getCampaignBudget());
+        params.put("budget", template.getBudgetDaily());
+        params.put("landing_type", template.getPromotionPurpuse());
+        JSONObject result = createCampaign(params, token.getAccessToken());
+        Integer code = result.getInteger("code");
+
+        if (null == code || !code.equals(0)) {
+            logger.info("创建广告组接口异常==》accountId:{},message:{}", token.getAccountId(), result.getString("message"));
+            resultMap.put("code", -1);
+            resultMap.put("message", "创建广告组接口异常");
+            return resultMap;
+        }
+        JSONObject data = result.getJSONObject("data");
+        if (null == data) {
+            logger.info("广告组创建异常==》accountId:{},message:{}", token.getAccountId(), result.getString("message"));
+            resultMap.put("code", -1);
+            resultMap.put("message", "广告组创建异常");
+            return resultMap;
+        }
+        Long id = data.getLong("campaign_id");
+        ByteDanceCampaign campaign = new ByteDanceCampaign(id, token, template);
+        //清除清数据,插入新数据
+        campaignMapper.insert(campaign);
+        resultMap.put("code", 0);
+        resultMap.put("message", "广告组创建成功");
+        return resultMap;
+    }
+
     @Autowired
     @Autowired
     private ByteDanceCustomAudienceMapper audienceMapper;
     private ByteDanceCustomAudienceMapper audienceMapper;
 
 

+ 4 - 3
jeecg-boot-module-system/src/main/java/org/jeecg/modules/ctop/service/impl/ByteDanceCampaignTemplateServiceImpl.java

@@ -11,6 +11,7 @@ import org.jeecg.modules.ctop.entity.ByteDanceCampaign;
 import org.jeecg.modules.ctop.entity.ByteDanceCampaignTemplate;
 import org.jeecg.modules.ctop.entity.ByteDanceCampaignTemplate;
 import org.jeecg.modules.ctop.entity.CTopOauthToken;
 import org.jeecg.modules.ctop.entity.CTopOauthToken;
 import org.jeecg.modules.ctop.mapper.ByteDanceCampaignTemplateMapper;
 import org.jeecg.modules.ctop.mapper.ByteDanceCampaignTemplateMapper;
+import org.jeecg.modules.ctop.service.IByteDanceAdvertiserDataService;
 import org.jeecg.modules.ctop.service.IByteDanceCampaignTemplateService;
 import org.jeecg.modules.ctop.service.IByteDanceCampaignTemplateService;
 import org.jeecg.modules.ctop.service.ICTopOauthTokenService;
 import org.jeecg.modules.ctop.service.ICTopOauthTokenService;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -39,11 +40,11 @@ public class ByteDanceCampaignTemplateServiceImpl extends ServiceImpl<ByteDanceC
         template.setAccountId(token.getAccountId());
         template.setAccountId(token.getAccountId());
         template.setAdvertiserId(token.getAdvertiserId());
         template.setAdvertiserId(token.getAdvertiserId());
         campaignTemplateMapper.insert(template);
         campaignTemplateMapper.insert(template);
-        resultMap.put("success", true);
-        resultMap.put("message", "模板保存成功");
-        return resultMap;
+        return advertiserDataService.campaignCreate(token, template);
     }
     }
 
 
+    @Autowired
+    private IByteDanceAdvertiserDataService advertiserDataService;
     @Override
     @Override
     public Result<IPage<ByteDanceCampaignTemplate>> getList(ByteDanceCampaignTemplate template, Integer pageNo, Integer pageSize, HttpServletRequest req) {
     public Result<IPage<ByteDanceCampaignTemplate>> getList(ByteDanceCampaignTemplate template, Integer pageNo, Integer pageSize, HttpServletRequest req) {
         LoginUser user = (LoginUser) SecurityUtils.getSubject().getPrincipal();
         LoginUser user = (LoginUser) SecurityUtils.getSubject().getPrincipal();

+ 89 - 0
jeecg-boot-module-system/src/main/java/org/jeecg/modules/ctop/service/impl/ByteDanceCreativeServiceImpl.java

@@ -1,12 +1,32 @@
 package org.jeecg.modules.ctop.service.impl;
 package org.jeecg.modules.ctop.service.impl;
 
 
+import cn.com.ctop.common.utils.PropertiesUtils;
+import com.alibaba.fastjson.JSONObject;
+import org.apache.http.client.ClientProtocolException;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.entity.ContentType;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClientBuilder;
 import org.jeecg.modules.ctop.entity.ByteDanceCreative;
 import org.jeecg.modules.ctop.entity.ByteDanceCreative;
+import org.jeecg.modules.ctop.entity.CTopOauthToken;
 import org.jeecg.modules.ctop.mapper.ByteDanceCreativeMapper;
 import org.jeecg.modules.ctop.mapper.ByteDanceCreativeMapper;
 import org.jeecg.modules.ctop.service.IByteDanceCreativeService;
 import org.jeecg.modules.ctop.service.IByteDanceCreativeService;
+import org.jeecg.modules.ctop.service.ICTopOauthTokenService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import org.springframework.stereotype.Service;
 
 
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 
 
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.HashMap;
+import java.util.Map;
+
 /**
 /**
  * @Description: 今日头条创意信息
  * @Description: 今日头条创意信息
  * @Author: jeecg-boot
  * @Author: jeecg-boot
@@ -15,5 +35,74 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
  */
  */
 @Service
 @Service
 public class ByteDanceCreativeServiceImpl extends ServiceImpl<ByteDanceCreativeMapper, ByteDanceCreative> implements IByteDanceCreativeService {
 public class ByteDanceCreativeServiceImpl extends ServiceImpl<ByteDanceCreativeMapper, ByteDanceCreative> implements IByteDanceCreativeService {
+    private static final Logger logger = LoggerFactory.getLogger(ByteDanceCreativeServiceImpl.class);
+
+    @Override
+    public Map<String, Object> creativeCreate(String accountId, Long adId, String dataString) {
+        Map<String, Object> resultMap = new HashMap<>();
+        //1:获取token
+        CTopOauthToken token = tokenService.getOAuthTokenByAccountId(accountId);
+        JSONObject data = JSONObject.parseObject(dataString);
+        data.put("advertiser_id", token.getAccountId());
+        data.put("ad_id", adId);
+        JSONObject result = createCreative(data, token.getAccessToken());
+        Integer code = result.getInteger("code");
+        String message = result.getString("message");
+        if (null == code || code != 0) {
+            logger.info("广告创意创建失败,accountId:{},message:{}", accountId, message);
+            resultMap.put("code", -1);
+            resultMap.put("message", message);
+            return resultMap;
+        }
+        JSONObject dataObject = result.getJSONObject("data");
+//        Long adId = dataObject.getLong("ad_id");
+        System.out.println(dataObject.toJSONString());
+        resultMap.put("code", 0);
+        resultMap.put("message", "广告创意创建成功");
+        return resultMap;
+    }
+
+    public JSONObject createCreative(JSONObject data, String token) {
+
+        // 构造请求
+        String url = PropertiesUtils.getValue("bytedance_config", "bytedance_api_url") + PropertiesUtils.getValue("bytedance_config", "bytedance_v2_creative_create_v2");
+        // 构造请求
+        HttpPost httpEntity = new HttpPost(url);
+        httpEntity.setHeader("Access-Token", token);
+        CloseableHttpResponse response = null;
+        CloseableHttpClient client = null;
+        try {
+            client = HttpClientBuilder.create().build();
+            httpEntity.setEntity(new StringEntity(data.toJSONString(), ContentType.APPLICATION_JSON));
+            response = client.execute(httpEntity);
+            if (response != null && response.getStatusLine().getStatusCode() == 200) {
+                BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
+                StringBuffer result = new StringBuffer();
+                String line = "";
+                while ((line = bufferedReader.readLine()) != null) {
+                    result.append(line);
+                }
+                bufferedReader.close();
+                return JSONObject.parseObject(result.toString());
+            }
+
+        } catch (ClientProtocolException e) {
+            e.printStackTrace();
+        } catch (IOException e) {
+            e.printStackTrace();
+        } finally {
+            try {
+                if (response != null) {
+                    response.close();
+                }
+                client.close();
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+        }
+        return null;
+    }
 
 
+    @Autowired
+    private ICTopOauthTokenService tokenService;
 }
 }

+ 19 - 0
jeecg-boot-module-system/src/main/java/org/jeecg/modules/ctop/service/impl/ByteDanceImageInfoServiceImpl.java

@@ -0,0 +1,19 @@
+package org.jeecg.modules.ctop.service.impl;
+
+import org.jeecg.modules.ctop.entity.ByteDanceImageInfo;
+import org.jeecg.modules.ctop.mapper.ByteDanceImageInfoMapper;
+import org.jeecg.modules.ctop.service.IByteDanceImageInfoService;
+import org.springframework.stereotype.Service;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+
+/**
+ * @Description: 头条图片素材信息
+ * @Author: jeecg-boot
+ * @Date: 2019-07-29
+ * @Version: V1.0
+ */
+@Service
+public class ByteDanceImageInfoServiceImpl extends ServiceImpl<ByteDanceImageInfoMapper, ByteDanceImageInfo> implements IByteDanceImageInfoService {
+
+}

+ 19 - 0
jeecg-boot-module-system/src/main/java/org/jeecg/modules/ctop/service/impl/ByteDanceVideoInfoServiceImpl.java

@@ -0,0 +1,19 @@
+package org.jeecg.modules.ctop.service.impl;
+
+import org.jeecg.modules.ctop.entity.ByteDanceVideoInfo;
+import org.jeecg.modules.ctop.mapper.ByteDanceVideoInfoMapper;
+import org.jeecg.modules.ctop.service.IByteDanceVideoInfoService;
+import org.springframework.stereotype.Service;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+
+/**
+ * @Description: 今日头条视频素材信息
+ * @Author: jeecg-boot
+ * @Date: 2019-07-29
+ * @Version: V1.0
+ */
+@Service
+public class ByteDanceVideoInfoServiceImpl extends ServiceImpl<ByteDanceVideoInfoMapper, ByteDanceVideoInfo> implements IByteDanceVideoInfoService {
+
+}

+ 260 - 1
jeecg-boot-module-system/src/main/java/org/jeecg/modules/ctop/service/impl/FileInfoServiceImpl.java

@@ -1,11 +1,38 @@
 package org.jeecg.modules.ctop.service.impl;
 package org.jeecg.modules.ctop.service.impl;
 
 
+import cn.com.ctop.common.utils.PropertiesUtils;
+import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.apache.commons.codec.digest.DigestUtils;
+import org.apache.http.HttpEntity;
+import org.apache.http.client.ClientProtocolException;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.entity.ContentType;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.entity.mime.MultipartEntityBuilder;
+import org.apache.http.entity.mime.content.FileBody;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClientBuilder;
+import org.jeecg.modules.ctop.entity.ByteDanceImageInfo;
+import org.jeecg.modules.ctop.entity.ByteDanceVideoInfo;
+import org.jeecg.modules.ctop.entity.CTopOauthToken;
 import org.jeecg.modules.ctop.entity.FileInfo;
 import org.jeecg.modules.ctop.entity.FileInfo;
+import org.jeecg.modules.ctop.mapper.ByteDanceImageInfoMapper;
+import org.jeecg.modules.ctop.mapper.ByteDanceVideoInfoMapper;
 import org.jeecg.modules.ctop.mapper.FileInfoMapper;
 import org.jeecg.modules.ctop.mapper.FileInfoMapper;
+import org.jeecg.modules.ctop.service.ICTopOauthTokenService;
 import org.jeecg.modules.ctop.service.IFileInfoService;
 import org.jeecg.modules.ctop.service.IFileInfoService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import org.springframework.stereotype.Service;
 
 
-import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import java.io.*;
+import java.net.URI;
+import java.util.HashMap;
+import java.util.Map;
 
 
 /**
 /**
  * @Description: 文件信息
  * @Description: 文件信息
@@ -15,5 +42,237 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
  */
  */
 @Service
 @Service
 public class FileInfoServiceImpl extends ServiceImpl<FileInfoMapper, FileInfo> implements IFileInfoService {
 public class FileInfoServiceImpl extends ServiceImpl<FileInfoMapper, FileInfo> implements IFileInfoService {
+    private static final Logger logger = LoggerFactory.getLogger(FileInfoServiceImpl.class);
+
+    @Override
+    public Map<String, Object> uploadVideoToTemplate(String accountId, Long videoFileId, String templatename) {
+        Map<String, Object> resultMap = new HashMap<>();
+        FileInfo fileInfo = fileInfoMapper.selectById(videoFileId);
+        if (null == fileInfo) {
+            resultMap.put("message", "该视频文件信息不存在");
+            resultMap.put("code", -1);
+            return resultMap;
+        }
+        //TODO查询是否已经上传过头条平台
+        CTopOauthToken token = tokenService.getOAuthTokenByAccountId(accountId);
+        JSONObject resultObject = uploadAdvideo(token.getAccessToken(), fileInfo, token.getAccountId() + "");
+        System.out.println(resultObject);
+        Integer code = resultObject.getInteger("code");
+        String message = resultObject.getString("message");
+        if (null == code || code != 0) {
+            logger.info("视频文件上传失败,accountId:{},message:{}", accountId, message);
+            resultMap.put("code", -1);
+            resultMap.put("message", "视频文件上传失败");
+            return resultMap;
+        }
+        JSONObject data = resultObject.getJSONObject("data");
+        ByteDanceVideoInfo videoInfo = new ByteDanceVideoInfo(data, token, videoFileId);
+        videoInfoMapper.insert(videoInfo);
+        resultMap.put("code", 0);
+        resultMap.put("message", "视频文件上传成功");
+        return resultMap;
+    }
+
+    @Autowired
+    private ByteDanceVideoInfoMapper videoInfoMapper;
+    @Autowired
+    private ByteDanceImageInfoMapper imageInfoMapper;
+
+    @Override
+    public Map<String, Object> uploadImageToTemplate(String accountId, Long imageFileId, String templatename) {
+        Map<String, Object> resultMap = new HashMap<>();
+        FileInfo fileInfo = fileInfoMapper.selectById(imageFileId);
+        if (null == fileInfo) {
+            resultMap.put("message", "该图片文件信息不存在");
+            resultMap.put("code", -1);
+            return resultMap;
+        }
+        if (null == fileInfo.getType() || !"IMAGE".equals(fileInfo.getType())) {
+            resultMap.put("message", "文件格式错误");
+            resultMap.put("code", -1);
+            return resultMap;
+        }
+        //TODO查询是否已经上传过头条平台
+        CTopOauthToken token = tokenService.getOAuthTokenByAccountId(accountId);
+        JSONObject resultObject = uploadAdImage(token.getAccessToken(), fileInfo, token.getAccountId() + "");
+        System.out.println(resultObject);
+        Integer code = resultObject.getInteger("code");
+        String message = resultObject.getString("message");
+        if (null == code || code != 0) {
+            logger.info("图片文件上传失败,accountId:{},message:{}", accountId, message);
+            resultMap.put("code", -1);
+            resultMap.put("message", "图片文件上传失败");
+            return resultMap;
+        }
+        JSONObject data = resultObject.getJSONObject("data");
+        ByteDanceImageInfo imageInfo = new ByteDanceImageInfo(data, token, imageFileId);
+        imageInfoMapper.insert(imageInfo);
+        resultMap.put("code", 0);
+        resultMap.put("message", "图片文件上传成功");
+        return resultMap;
+    }
+
+    @Override
+    public Map<String, Object> getIndustryList(String accountId) {
+        Map<String, Object> resultMap = new HashMap<>();
+        CTopOauthToken token = tokenService.getOAuthTokenByAccountId(accountId);
+        JSONObject result = searchIndustry(token);
+        resultMap.put("code", 0);
+        resultMap.put("message", "数据获取成功");
+        resultMap.put("data", result);
+        return resultMap;
+    }
+
+    public JSONObject searchIndustry(CTopOauthToken token) {
+        // 请求地址
+        String url = "https://ad.toutiao.com/open_api/2/tools/industry/get/";
+
+        // 构造请求
+        HttpEntityEnclosingRequestBase httpEntity = new HttpEntityEnclosingRequestBase() {
+            @Override
+            public String getMethod() {
+                return "GET";
+            }
+        };
+        httpEntity.setHeader("Access-Token", token.getAccessToken());
+        CloseableHttpResponse response = null;
+        CloseableHttpClient client = null;
+        try {
+            client = HttpClientBuilder.create().build();
+            httpEntity.setURI(URI.create(url));
+            httpEntity.setEntity(new StringEntity(new JSONObject().toJSONString(), ContentType.APPLICATION_JSON));
+            response = client.execute(httpEntity);
+            if (response != null && response.getStatusLine().getStatusCode() == 200) {
+                BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
+                StringBuffer result = new StringBuffer();
+                String line = "";
+                while ((line = bufferedReader.readLine()) != null) {
+                    result.append(line);
+                }
+                bufferedReader.close();
+                return JSONObject.parseObject(result.toString());
+            }
+        } catch (ClientProtocolException e) {
+            e.printStackTrace();
+        } catch (IOException e) {
+            e.printStackTrace();
+        } finally {
+            try {
+                if (response != null) {
+                    response.close();
+                }
+                client.close();
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+        }
+        return null;
+    }
+
+    public JSONObject uploadAdImage(String accessToken, FileInfo fileInfo, String advertiserId) {
+        // 请求地址
+        String url = PropertiesUtils.getValue("bytedance_config", "bytedance_api_url") + PropertiesUtils.getValue("bytedance_config", "bytedance_v2_file_image_ad");
+        // 构造请求
+        HttpPost httpPost = new HttpPost(url);
+        httpPost.setHeader("Access-Token", accessToken);
+        // 文件参数
+        FileBody file = new FileBody(new File(fileInfo.getPath()));
+        MultipartEntityBuilder entityBuilder = MultipartEntityBuilder.create().addPart("image_file", file);
+        // 其他参数
+        entityBuilder.addTextBody("advertiser_id", advertiserId);
+        try {
+            entityBuilder.addTextBody("image_signature", DigestUtils.md5Hex(new FileInputStream(fileInfo.getPath())));
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+        HttpEntity entity = entityBuilder.build();
+        CloseableHttpResponse response = null;
+        CloseableHttpClient client = null;
+        try {
+            client = HttpClientBuilder.create().build();
+            httpPost.setURI(URI.create(url));
+            httpPost.setEntity(entity);
+            response = client.execute(httpPost);
+            if (response != null && response.getStatusLine().getStatusCode() == 200) {
+                BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
+                StringBuffer result = new StringBuffer();
+                String line = "";
+                while ((line = bufferedReader.readLine()) != null) {
+                    result.append(line);
+                }
+                bufferedReader.close();
+                return JSONObject.parseObject(result.toString());
+            }
+        } catch (ClientProtocolException e) {
+            e.printStackTrace();
+        } catch (IOException e) {
+            e.printStackTrace();
+        } finally {
+            try {
+                if (response != null) {
+                    response.close();
+                }
+                client.close();
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+        }
+        return null;
+    }
+
+    public JSONObject uploadAdvideo(String accessToken, FileInfo fileInfo, String advertiserId) {
+        // 请求地址
+        String url = PropertiesUtils.getValue("bytedance_config", "bytedance_api_url") + PropertiesUtils.getValue("bytedance_config", "bytedance_v2_file_video_ad");
+        // 构造请求
+        HttpPost httpPost = new HttpPost(url);
+        httpPost.setHeader("Access-Token", accessToken);
+        // 文件参数
+        FileBody file = new FileBody(new File(fileInfo.getPath()));
+        MultipartEntityBuilder entityBuilder = MultipartEntityBuilder.create().addPart("video_file", file);
+        // 其他参数
+        entityBuilder.addTextBody("advertiser_id", advertiserId);
+        try {
+            entityBuilder.addTextBody("video_signature", DigestUtils.md5Hex(new FileInputStream(fileInfo.getPath())));
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+        HttpEntity entity = entityBuilder.build();
+        CloseableHttpResponse response = null;
+        CloseableHttpClient client = null;
+        try {
+            client = HttpClientBuilder.create().build();
+            httpPost.setURI(URI.create(url));
+            httpPost.setEntity(entity);
+            response = client.execute(httpPost);
+            if (response != null && response.getStatusLine().getStatusCode() == 200) {
+                BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
+                StringBuffer result = new StringBuffer();
+                String line = "";
+                while ((line = bufferedReader.readLine()) != null) {
+                    result.append(line);
+                }
+                bufferedReader.close();
+                return JSONObject.parseObject(result.toString());
+            }
+        } catch (ClientProtocolException e) {
+            e.printStackTrace();
+        } catch (IOException e) {
+            e.printStackTrace();
+        } finally {
+            try {
+                if (response != null) {
+                    response.close();
+                }
+                client.close();
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+        }
+        return null;
+    }
 
 
+    @Autowired
+    private FileInfoMapper fileInfoMapper;
+    @Autowired
+    private ICTopOauthTokenService tokenService;
 }
 }

+ 193 - 0
jeecg-boot-module-system/src/main/java/org/jeecg/modules/ctop/vue/BindAccountList.vue

@@ -0,0 +1,193 @@
+<template>
+  <a-card :bordered="false">
+
+    <!-- 查询区域 -->
+    <div class="table-page-search-wrapper">
+      <a-form layout="inline">
+        <a-row :gutter="24">
+
+          <a-col :md="6" :sm="8">
+            <a-form-item label="广告id">
+              <a-input placeholder="请输入广告id" v-model="queryParam.advertiserId"></a-input>
+            </a-form-item>
+          </a-col>
+          <a-col :md="6" :sm="8">
+            <a-form-item label="账号">
+              <a-input placeholder="请输入账号" v-model="queryParam.accountName"></a-input>
+            </a-form-item>
+          </a-col>
+        <template v-if="toggleSearchStatus">
+        <a-col :md="6" :sm="8">
+            <a-form-item label="密码">
+              <a-input placeholder="请输入密码" v-model="queryParam.password"></a-input>
+            </a-form-item>
+          </a-col>
+          <a-col :md="6" :sm="8">
+            <a-form-item label="登录/授权方式">
+              <a-input placeholder="请输入登录/授权方式" v-model="queryParam.loginType"></a-input>
+            </a-form-item>
+          </a-col>
+          <a-col :md="6" :sm="8">
+            <a-form-item label="方式:登录或授权">
+              <a-input placeholder="请输入方式:登录或授权" v-model="queryParam.type"></a-input>
+            </a-form-item>
+          </a-col>
+          </template>
+          <a-col :md="6" :sm="8" >
+            <span style="float: left;overflow: hidden;" class="table-page-search-submitButtons">
+              <a-button type="primary" @click="searchQuery" icon="search">查询</a-button>
+              <a-button type="primary" @click="searchReset" icon="reload" style="margin-left: 8px">重置</a-button>
+              <a @click="handleToggleSearch" style="margin-left: 8px">
+                {{ toggleSearchStatus ? '收起' : '展开' }}
+                <a-icon :type="toggleSearchStatus ? 'up' : 'down'"/>
+              </a>
+            </span>
+          </a-col>
+
+        </a-row>
+      </a-form>
+    </div>
+
+    <!-- 操作按钮区域 -->
+    <div class="table-operator">
+      <a-button @click="handleAdd" type="primary" icon="plus">新增</a-button>
+      <a-button type="primary" icon="download" @click="handleExportXls('账户绑定')">导出</a-button>
+      <a-upload name="file" :showUploadList="false" :multiple="false" :headers="tokenHeader" :action="importExcelUrl" @change="handleImportExcel">
+        <a-button type="primary" icon="import">导入</a-button>
+      </a-upload>
+      <a-dropdown v-if="selectedRowKeys.length > 0">
+        <a-menu slot="overlay">
+          <a-menu-item key="1" @click="batchDel"><a-icon type="delete"/>删除</a-menu-item>
+        </a-menu>
+        <a-button style="margin-left: 8px"> 批量操作 <a-icon type="down" /></a-button>
+      </a-dropdown>
+    </div>
+
+    <!-- table区域-begin -->
+    <div>
+      <div class="ant-alert ant-alert-info" style="margin-bottom: 16px;">
+        <i class="anticon anticon-info-circle ant-alert-icon"></i> 已选择 <a style="font-weight: 600">{{ selectedRowKeys.length }}</a>项
+        <a style="margin-left: 24px" @click="onClearSelected">清空</a>
+      </div>
+
+      <a-table
+        ref="table"
+        size="middle"
+        bordered
+        rowKey="id"
+        :columns="columns"
+        :dataSource="dataSource"
+        :pagination="ipagination"
+        :loading="loading"
+        :rowSelection="{selectedRowKeys: selectedRowKeys, onChange: onSelectChange}"
+        @change="handleTableChange">
+
+        <span slot="action" slot-scope="text, record">
+          <a @click="handleEdit(record)">编辑</a>
+
+          <a-divider type="vertical" />
+          <a-dropdown>
+            <a class="ant-dropdown-link">更多 <a-icon type="down" /></a>
+            <a-menu slot="overlay">
+              <a-menu-item>
+                <a-popconfirm title="确定删除吗?" @confirm="() => handleDelete(record.id)">
+                  <a>删除</a>
+                </a-popconfirm>
+              </a-menu-item>
+            </a-menu>
+          </a-dropdown>
+        </span>
+
+      </a-table>
+    </div>
+    <!-- table区域-end -->
+
+    <!-- 表单区域 -->
+    <bindAccount-modal ref="modalForm" @ok="modalFormOk"></bindAccount-modal>
+  </a-card>
+</template>
+
+<script>
+  import BindAccountModal from './modules/BindAccountModal'
+  import { JeecgListMixin } from '@/mixins/JeecgListMixin'
+
+  export default {
+    name: "BindAccountList",
+    mixins:[JeecgListMixin],
+    components: {
+      BindAccountModal
+    },
+    data () {
+      return {
+        description: '账户绑定管理页面',
+        // 表头
+        columns: [
+          {
+            title: '#',
+            dataIndex: '',
+            key:'rowIndex',
+            width:60,
+            align:"center",
+            customRender:function (t,r,index) {
+              return parseInt(index)+1;
+            }
+           },
+		   {
+            title: '广告id',
+            align:"center",
+            dataIndex: 'advertiserId'
+           },
+		   {
+            title: '账号',
+            align:"center",
+            dataIndex: 'accountName'
+           },
+		   {
+            title: '密码',
+            align:"center",
+            dataIndex: 'password'
+           },
+		   {
+            title: '登录/授权方式',
+            align:"center",
+            dataIndex: 'loginType'
+           },
+		   {
+            title: '方式:登录或授权',
+            align:"center",
+            dataIndex: 'type'
+           },
+		   {
+            title: '回调返回广告主id',
+            align:"center",
+            dataIndex: 'accountId'
+           },
+          {
+            title: '操作',
+            dataIndex: 'action',
+            align:"center",
+            scopedSlots: { customRender: 'action' },
+          }
+        ],
+		url: {
+          list: "/ctop/bindAccount/list",
+          delete: "/ctop/bindAccount/delete",
+          deleteBatch: "/ctop/bindAccount/deleteBatch",
+          exportXlsUrl: "ctop/bindAccount/exportXls",
+          importExcelUrl: "ctop/bindAccount/importExcel",
+       },
+    }
+  },
+  computed: {
+    importExcelUrl: function(){
+      return `${window._CONFIG['domianURL']}/${this.url.importExcelUrl}`;
+    }
+  },
+    methods: {
+     
+    }
+  }
+</script>
+<style scoped>
+  @import '~@assets/less/common.less'
+</style>

+ 213 - 0
jeecg-boot-module-system/src/main/java/org/jeecg/modules/ctop/vue/ByteDanceImageInfoList.vue

@@ -0,0 +1,213 @@
+<template>
+    <a-card :bordered="false">
+
+        <!-- 查询区域 -->
+        <div class="table-page-search-wrapper">
+            <a-form layout="inline">
+                <a-row :gutter="24">
+
+                    <a-col :md="6" :sm="8">
+                        <a-form-item label="文件id">
+                            <a-input placeholder="请输入文件id" v-model="queryParam.fileId"></a-input>
+                        </a-form-item>
+                    </a-col>
+                    <a-col :md="6" :sm="8">
+                        <a-form-item label="头条平台账号id">
+                            <a-input placeholder="请输入头条平台账号id" v-model="queryParam.accountId"></a-input>
+                        </a-form-item>
+                    </a-col>
+                    <template v-if="toggleSearchStatus">
+                        <a-col :md="6" :sm="8">
+                            <a-form-item label="图片大小">
+                                <a-input placeholder="请输入图片大小" v-model="queryParam.size"></a-input>
+                            </a-form-item>
+                        </a-col>
+                        <a-col :md="6" :sm="8">
+                            <a-form-item label="图片宽度">
+                                <a-input placeholder="请输入图片宽度" v-model="queryParam.width"></a-input>
+                            </a-form-item>
+                        </a-col>
+                        <a-col :md="6" :sm="8">
+                            <a-form-item label="图片高度">
+                                <a-input placeholder="请输入图片高度" v-model="queryParam.height"></a-input>
+                            </a-form-item>
+                        </a-col>
+                    </template>
+                    <a-col :md="6" :sm="8">
+            <span style="float: left;overflow: hidden;" class="table-page-search-submitButtons">
+              <a-button type="primary" @click="searchQuery" icon="search">查询</a-button>
+              <a-button type="primary" @click="searchReset" icon="reload" style="margin-left: 8px">重置</a-button>
+              <a @click="handleToggleSearch" style="margin-left: 8px">
+                {{ toggleSearchStatus ? '收起' : '展开' }}
+                <a-icon :type="toggleSearchStatus ? 'up' : 'down'"/>
+              </a>
+            </span>
+                    </a-col>
+
+                </a-row>
+            </a-form>
+        </div>
+
+        <!-- 操作按钮区域 -->
+        <div class="table-operator">
+            <a-button @click="handleAdd" type="primary" icon="plus">新增</a-button>
+            <a-button type="primary" icon="download" @click="handleExportXls('头条图片素材信息')">导出</a-button>
+            <a-upload name="file" :showUploadList="false" :multiple="false" :headers="tokenHeader"
+                      :action="importExcelUrl" @change="handleImportExcel">
+                <a-button type="primary" icon="import">导入</a-button>
+            </a-upload>
+            <a-dropdown v-if="selectedRowKeys.length > 0">
+                <a-menu slot="overlay">
+                    <a-menu-item key="1" @click="batchDel">
+                        <a-icon type="delete"/>
+                        删除
+                    </a-menu-item>
+                </a-menu>
+                <a-button style="margin-left: 8px"> 批量操作
+                    <a-icon type="down"/>
+                </a-button>
+            </a-dropdown>
+        </div>
+
+        <!-- table区域-begin -->
+        <div>
+            <div class="ant-alert ant-alert-info" style="margin-bottom: 16px;">
+                <i class="anticon anticon-info-circle ant-alert-icon"></i> 已选择 <a style="font-weight: 600">{{
+                selectedRowKeys.length }}</a>项
+                <a style="margin-left: 24px" @click="onClearSelected">清空</a>
+            </div>
+
+            <a-table
+                    ref="table"
+                    size="middle"
+                    bordered
+                    rowKey="id"
+                    :columns="columns"
+                    :dataSource="dataSource"
+                    :pagination="ipagination"
+                    :loading="loading"
+                    :rowSelection="{selectedRowKeys: selectedRowKeys, onChange: onSelectChange}"
+                    @change="handleTableChange">
+
+        <span slot="action" slot-scope="text, record">
+          <a @click="handleEdit(record)">编辑</a>
+
+          <a-divider type="vertical"/>
+          <a-dropdown>
+            <a class="ant-dropdown-link">更多 <a-icon type="down"/></a>
+            <a-menu slot="overlay">
+              <a-menu-item>
+                <a-popconfirm title="确定删除吗?" @confirm="() => handleDelete(record.id)">
+                  <a>删除</a>
+                </a-popconfirm>
+              </a-menu-item>
+            </a-menu>
+          </a-dropdown>
+        </span>
+
+            </a-table>
+        </div>
+        <!-- table区域-end -->
+
+        <!-- 表单区域 -->
+        <byteDanceImageInfo-modal ref="modalForm" @ok="modalFormOk"></byteDanceImageInfo-modal>
+    </a-card>
+</template>
+
+<script>
+    import ByteDanceImageInfoModal from './modules/ByteDanceImageInfoModal'
+    import {JeecgListMixin} from '@/mixins/JeecgListMixin'
+
+    export default {
+        name: "ByteDanceImageInfoList",
+        mixins: [JeecgListMixin],
+        components: {
+            ByteDanceImageInfoModal
+        },
+        data() {
+            return {
+                description: '头条图片素材信息管理页面',
+                // 表头
+                columns: [
+                    {
+                        title: '#',
+                        dataIndex: '',
+                        key: 'rowIndex',
+                        width: 60,
+                        align: "center",
+                        customRender: function (t, r, index) {
+                            return parseInt(index) + 1;
+                        }
+                    },
+                    {
+                        title: '文件id',
+                        align: "center",
+                        dataIndex: 'fileId'
+                    },
+                    {
+                        title: '头条平台账号id',
+                        align: "center",
+                        dataIndex: 'accountId'
+                    },
+                    {
+                        title: '图片大小',
+                        align: "center",
+                        dataIndex: 'size'
+                    },
+                    {
+                        title: '图片宽度',
+                        align: "center",
+                        dataIndex: 'width'
+                    },
+                    {
+                        title: '图片高度',
+                        align: "center",
+                        dataIndex: 'height'
+                    },
+                    {
+                        title: '预览地址',
+                        align: "center",
+                        dataIndex: 'url'
+                    },
+                    {
+                        title: '图片格式',
+                        align: "center",
+                        dataIndex: 'format'
+                    },
+                    {
+                        title: '图片Md5',
+                        align: "center",
+                        dataIndex: 'signature'
+                    },
+                    {
+                        title: 'status',
+                        align: "center",
+                        dataIndex: 'status'
+                    },
+                    {
+                        title: '操作',
+                        dataIndex: 'action',
+                        align: "center",
+                        scopedSlots: {customRender: 'action'},
+                    }
+                ],
+                url: {
+                    list: "/ctop/byteDanceImageInfo/list",
+                    delete: "/ctop/byteDanceImageInfo/delete",
+                    deleteBatch: "/ctop/byteDanceImageInfo/deleteBatch",
+                    exportXlsUrl: "ctop/byteDanceImageInfo/exportXls",
+                    importExcelUrl: "ctop/byteDanceImageInfo/importExcel",
+                },
+            }
+        },
+        computed: {
+            importExcelUrl: function () {
+                return `${window._CONFIG['domianURL']}/${this.url.importExcelUrl}`;
+            }
+        },
+        methods: {}
+    }
+</script>
+<style scoped>
+    @import '~@assets/less/common.less'
+</style>

+ 203 - 0
jeecg-boot-module-system/src/main/java/org/jeecg/modules/ctop/vue/ByteDanceVideoInfoList.vue

@@ -0,0 +1,203 @@
+<template>
+    <a-card :bordered="false">
+
+        <!-- 查询区域 -->
+        <div class="table-page-search-wrapper">
+            <a-form layout="inline">
+                <a-row :gutter="24">
+
+                    <a-col :md="6" :sm="8">
+                        <a-form-item label="对应本文件id">
+                            <a-input placeholder="请输入对应本文件id" v-model="queryParam.fileId"></a-input>
+                        </a-form-item>
+                    </a-col>
+                    <a-col :md="6" :sm="8">
+                        <a-form-item label="视频宽度">
+                            <a-input placeholder="请输入视频宽度" v-model="queryParam.width"></a-input>
+                        </a-form-item>
+                    </a-col>
+                    <template v-if="toggleSearchStatus">
+                        <a-col :md="6" :sm="8">
+                            <a-form-item label="视频高度">
+                                <a-input placeholder="请输入视频高度" v-model="queryParam.height"></a-input>
+                            </a-form-item>
+                        </a-col>
+                        <a-col :md="6" :sm="8">
+                            <a-form-item label="视频时长">
+                                <a-input placeholder="请输入视频时长" v-model="queryParam.duration"></a-input>
+                            </a-form-item>
+                        </a-col>
+                        <a-col :md="6" :sm="8">
+                            <a-form-item label="视频大小">
+                                <a-input placeholder="请输入视频大小" v-model="queryParam.size"></a-input>
+                            </a-form-item>
+                        </a-col>
+                    </template>
+                    <a-col :md="6" :sm="8">
+            <span style="float: left;overflow: hidden;" class="table-page-search-submitButtons">
+              <a-button type="primary" @click="searchQuery" icon="search">查询</a-button>
+              <a-button type="primary" @click="searchReset" icon="reload" style="margin-left: 8px">重置</a-button>
+              <a @click="handleToggleSearch" style="margin-left: 8px">
+                {{ toggleSearchStatus ? '收起' : '展开' }}
+                <a-icon :type="toggleSearchStatus ? 'up' : 'down'"/>
+              </a>
+            </span>
+                    </a-col>
+
+                </a-row>
+            </a-form>
+        </div>
+
+        <!-- 操作按钮区域 -->
+        <div class="table-operator">
+            <a-button @click="handleAdd" type="primary" icon="plus">新增</a-button>
+            <a-button type="primary" icon="download" @click="handleExportXls('今日头条视频素材信息')">导出</a-button>
+            <a-upload name="file" :showUploadList="false" :multiple="false" :headers="tokenHeader"
+                      :action="importExcelUrl" @change="handleImportExcel">
+                <a-button type="primary" icon="import">导入</a-button>
+            </a-upload>
+            <a-dropdown v-if="selectedRowKeys.length > 0">
+                <a-menu slot="overlay">
+                    <a-menu-item key="1" @click="batchDel">
+                        <a-icon type="delete"/>
+                        删除
+                    </a-menu-item>
+                </a-menu>
+                <a-button style="margin-left: 8px"> 批量操作
+                    <a-icon type="down"/>
+                </a-button>
+            </a-dropdown>
+        </div>
+
+        <!-- table区域-begin -->
+        <div>
+            <div class="ant-alert ant-alert-info" style="margin-bottom: 16px;">
+                <i class="anticon anticon-info-circle ant-alert-icon"></i> 已选择 <a style="font-weight: 600">{{
+                selectedRowKeys.length }}</a>项
+                <a style="margin-left: 24px" @click="onClearSelected">清空</a>
+            </div>
+
+            <a-table
+                    ref="table"
+                    size="middle"
+                    bordered
+                    rowKey="id"
+                    :columns="columns"
+                    :dataSource="dataSource"
+                    :pagination="ipagination"
+                    :loading="loading"
+                    :rowSelection="{selectedRowKeys: selectedRowKeys, onChange: onSelectChange}"
+                    @change="handleTableChange">
+
+        <span slot="action" slot-scope="text, record">
+          <a @click="handleEdit(record)">编辑</a>
+
+          <a-divider type="vertical"/>
+          <a-dropdown>
+            <a class="ant-dropdown-link">更多 <a-icon type="down"/></a>
+            <a-menu slot="overlay">
+              <a-menu-item>
+                <a-popconfirm title="确定删除吗?" @confirm="() => handleDelete(record.id)">
+                  <a>删除</a>
+                </a-popconfirm>
+              </a-menu-item>
+            </a-menu>
+          </a-dropdown>
+        </span>
+
+            </a-table>
+        </div>
+        <!-- table区域-end -->
+
+        <!-- 表单区域 -->
+        <byteDanceVideoInfo-modal ref="modalForm" @ok="modalFormOk"></byteDanceVideoInfo-modal>
+    </a-card>
+</template>
+
+<script>
+    import ByteDanceVideoInfoModal from './modules/ByteDanceVideoInfoModal'
+    import {JeecgListMixin} from '@/mixins/JeecgListMixin'
+
+    export default {
+        name: "ByteDanceVideoInfoList",
+        mixins: [JeecgListMixin],
+        components: {
+            ByteDanceVideoInfoModal
+        },
+        data() {
+            return {
+                description: '今日头条视频素材信息管理页面',
+                // 表头
+                columns: [
+                    {
+                        title: '#',
+                        dataIndex: '',
+                        key: 'rowIndex',
+                        width: 60,
+                        align: "center",
+                        customRender: function (t, r, index) {
+                            return parseInt(index) + 1;
+                        }
+                    },
+                    {
+                        title: '对应本文件id',
+                        align: "center",
+                        dataIndex: 'fileId'
+                    },
+                    {
+                        title: '视频宽度',
+                        align: "center",
+                        dataIndex: 'width'
+                    },
+                    {
+                        title: '视频高度',
+                        align: "center",
+                        dataIndex: 'height'
+                    },
+                    {
+                        title: '视频时长',
+                        align: "center",
+                        dataIndex: 'duration'
+                    },
+                    {
+                        title: '视频大小',
+                        align: "center",
+                        dataIndex: 'size'
+                    },
+                    {
+                        title: '视频地址',
+                        align: "center",
+                        dataIndex: 'videoUrl'
+                    },
+                    {
+                        title: 'status',
+                        align: "center",
+                        dataIndex: 'status'
+                    },
+                    {
+                        title: '操作',
+                        dataIndex: 'action',
+                        align: "center",
+                        scopedSlots: {customRender: 'action'},
+                    }
+                ],
+                url: {
+                    list: "/ctop/byteDanceVideoInfo/list",
+                    delete: "/ctop/byteDanceVideoInfo/delete",
+                    deleteBatch: "/ctop/byteDanceVideoInfo/deleteBatch",
+                    exportXlsUrl: "ctop/byteDanceVideoInfo/exportXls",
+                    importExcelUrl: "ctop/byteDanceVideoInfo/importExcel",
+                },
+            }
+        },
+        computed: {
+            importExcelUrl: function () {
+                return `${window._CONFIG['domianURL']}/${this.url.importExcelUrl}`;
+            }
+        },
+        methods: {}
+    }
+</script>
+<style scoped>
+    @import '~@assets/less/common.less'
+</style>

+ 154 - 0
jeecg-boot-module-system/src/main/java/org/jeecg/modules/ctop/vue/modules/BindAccountModal.vue

@@ -0,0 +1,154 @@
+<template>
+  <a-modal
+    :title="title"
+    :width="800"
+    :visible="visible"
+    :confirmLoading="confirmLoading"
+    @ok="handleOk"
+    @cancel="handleCancel"
+    cancelText="关闭">
+    
+    <a-spin :spinning="confirmLoading">
+      <a-form :form="form">
+      
+        <a-form-item
+          :labelCol="labelCol"
+          :wrapperCol="wrapperCol"
+          label="广告id">
+          <a-input placeholder="请输入广告id" v-decorator="['advertiserId', {}]" />
+        </a-form-item>
+        <a-form-item
+          :labelCol="labelCol"
+          :wrapperCol="wrapperCol"
+          label="账号">
+          <a-input placeholder="请输入账号" v-decorator="['accountName', {}]" />
+        </a-form-item>
+        <a-form-item
+          :labelCol="labelCol"
+          :wrapperCol="wrapperCol"
+          label="密码">
+          <a-input placeholder="请输入密码" v-decorator="['password', {}]" />
+        </a-form-item>
+        <a-form-item
+          :labelCol="labelCol"
+          :wrapperCol="wrapperCol"
+          label="登录/授权方式">
+          <a-input placeholder="请输入登录/授权方式" v-decorator="['loginType', {}]" />
+        </a-form-item>
+        <a-form-item
+          :labelCol="labelCol"
+          :wrapperCol="wrapperCol"
+          label="方式:登录或授权">
+          <a-input placeholder="请输入方式:登录或授权" v-decorator="['type', {}]" />
+        </a-form-item>
+        <a-form-item
+          :labelCol="labelCol"
+          :wrapperCol="wrapperCol"
+          label="回调返回广告主id">
+          <a-input placeholder="请输入回调返回广告主id" v-decorator="['accountId', {}]" />
+        </a-form-item>
+		
+      </a-form>
+    </a-spin>
+  </a-modal>
+</template>
+
+<script>
+  import { httpAction } from '@/api/manage'
+  import pick from 'lodash.pick'
+  import moment from "moment"
+
+  export default {
+    name: "BindAccountModal",
+    data () {
+      return {
+        title:"操作",
+        visible: false,
+        model: {},
+        labelCol: {
+          xs: { span: 24 },
+          sm: { span: 5 },
+        },
+        wrapperCol: {
+          xs: { span: 24 },
+          sm: { span: 16 },
+        },
+
+        confirmLoading: false,
+        form: this.$form.createForm(this),
+        validatorRules:{
+        },
+        url: {
+          add: "/ctop/bindAccount/add",
+          edit: "/ctop/bindAccount/edit",
+        },
+      }
+    },
+    created () {
+    },
+    methods: {
+      add () {
+        this.edit({});
+      },
+      edit (record) {
+        this.form.resetFields();
+        this.model = Object.assign({}, record);
+        this.visible = true;
+        this.$nextTick(() => {
+          this.form.setFieldsValue(pick(this.model,'advertiserId','accountName','password','loginType','type','accountId'))
+		  //时间格式化
+        });
+
+      },
+      close () {
+        this.$emit('close');
+        this.visible = false;
+      },
+      handleOk () {
+        const that = this;
+        // 触发表单验证
+        this.form.validateFields((err, values) => {
+          if (!err) {
+            that.confirmLoading = true;
+            let httpurl = '';
+            let method = '';
+            if(!this.model.id){
+              httpurl+=this.url.add;
+              method = 'post';
+            }else{
+              httpurl+=this.url.edit;
+               method = 'put';
+            }
+            let formData = Object.assign(this.model, values);
+            //时间格式化
+            
+            console.log(formData)
+            httpAction(httpurl,formData,method).then((res)=>{
+              if(res.success){
+                that.$message.success(res.message);
+                that.$emit('ok');
+              }else{
+                that.$message.warning(res.message);
+              }
+            }).finally(() => {
+              that.confirmLoading = false;
+              that.close();
+            })
+
+
+
+          }
+        })
+      },
+      handleCancel () {
+        this.close()
+      },
+
+
+    }
+  }
+</script>
+
+<style lang="less" scoped>
+
+</style>

+ 161 - 0
jeecg-boot-module-system/src/main/java/org/jeecg/modules/ctop/vue/modules/BindAccountModal__Style#Drawer.vue

@@ -0,0 +1,161 @@
+<template>
+  <a-drawer
+      :title="title"
+      :width="800"
+      placement="right"
+      :closable="false"
+      @close="close"
+      :visible="visible"
+  >
+
+    <a-spin :spinning="confirmLoading">
+      <a-form :form="form">
+      
+        <a-form-item
+          :labelCol="labelCol"
+          :wrapperCol="wrapperCol"
+          label="广告id">
+          <a-input placeholder="请输入广告id" v-decorator="['advertiserId', {}]" />
+        </a-form-item>
+        <a-form-item
+          :labelCol="labelCol"
+          :wrapperCol="wrapperCol"
+          label="账号">
+          <a-input placeholder="请输入账号" v-decorator="['accountName', {}]" />
+        </a-form-item>
+        <a-form-item
+          :labelCol="labelCol"
+          :wrapperCol="wrapperCol"
+          label="密码">
+          <a-input placeholder="请输入密码" v-decorator="['password', {}]" />
+        </a-form-item>
+        <a-form-item
+          :labelCol="labelCol"
+          :wrapperCol="wrapperCol"
+          label="登录/授权方式">
+          <a-input placeholder="请输入登录/授权方式" v-decorator="['loginType', {}]" />
+        </a-form-item>
+        <a-form-item
+          :labelCol="labelCol"
+          :wrapperCol="wrapperCol"
+          label="方式:登录或授权">
+          <a-input placeholder="请输入方式:登录或授权" v-decorator="['type', {}]" />
+        </a-form-item>
+        <a-form-item
+          :labelCol="labelCol"
+          :wrapperCol="wrapperCol"
+          label="回调返回广告主id">
+          <a-input placeholder="请输入回调返回广告主id" v-decorator="['accountId', {}]" />
+        </a-form-item>
+		
+      </a-form>
+    </a-spin>
+    <a-button type="primary" @click="handleOk">确定</a-button>
+    <a-button type="primary" @click="handleCancel">取消</a-button>
+  </a-drawer>
+</template>
+
+<script>
+  import { httpAction } from '@/api/manage'
+  import pick from 'lodash.pick'
+  import moment from "moment"
+
+  export default {
+    name: "BindAccountModal",
+    data () {
+      return {
+        title:"操作",
+        visible: false,
+        model: {},
+        labelCol: {
+          xs: { span: 24 },
+          sm: { span: 5 },
+        },
+        wrapperCol: {
+          xs: { span: 24 },
+          sm: { span: 16 },
+        },
+
+        confirmLoading: false,
+        form: this.$form.createForm(this),
+        validatorRules:{
+        },
+        url: {
+          add: "/ctop/bindAccount/add",
+          edit: "/ctop/bindAccount/edit",
+        },
+      }
+    },
+    created () {
+    },
+    methods: {
+      add () {
+        this.edit({});
+      },
+      edit (record) {
+        this.form.resetFields();
+        this.model = Object.assign({}, record);
+        this.visible = true;
+        this.$nextTick(() => {
+          this.form.setFieldsValue(pick(this.model,'advertiserId','accountName','password','loginType','type','accountId'))
+		  //时间格式化
+        });
+
+      },
+      close () {
+        this.$emit('close');
+        this.visible = false;
+      },
+      handleOk () {
+        const that = this;
+        // 触发表单验证
+        this.form.validateFields((err, values) => {
+          if (!err) {
+            that.confirmLoading = true;
+            let httpurl = '';
+            let method = '';
+            if(!this.model.id){
+              httpurl+=this.url.add;
+              method = 'post';
+            }else{
+              httpurl+=this.url.edit;
+               method = 'put';
+            }
+            let formData = Object.assign(this.model, values);
+            //时间格式化
+            
+            console.log(formData)
+            httpAction(httpurl,formData,method).then((res)=>{
+              if(res.success){
+                that.$message.success(res.message);
+                that.$emit('ok');
+              }else{
+                that.$message.warning(res.message);
+              }
+            }).finally(() => {
+              that.confirmLoading = false;
+              that.close();
+            })
+
+
+
+          }
+        })
+      },
+      handleCancel () {
+        this.close()
+      },
+
+
+    }
+  }
+</script>
+
+<style lang="less" scoped>
+/** Button按钮间距 */
+  .ant-btn {
+    margin-left: 30px;
+    margin-bottom: 30px;
+    float: right;
+  }
+</style>

+ 170 - 0
jeecg-boot-module-system/src/main/java/org/jeecg/modules/ctop/vue/modules/ByteDanceImageInfoModal.vue

@@ -0,0 +1,170 @@
+<template>
+    <a-modal
+            :title="title"
+            :width="800"
+            :visible="visible"
+            :confirmLoading="confirmLoading"
+            @ok="handleOk"
+            @cancel="handleCancel"
+            cancelText="关闭">
+
+        <a-spin :spinning="confirmLoading">
+            <a-form :form="form">
+
+                <a-form-item
+                        :labelCol="labelCol"
+                        :wrapperCol="wrapperCol"
+                        label="文件id">
+                    <a-input placeholder="请输入文件id" v-decorator="['fileId', {}]"/>
+                </a-form-item>
+                <a-form-item
+                        :labelCol="labelCol"
+                        :wrapperCol="wrapperCol"
+                        label="头条平台账号id">
+                    <a-input placeholder="请输入头条平台账号id" v-decorator="['accountId', {}]"/>
+                </a-form-item>
+                <a-form-item
+                        :labelCol="labelCol"
+                        :wrapperCol="wrapperCol"
+                        label="图片大小">
+                    <a-input placeholder="请输入图片大小" v-decorator="['size', {}]"/>
+                </a-form-item>
+                <a-form-item
+                        :labelCol="labelCol"
+                        :wrapperCol="wrapperCol"
+                        label="图片宽度">
+                    <a-input-number v-decorator="[ 'width', {}]"/>
+                </a-form-item>
+                <a-form-item
+                        :labelCol="labelCol"
+                        :wrapperCol="wrapperCol"
+                        label="图片高度">
+                    <a-input-number v-decorator="[ 'height', {}]"/>
+                </a-form-item>
+                <a-form-item
+                        :labelCol="labelCol"
+                        :wrapperCol="wrapperCol"
+                        label="预览地址">
+                    <a-input placeholder="请输入预览地址" v-decorator="['url', {}]"/>
+                </a-form-item>
+                <a-form-item
+                        :labelCol="labelCol"
+                        :wrapperCol="wrapperCol"
+                        label="图片格式">
+                    <a-input placeholder="请输入图片格式" v-decorator="['format', {}]"/>
+                </a-form-item>
+                <a-form-item
+                        :labelCol="labelCol"
+                        :wrapperCol="wrapperCol"
+                        label="图片Md5">
+                    <a-input placeholder="请输入图片Md5" v-decorator="['signature', {}]"/>
+                </a-form-item>
+                <a-form-item
+                        :labelCol="labelCol"
+                        :wrapperCol="wrapperCol"
+                        label="status">
+                    <a-input-number v-decorator="[ 'status', {}]"/>
+                </a-form-item>
+
+            </a-form>
+        </a-spin>
+    </a-modal>
+</template>
+
+<script>
+    import {httpAction} from '@/api/manage'
+    import pick from 'lodash.pick'
+    import moment from "moment"
+
+    export default {
+        name: "ByteDanceImageInfoModal",
+        data() {
+            return {
+                title: "操作",
+                visible: false,
+                model: {},
+                labelCol: {
+                    xs: {span: 24},
+                    sm: {span: 5},
+                },
+                wrapperCol: {
+                    xs: {span: 24},
+                    sm: {span: 16},
+                },
+
+                confirmLoading: false,
+                form: this.$form.createForm(this),
+                validatorRules: {},
+                url: {
+                    add: "/ctop/byteDanceImageInfo/add",
+                    edit: "/ctop/byteDanceImageInfo/edit",
+                },
+            }
+        },
+        created() {
+        },
+        methods: {
+            add() {
+                this.edit({});
+            },
+            edit(record) {
+                this.form.resetFields();
+                this.model = Object.assign({}, record);
+                this.visible = true;
+                this.$nextTick(() => {
+                    this.form.setFieldsValue(pick(this.model, 'fileId', 'accountId', 'size', 'width', 'height', 'url', 'format', 'signature', 'status'))
+                    //时间格式化
+                });
+
+            },
+            close() {
+                this.$emit('close');
+                this.visible = false;
+            },
+            handleOk() {
+                const that = this;
+                // 触发表单验证
+                this.form.validateFields((err, values) => {
+                    if (!err) {
+                        that.confirmLoading = true;
+                        let httpurl = '';
+                        let method = '';
+                        if (!this.model.id) {
+                            httpurl += this.url.add;
+                            method = 'post';
+                        } else {
+                            httpurl += this.url.edit;
+                            method = 'put';
+                        }
+                        let formData = Object.assign(this.model, values);
+                        //时间格式化
+
+                        console.log(formData)
+                        httpAction(httpurl, formData, method).then((res) => {
+                            if (res.success) {
+                                that.$message.success(res.message);
+                                that.$emit('ok');
+                            } else {
+                                that.$message.warning(res.message);
+                            }
+                        }).finally(() => {
+                            that.confirmLoading = false;
+                            that.close();
+                        })
+
+
+                    }
+                })
+            },
+            handleCancel() {
+                this.close()
+            },
+
+
+        }
+    }
+</script>
+
+<style lang="less" scoped>
+
+</style>

+ 177 - 0
jeecg-boot-module-system/src/main/java/org/jeecg/modules/ctop/vue/modules/ByteDanceImageInfoModal__Style#Drawer.vue

@@ -0,0 +1,177 @@
+<template>
+    <a-drawer
+            :title="title"
+            :width="800"
+            placement="right"
+            :closable="false"
+            @close="close"
+            :visible="visible"
+    >
+
+        <a-spin :spinning="confirmLoading">
+            <a-form :form="form">
+
+                <a-form-item
+                        :labelCol="labelCol"
+                        :wrapperCol="wrapperCol"
+                        label="文件id">
+                    <a-input placeholder="请输入文件id" v-decorator="['fileId', {}]"/>
+                </a-form-item>
+                <a-form-item
+                        :labelCol="labelCol"
+                        :wrapperCol="wrapperCol"
+                        label="头条平台账号id">
+                    <a-input placeholder="请输入头条平台账号id" v-decorator="['accountId', {}]"/>
+                </a-form-item>
+                <a-form-item
+                        :labelCol="labelCol"
+                        :wrapperCol="wrapperCol"
+                        label="图片大小">
+                    <a-input placeholder="请输入图片大小" v-decorator="['size', {}]"/>
+                </a-form-item>
+                <a-form-item
+                        :labelCol="labelCol"
+                        :wrapperCol="wrapperCol"
+                        label="图片宽度">
+                    <a-input-number v-decorator="[ 'width', {}]"/>
+                </a-form-item>
+                <a-form-item
+                        :labelCol="labelCol"
+                        :wrapperCol="wrapperCol"
+                        label="图片高度">
+                    <a-input-number v-decorator="[ 'height', {}]"/>
+                </a-form-item>
+                <a-form-item
+                        :labelCol="labelCol"
+                        :wrapperCol="wrapperCol"
+                        label="预览地址">
+                    <a-input placeholder="请输入预览地址" v-decorator="['url', {}]"/>
+                </a-form-item>
+                <a-form-item
+                        :labelCol="labelCol"
+                        :wrapperCol="wrapperCol"
+                        label="图片格式">
+                    <a-input placeholder="请输入图片格式" v-decorator="['format', {}]"/>
+                </a-form-item>
+                <a-form-item
+                        :labelCol="labelCol"
+                        :wrapperCol="wrapperCol"
+                        label="图片Md5">
+                    <a-input placeholder="请输入图片Md5" v-decorator="['signature', {}]"/>
+                </a-form-item>
+                <a-form-item
+                        :labelCol="labelCol"
+                        :wrapperCol="wrapperCol"
+                        label="status">
+                    <a-input-number v-decorator="[ 'status', {}]"/>
+                </a-form-item>
+
+            </a-form>
+        </a-spin>
+        <a-button type="primary" @click="handleOk">确定</a-button>
+        <a-button type="primary" @click="handleCancel">取消</a-button>
+    </a-drawer>
+</template>
+
+<script>
+    import {httpAction} from '@/api/manage'
+    import pick from 'lodash.pick'
+    import moment from "moment"
+
+    export default {
+        name: "ByteDanceImageInfoModal",
+        data() {
+            return {
+                title: "操作",
+                visible: false,
+                model: {},
+                labelCol: {
+                    xs: {span: 24},
+                    sm: {span: 5},
+                },
+                wrapperCol: {
+                    xs: {span: 24},
+                    sm: {span: 16},
+                },
+
+                confirmLoading: false,
+                form: this.$form.createForm(this),
+                validatorRules: {},
+                url: {
+                    add: "/ctop/byteDanceImageInfo/add",
+                    edit: "/ctop/byteDanceImageInfo/edit",
+                },
+            }
+        },
+        created() {
+        },
+        methods: {
+            add() {
+                this.edit({});
+            },
+            edit(record) {
+                this.form.resetFields();
+                this.model = Object.assign({}, record);
+                this.visible = true;
+                this.$nextTick(() => {
+                    this.form.setFieldsValue(pick(this.model, 'fileId', 'accountId', 'size', 'width', 'height', 'url', 'format', 'signature', 'status'))
+                    //时间格式化
+                });
+
+            },
+            close() {
+                this.$emit('close');
+                this.visible = false;
+            },
+            handleOk() {
+                const that = this;
+                // 触发表单验证
+                this.form.validateFields((err, values) => {
+                    if (!err) {
+                        that.confirmLoading = true;
+                        let httpurl = '';
+                        let method = '';
+                        if (!this.model.id) {
+                            httpurl += this.url.add;
+                            method = 'post';
+                        } else {
+                            httpurl += this.url.edit;
+                            method = 'put';
+                        }
+                        let formData = Object.assign(this.model, values);
+                        //时间格式化
+
+                        console.log(formData)
+                        httpAction(httpurl, formData, method).then((res) => {
+                            if (res.success) {
+                                that.$message.success(res.message);
+                                that.$emit('ok');
+                            } else {
+                                that.$message.warning(res.message);
+                            }
+                        }).finally(() => {
+                            that.confirmLoading = false;
+                            that.close();
+                        })
+
+
+                    }
+                })
+            },
+            handleCancel() {
+                this.close()
+            },
+
+
+        }
+    }
+</script>
+
+<style lang="less" scoped>
+    /** Button按钮间距 */
+    .ant-btn {
+        margin-left: 30px;
+        margin-bottom: 30px;
+        float: right;
+    }
+</style>

+ 158 - 0
jeecg-boot-module-system/src/main/java/org/jeecg/modules/ctop/vue/modules/ByteDanceVideoInfoModal.vue

@@ -0,0 +1,158 @@
+<template>
+    <a-modal
+            :title="title"
+            :width="800"
+            :visible="visible"
+            :confirmLoading="confirmLoading"
+            @ok="handleOk"
+            @cancel="handleCancel"
+            cancelText="关闭">
+
+        <a-spin :spinning="confirmLoading">
+            <a-form :form="form">
+
+                <a-form-item
+                        :labelCol="labelCol"
+                        :wrapperCol="wrapperCol"
+                        label="对应本文件id">
+                    <a-input placeholder="请输入对应本文件id" v-decorator="['fileId', {}]"/>
+                </a-form-item>
+                <a-form-item
+                        :labelCol="labelCol"
+                        :wrapperCol="wrapperCol"
+                        label="视频宽度">
+                    <a-input-number v-decorator="[ 'width', {}]"/>
+                </a-form-item>
+                <a-form-item
+                        :labelCol="labelCol"
+                        :wrapperCol="wrapperCol"
+                        label="视频高度">
+                    <a-input-number v-decorator="[ 'height', {}]"/>
+                </a-form-item>
+                <a-form-item
+                        :labelCol="labelCol"
+                        :wrapperCol="wrapperCol"
+                        label="视频时长">
+                    <a-input-number v-decorator="[ 'duration', {}]"/>
+                </a-form-item>
+                <a-form-item
+                        :labelCol="labelCol"
+                        :wrapperCol="wrapperCol"
+                        label="视频大小">
+                    <a-input placeholder="请输入视频大小" v-decorator="['size', {}]"/>
+                </a-form-item>
+                <a-form-item
+                        :labelCol="labelCol"
+                        :wrapperCol="wrapperCol"
+                        label="视频地址">
+                    <a-input placeholder="请输入视频地址" v-decorator="['videoUrl', {}]"/>
+                </a-form-item>
+                <a-form-item
+                        :labelCol="labelCol"
+                        :wrapperCol="wrapperCol"
+                        label="status">
+                    <a-input-number v-decorator="[ 'status', {}]"/>
+                </a-form-item>
+
+            </a-form>
+        </a-spin>
+    </a-modal>
+</template>
+
+<script>
+    import {httpAction} from '@/api/manage'
+    import pick from 'lodash.pick'
+    import moment from "moment"
+
+    export default {
+        name: "ByteDanceVideoInfoModal",
+        data() {
+            return {
+                title: "操作",
+                visible: false,
+                model: {},
+                labelCol: {
+                    xs: {span: 24},
+                    sm: {span: 5},
+                },
+                wrapperCol: {
+                    xs: {span: 24},
+                    sm: {span: 16},
+                },
+
+                confirmLoading: false,
+                form: this.$form.createForm(this),
+                validatorRules: {},
+                url: {
+                    add: "/ctop/byteDanceVideoInfo/add",
+                    edit: "/ctop/byteDanceVideoInfo/edit",
+                },
+            }
+        },
+        created() {
+        },
+        methods: {
+            add() {
+                this.edit({});
+            },
+            edit(record) {
+                this.form.resetFields();
+                this.model = Object.assign({}, record);
+                this.visible = true;
+                this.$nextTick(() => {
+                    this.form.setFieldsValue(pick(this.model, 'fileId', 'width', 'height', 'duration', 'size', 'videoUrl', 'status'))
+                    //时间格式化
+                });
+
+            },
+            close() {
+                this.$emit('close');
+                this.visible = false;
+            },
+            handleOk() {
+                const that = this;
+                // 触发表单验证
+                this.form.validateFields((err, values) => {
+                    if (!err) {
+                        that.confirmLoading = true;
+                        let httpurl = '';
+                        let method = '';
+                        if (!this.model.id) {
+                            httpurl += this.url.add;
+                            method = 'post';
+                        } else {
+                            httpurl += this.url.edit;
+                            method = 'put';
+                        }
+                        let formData = Object.assign(this.model, values);
+                        //时间格式化
+
+                        console.log(formData)
+                        httpAction(httpurl, formData, method).then((res) => {
+                            if (res.success) {
+                                that.$message.success(res.message);
+                                that.$emit('ok');
+                            } else {
+                                that.$message.warning(res.message);
+                            }
+                        }).finally(() => {
+                            that.confirmLoading = false;
+                            that.close();
+                        })
+
+
+                    }
+                })
+            },
+            handleCancel() {
+                this.close()
+            },
+
+
+        }
+    }
+</script>
+
+<style lang="less" scoped>
+
+</style>

+ 165 - 0
jeecg-boot-module-system/src/main/java/org/jeecg/modules/ctop/vue/modules/ByteDanceVideoInfoModal__Style#Drawer.vue

@@ -0,0 +1,165 @@
+<template>
+    <a-drawer
+            :title="title"
+            :width="800"
+            placement="right"
+            :closable="false"
+            @close="close"
+            :visible="visible"
+    >
+
+        <a-spin :spinning="confirmLoading">
+            <a-form :form="form">
+
+                <a-form-item
+                        :labelCol="labelCol"
+                        :wrapperCol="wrapperCol"
+                        label="对应本文件id">
+                    <a-input placeholder="请输入对应本文件id" v-decorator="['fileId', {}]"/>
+                </a-form-item>
+                <a-form-item
+                        :labelCol="labelCol"
+                        :wrapperCol="wrapperCol"
+                        label="视频宽度">
+                    <a-input-number v-decorator="[ 'width', {}]"/>
+                </a-form-item>
+                <a-form-item
+                        :labelCol="labelCol"
+                        :wrapperCol="wrapperCol"
+                        label="视频高度">
+                    <a-input-number v-decorator="[ 'height', {}]"/>
+                </a-form-item>
+                <a-form-item
+                        :labelCol="labelCol"
+                        :wrapperCol="wrapperCol"
+                        label="视频时长">
+                    <a-input-number v-decorator="[ 'duration', {}]"/>
+                </a-form-item>
+                <a-form-item
+                        :labelCol="labelCol"
+                        :wrapperCol="wrapperCol"
+                        label="视频大小">
+                    <a-input placeholder="请输入视频大小" v-decorator="['size', {}]"/>
+                </a-form-item>
+                <a-form-item
+                        :labelCol="labelCol"
+                        :wrapperCol="wrapperCol"
+                        label="视频地址">
+                    <a-input placeholder="请输入视频地址" v-decorator="['videoUrl', {}]"/>
+                </a-form-item>
+                <a-form-item
+                        :labelCol="labelCol"
+                        :wrapperCol="wrapperCol"
+                        label="status">
+                    <a-input-number v-decorator="[ 'status', {}]"/>
+                </a-form-item>
+
+            </a-form>
+        </a-spin>
+        <a-button type="primary" @click="handleOk">确定</a-button>
+        <a-button type="primary" @click="handleCancel">取消</a-button>
+    </a-drawer>
+</template>
+
+<script>
+    import {httpAction} from '@/api/manage'
+    import pick from 'lodash.pick'
+    import moment from "moment"
+
+    export default {
+        name: "ByteDanceVideoInfoModal",
+        data() {
+            return {
+                title: "操作",
+                visible: false,
+                model: {},
+                labelCol: {
+                    xs: {span: 24},
+                    sm: {span: 5},
+                },
+                wrapperCol: {
+                    xs: {span: 24},
+                    sm: {span: 16},
+                },
+
+                confirmLoading: false,
+                form: this.$form.createForm(this),
+                validatorRules: {},
+                url: {
+                    add: "/ctop/byteDanceVideoInfo/add",
+                    edit: "/ctop/byteDanceVideoInfo/edit",
+                },
+            }
+        },
+        created() {
+        },
+        methods: {
+            add() {
+                this.edit({});
+            },
+            edit(record) {
+                this.form.resetFields();
+                this.model = Object.assign({}, record);
+                this.visible = true;
+                this.$nextTick(() => {
+                    this.form.setFieldsValue(pick(this.model, 'fileId', 'width', 'height', 'duration', 'size', 'videoUrl', 'status'))
+                    //时间格式化
+                });
+
+            },
+            close() {
+                this.$emit('close');
+                this.visible = false;
+            },
+            handleOk() {
+                const that = this;
+                // 触发表单验证
+                this.form.validateFields((err, values) => {
+                    if (!err) {
+                        that.confirmLoading = true;
+                        let httpurl = '';
+                        let method = '';
+                        if (!this.model.id) {
+                            httpurl += this.url.add;
+                            method = 'post';
+                        } else {
+                            httpurl += this.url.edit;
+                            method = 'put';
+                        }
+                        let formData = Object.assign(this.model, values);
+                        //时间格式化
+
+                        console.log(formData)
+                        httpAction(httpurl, formData, method).then((res) => {
+                            if (res.success) {
+                                that.$message.success(res.message);
+                                that.$emit('ok');
+                            } else {
+                                that.$message.warning(res.message);
+                            }
+                        }).finally(() => {
+                            that.confirmLoading = false;
+                            that.close();
+                        })
+
+
+                    }
+                })
+            },
+            handleCancel() {
+                this.close()
+            },
+
+
+        }
+    }
+</script>
+
+<style lang="less" scoped>
+    /** Button按钮间距 */
+    .ant-btn {
+        margin-left: 30px;
+        margin-bottom: 30px;
+        float: right;
+    }
+</style>

+ 1 - 1
jeecg-boot-module-system/src/main/java/org/jeecg/modules/kuaishou/service/impl/KuaishouInterfaceServiceImpl.java

@@ -721,7 +721,7 @@ public class KuaishouInterfaceServiceImpl implements IKuaishouInterfaceService {
 
 
         KuaishouResultToken kuaiShouResult = null;
         KuaishouResultToken kuaiShouResult = null;
         try {
         try {
-            String result = HttpUtils.kuaiShouhttpPostRequest(url, requestJson.toJSONString(), null);
+            String result = HttpUtils.kuaiShouhttpPostRequest(url, requestJson.toJSONString(), headers);
             ObjectMapper mapper = new ObjectMapper();
             ObjectMapper mapper = new ObjectMapper();
             mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
             mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
             kuaiShouResult = mapper.readValue(result, new TypeReference<KuaishouResultToken>() {
             kuaiShouResult = mapper.readValue(result, new TypeReference<KuaishouResultToken>() {

+ 26 - 0
module-common/src/main/java/cn/com/ctop/common/utils/MD5Utils.java

@@ -1,5 +1,9 @@
 package cn.com.ctop.common.utils;
 package cn.com.ctop.common.utils;
 
 
+import org.apache.commons.io.FileUtils;
+
+import java.io.File;
+import java.io.IOException;
 import java.security.MessageDigest;
 import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
 import java.security.NoSuchAlgorithmException;
 
 
@@ -35,4 +39,26 @@ public class MD5Utils {
 		}
 		}
 		return String.valueOf(str);
 		return String.valueOf(str);
 	}
 	}
+
+    public static String getFileMD5(String path) {
+        StringBuffer sb = new StringBuffer();
+        try {
+            MessageDigest md = MessageDigest.getInstance("MD5");
+            byte[] b = md.digest(FileUtils.readFileToByteArray(new File(path)));
+            for (int i = 0; i < b.length; i++) {
+                int d = b[i];
+                if (d < 0) {
+                    d += 256;
+                }
+                int d1 = d / 16;
+                int d2 = d % 16;
+                sb.append(hexDigits[d1] + hexDigits[d2]);
+            }
+        } catch (NoSuchAlgorithmException e) {
+            e.printStackTrace();
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+        return sb.toString();
+    }
 }
 }

+ 6 - 0
module-kuaishou/src/main/java/constant/KuaishouInterfaceConstant.java

@@ -24,4 +24,10 @@ public class KuaishouInterfaceConstant {
     public static final String APP_LIST = "/rest/openapi/v1/file/ad/app/list"; //创建广告获取应用列表
     public static final String APP_LIST = "/rest/openapi/v1/file/ad/app/list"; //创建广告获取应用列表
 
 
 
 
+    public static final String TYPE_LOGIN = "login"; //登录
+    public static final String TYPE_AUTHORIZATION = "authorization"; //授权
+    public static final String LOGIN_TYPE_KUAISHOU = "kuaishou"; //登录方式-快手
+    public static final String LOGIN_TYPE_BYTEDANCE = "bytedance"; //登录方式-快手
+
+
 }
 }

+ 5 - 1
module-toutiao/src/main/resources/bytedance_config.properties

@@ -10,6 +10,7 @@ bytedance_auth_url=https://ad.toutiao.com/openapi
 bytedance_callback_url=http://callback.c-top.com.cn/bytedance
 bytedance_callback_url=http://callback.c-top.com.cn/bytedance
 bytedance_v2_advertiser_info=/2/advertiser/info
 bytedance_v2_advertiser_info=/2/advertiser/info
 bytedance_v2_ad_get=/2/ad/get
 bytedance_v2_ad_get=/2/ad/get
+bytedance_v2_ad_create=/2/ad/create/
 bytedance_v2_ad_update_status=/2/ad/update/status
 bytedance_v2_ad_update_status=/2/ad/update/status
 bytedance_v2_ad_update_bid=/2/ad/update/bid
 bytedance_v2_ad_update_bid=/2/ad/update/bid
 bytedance_v2_ad_update_budget=/2/ad/update/budget
 bytedance_v2_ad_update_budget=/2/ad/update/budget
@@ -18,6 +19,9 @@ bytedance_v2_campaign_create=/2/campaign/create/
 bytedance_v2_campaign_update_status=/2/campaign/update/status
 bytedance_v2_campaign_update_status=/2/campaign/update/status
 bytedance_v2_campaign_update=/2/campaign/update
 bytedance_v2_campaign_update=/2/campaign/update
 bytedance_v2_dmp_custom_audience_select=/2/dmp/custom_audience/select/
 bytedance_v2_dmp_custom_audience_select=/2/dmp/custom_audience/select/
+bytedance_v2_file_video_ad=/2/file/video/ad/
+bytedance_v2_file_image_ad=/2/file/image/ad/
 
 
 bytedance_v2_creative_update_status=/2/creative/update/status/
 bytedance_v2_creative_update_status=/2/creative/update/status/
-bytedance_v2_creative_material_get=/2/creative/material/read
+bytedance_v2_creative_material_get=/2/creative/material/read
+bytedance_v2_creative_create_v2=/2/creative/create_v2/