Browse Source

Youtube和Linkedin营销效果数据功能完善联调测试通过

Jack 10 months ago
parent
commit
af07a33d79
23 changed files with 1540 additions and 30 deletions
  1. 35 26
      .idea/workspace.xml
  2. 276 0
      jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/okki/linkedin/controller/OkkiLinkedinMarketingDataController.java
  3. 59 0
      jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/okki/linkedin/entity/OkkiLinkedinMarketingData.java
  4. 64 0
      jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/okki/linkedin/entity/OkkiLinkedinMarketingDataDetail.java
  5. 32 0
      jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/okki/linkedin/mapper/OkkiLinkedinMarketingDataDetailMapper.java
  6. 14 0
      jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/okki/linkedin/mapper/OkkiLinkedinMarketingDataMapper.java
  7. 16 0
      jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/okki/linkedin/mapper/xml/OkkiLinkedinMarketingDataDetailMapper.xml
  8. 5 0
      jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/okki/linkedin/mapper/xml/OkkiLinkedinMarketingDataMapper.xml
  9. 13 0
      jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/okki/linkedin/param/LinkedinMarketingDataParam.java
  10. 15 0
      jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/okki/linkedin/param/LinkedinReportListParam.java
  11. 22 0
      jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/okki/linkedin/service/IOkkiLinkedinMarketingDataDetailService.java
  12. 49 0
      jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/okki/linkedin/service/IOkkiLinkedinMarketingDataService.java
  13. 28 0
      jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/okki/linkedin/service/impl/OkkiLinkedinMarketingDataDetailServiceImpl.java
  14. 141 0
      jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/okki/linkedin/service/impl/OkkiLinkedinMarketingDataServiceImpl.java
  15. 59 0
      jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/okki/linkedin/vo/OkkiLinkedinMarketingDataPage.java
  16. 1 1
      jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/okki/showlist/service/impl/OkkiShowlistServiceImpl.java
  17. 3 3
      jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/application-dev.yml
  18. 71 0
      jeecgboot-vue3/src/views/okki/linkedin/OkkiLinkedinMarketingData.api.ts
  19. 95 0
      jeecgboot-vue3/src/views/okki/linkedin/OkkiLinkedinMarketingData.data.ts
  20. 187 0
      jeecgboot-vue3/src/views/okki/linkedin/OkkiLinkedinMarketingDataList.vue
  21. 26 0
      jeecgboot-vue3/src/views/okki/linkedin/V20240516_1__menu_insert_OkkiLinkedinMarketingData.sql
  22. 171 0
      jeecgboot-vue3/src/views/okki/linkedin/components/OkkiLinkedinMarketingDataForm.vue
  23. 158 0
      jeecgboot-vue3/src/views/okki/linkedin/components/OkkiLinkedinMarketingDataModal.vue

+ 35 - 26
.idea/workspace.xml

@@ -5,28 +5,29 @@
   </component>
   <component name="ChangeListManager">
     <list default="true" id="ed63665b-8c5d-41ac-a75b-7a0cfc2d6ec5" name="Default Changelist" comment="网站质量检查结果功能完善联调测试通过">
-      <change afterPath="$PROJECT_DIR$/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/okki/youtube/controller/OkkiYoutubeMarketingDataController.java" afterDir="false" />
-      <change afterPath="$PROJECT_DIR$/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/okki/youtube/entity/OkkiYoutubeMarketingData.java" afterDir="false" />
-      <change afterPath="$PROJECT_DIR$/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/okki/youtube/entity/OkkiYoutubeMarketingDataDetail.java" afterDir="false" />
-      <change afterPath="$PROJECT_DIR$/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/okki/youtube/mapper/OkkiYoutubeMarketingDataDetailMapper.java" afterDir="false" />
-      <change afterPath="$PROJECT_DIR$/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/okki/youtube/mapper/OkkiYoutubeMarketingDataMapper.java" afterDir="false" />
-      <change afterPath="$PROJECT_DIR$/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/okki/youtube/mapper/xml/OkkiYoutubeMarketingDataDetailMapper.xml" afterDir="false" />
-      <change afterPath="$PROJECT_DIR$/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/okki/youtube/mapper/xml/OkkiYoutubeMarketingDataMapper.xml" afterDir="false" />
-      <change afterPath="$PROJECT_DIR$/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/okki/youtube/param/ReportListParam.java" afterDir="false" />
-      <change afterPath="$PROJECT_DIR$/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/okki/youtube/param/YoutubeMarketingDataParam.java" afterDir="false" />
-      <change afterPath="$PROJECT_DIR$/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/okki/youtube/service/IOkkiYoutubeMarketingDataDetailService.java" afterDir="false" />
-      <change afterPath="$PROJECT_DIR$/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/okki/youtube/service/IOkkiYoutubeMarketingDataService.java" afterDir="false" />
-      <change afterPath="$PROJECT_DIR$/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/okki/youtube/service/impl/OkkiYoutubeMarketingDataDetailServiceImpl.java" afterDir="false" />
-      <change afterPath="$PROJECT_DIR$/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/okki/youtube/service/impl/OkkiYoutubeMarketingDataServiceImpl.java" afterDir="false" />
-      <change afterPath="$PROJECT_DIR$/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/okki/youtube/vo/OkkiYoutubeMarketingDataPage.java" afterDir="false" />
-      <change afterPath="$PROJECT_DIR$/jeecgboot-vue3/src/views/okki/youtube/OkkiYoutubeMarketingData.api.ts" afterDir="false" />
-      <change afterPath="$PROJECT_DIR$/jeecgboot-vue3/src/views/okki/youtube/OkkiYoutubeMarketingData.data.ts" afterDir="false" />
-      <change afterPath="$PROJECT_DIR$/jeecgboot-vue3/src/views/okki/youtube/OkkiYoutubeMarketingDataList.vue" afterDir="false" />
-      <change afterPath="$PROJECT_DIR$/jeecgboot-vue3/src/views/okki/youtube/V20240516_1__menu_insert_OkkiYoutubeMarketingData.sql" afterDir="false" />
-      <change afterPath="$PROJECT_DIR$/jeecgboot-vue3/src/views/okki/youtube/components/OkkiYoutubeMarketingDataForm.vue" afterDir="false" />
-      <change afterPath="$PROJECT_DIR$/jeecgboot-vue3/src/views/okki/youtube/components/OkkiYoutubeMarketingDataModal.vue" afterDir="false" />
-      <change afterPath="$PROJECT_DIR$/jeecgboot-vue3/src/views/okki/youtube/subTables/OkkiYoutubeMarketingDataDetailSubTable.vue" afterDir="false" />
+      <change afterPath="$PROJECT_DIR$/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/okki/linkedin/controller/OkkiLinkedinMarketingDataController.java" afterDir="false" />
+      <change afterPath="$PROJECT_DIR$/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/okki/linkedin/entity/OkkiLinkedinMarketingData.java" afterDir="false" />
+      <change afterPath="$PROJECT_DIR$/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/okki/linkedin/entity/OkkiLinkedinMarketingDataDetail.java" afterDir="false" />
+      <change afterPath="$PROJECT_DIR$/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/okki/linkedin/mapper/OkkiLinkedinMarketingDataDetailMapper.java" afterDir="false" />
+      <change afterPath="$PROJECT_DIR$/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/okki/linkedin/mapper/OkkiLinkedinMarketingDataMapper.java" afterDir="false" />
+      <change afterPath="$PROJECT_DIR$/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/okki/linkedin/mapper/xml/OkkiLinkedinMarketingDataDetailMapper.xml" afterDir="false" />
+      <change afterPath="$PROJECT_DIR$/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/okki/linkedin/mapper/xml/OkkiLinkedinMarketingDataMapper.xml" afterDir="false" />
+      <change afterPath="$PROJECT_DIR$/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/okki/linkedin/param/LinkedinMarketingDataParam.java" afterDir="false" />
+      <change afterPath="$PROJECT_DIR$/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/okki/linkedin/param/LinkedinReportListParam.java" afterDir="false" />
+      <change afterPath="$PROJECT_DIR$/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/okki/linkedin/service/IOkkiLinkedinMarketingDataDetailService.java" afterDir="false" />
+      <change afterPath="$PROJECT_DIR$/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/okki/linkedin/service/IOkkiLinkedinMarketingDataService.java" afterDir="false" />
+      <change afterPath="$PROJECT_DIR$/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/okki/linkedin/service/impl/OkkiLinkedinMarketingDataDetailServiceImpl.java" afterDir="false" />
+      <change afterPath="$PROJECT_DIR$/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/okki/linkedin/service/impl/OkkiLinkedinMarketingDataServiceImpl.java" afterDir="false" />
+      <change afterPath="$PROJECT_DIR$/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/okki/linkedin/vo/OkkiLinkedinMarketingDataPage.java" afterDir="false" />
+      <change afterPath="$PROJECT_DIR$/jeecgboot-vue3/src/views/okki/linkedin/OkkiLinkedinMarketingData.api.ts" afterDir="false" />
+      <change afterPath="$PROJECT_DIR$/jeecgboot-vue3/src/views/okki/linkedin/OkkiLinkedinMarketingData.data.ts" afterDir="false" />
+      <change afterPath="$PROJECT_DIR$/jeecgboot-vue3/src/views/okki/linkedin/OkkiLinkedinMarketingDataList.vue" afterDir="false" />
+      <change afterPath="$PROJECT_DIR$/jeecgboot-vue3/src/views/okki/linkedin/V20240516_1__menu_insert_OkkiLinkedinMarketingData.sql" afterDir="false" />
+      <change afterPath="$PROJECT_DIR$/jeecgboot-vue3/src/views/okki/linkedin/components/OkkiLinkedinMarketingDataForm.vue" afterDir="false" />
+      <change afterPath="$PROJECT_DIR$/jeecgboot-vue3/src/views/okki/linkedin/components/OkkiLinkedinMarketingDataModal.vue" afterDir="false" />
       <change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/okki/showlist/service/impl/OkkiShowlistServiceImpl.java" beforeDir="false" afterPath="$PROJECT_DIR$/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/okki/showlist/service/impl/OkkiShowlistServiceImpl.java" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/application-dev.yml" beforeDir="false" afterPath="$PROJECT_DIR$/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/application-dev.yml" afterDir="false" />
     </list>
     <option name="SHOW_DIALOG" value="false" />
     <option name="HIGHLIGHT_CONFLICTS" value="true" />
@@ -91,7 +92,7 @@
     "Spring Boot.JeecgSystemApplication.executor": "Debug",
     "git-widget-placeholder": "master",
     "kotlin-language-version-configured": "true",
-    "last_opened_file_path": "D:/ProjectsCode/okki-oms/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/okki/youtube",
+    "last_opened_file_path": "D:/ProjectsCode/okki-oms/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/okki/linkedin",
     "node.js.detected.package.eslint": "true",
     "node.js.detected.package.stylelint": "true",
     "node.js.detected.package.tslint": "true",
@@ -117,11 +118,11 @@
   </component>
   <component name="RecentsManager">
     <key name="CopyFile.RECENT_KEYS">
+      <recent name="D:\ProjectsCode\okki-oms\jeecg-boot\jeecg-module-system\jeecg-system-biz\src\main\java\org\jeecg\modules\okki\linkedin" />
+      <recent name="D:\ProjectsCode\okki-oms\jeecgboot-vue3\src\views\okki\linkedin" />
       <recent name="D:\ProjectsCode\okki-oms\jeecg-boot\jeecg-module-system\jeecg-system-biz\src\main\java\org\jeecg\modules\okki\youtube" />
       <recent name="D:\ProjectsCode\okki-oms\jeecgboot-vue3\src\views\okki\youtube" />
       <recent name="D:\ProjectsCode\okki-oms\jeecg-boot\jeecg-module-system\jeecg-system-biz\src\main\java\org\jeecg\modules\okki\websitequality" />
-      <recent name="D:\ProjectsCode\okki-oms\jeecgboot-vue3\src\views\okki\websitequality" />
-      <recent name="D:\ProjectsCode\okki-oms\jeecg-boot\jeecg-module-system\jeecg-system-biz\src\main\java\org\jeecg\modules\okki\showlist\entity" />
     </key>
     <key name="CopyClassDialog.RECENTS_KEY">
       <recent name="org.jeecg.modules.okki.websitequality.param" />
@@ -184,7 +185,7 @@
       <workItem from="1714957905106" duration="25834000" />
       <workItem from="1715333910993" duration="2376000" />
       <workItem from="1715391022847" duration="21115000" />
-      <workItem from="1715648405916" duration="48519000" />
+      <workItem from="1715648405916" duration="53955000" />
     </task>
     <task id="LOCAL-00001" summary="增加添加站点对外接口">
       <option name="closed" value="true" />
@@ -338,7 +339,15 @@
       <option name="project" value="LOCAL" />
       <updated>1715828313692</updated>
     </task>
-    <option name="localTasksCounter" value="20" />
+    <task id="LOCAL-00020" summary="网站质量检查结果功能完善联调测试通过">
+      <option name="closed" value="true" />
+      <created>1715843752405</created>
+      <option name="number" value="00020" />
+      <option name="presentableId" value="LOCAL-00020" />
+      <option name="project" value="LOCAL" />
+      <updated>1715843752405</updated>
+    </task>
+    <option name="localTasksCounter" value="21" />
     <servers />
   </component>
   <component name="TypeScriptGeneratedFilesManager">

+ 276 - 0
jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/okki/linkedin/controller/OkkiLinkedinMarketingDataController.java

@@ -0,0 +1,276 @@
+package org.jeecg.modules.okki.linkedin.controller;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.shiro.SecurityUtils;
+import org.apache.shiro.authz.annotation.RequiresPermissions;
+import org.jeecg.common.api.vo.Result;
+import org.jeecg.common.aspect.annotation.AutoLog;
+import org.jeecg.common.system.query.QueryGenerator;
+import org.jeecg.common.system.vo.LoginUser;
+import org.jeecg.common.util.oConvertUtils;
+import org.jeecg.modules.okki.linkedin.entity.OkkiLinkedinMarketingData;
+import org.jeecg.modules.okki.linkedin.entity.OkkiLinkedinMarketingDataDetail;
+import org.jeecg.modules.okki.linkedin.service.IOkkiLinkedinMarketingDataDetailService;
+import org.jeecg.modules.okki.linkedin.service.IOkkiLinkedinMarketingDataService;
+import org.jeecg.modules.okki.linkedin.vo.OkkiLinkedinMarketingDataPage;
+import org.jeecg.modules.okki.youtube.entity.OkkiYoutubeMarketingData;
+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.BeanUtils;
+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 javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
+ /**
+ * @Description: Linkedin营销效果数据
+ * @Author: jeecg-boot
+ * @Date:   2024-05-16
+ * @Version: V1.0
+ */
+@Api(tags="Linkedin营销效果数据")
+@RestController
+@RequestMapping("/linkedin/okkiLinkedinMarketingData")
+@Slf4j
+public class OkkiLinkedinMarketingDataController {
+	@Autowired
+	private IOkkiLinkedinMarketingDataService okkiLinkedinMarketingDataService;
+	@Autowired
+	private IOkkiLinkedinMarketingDataDetailService okkiLinkedinMarketingDataDetailService;
+	
+	/**
+	 * 分页列表查询
+	 *
+	 * @param okkiLinkedinMarketingData
+	 * @param pageNo
+	 * @param pageSize
+	 * @param req
+	 * @return
+	 */
+	//@AutoLog(value = "Linkedin营销效果数据-分页列表查询")
+	@ApiOperation(value="Linkedin营销效果数据-分页列表查询", notes="Linkedin营销效果数据-分页列表查询")
+	@GetMapping(value = "/list")
+	public Result<IPage<OkkiLinkedinMarketingData>> queryPageList(OkkiLinkedinMarketingData okkiLinkedinMarketingData,
+								   @RequestParam(name="pageNo", defaultValue="1") Integer pageNo,
+								   @RequestParam(name="pageSize", defaultValue="10") Integer pageSize,
+								   HttpServletRequest req) {
+		QueryWrapper<OkkiLinkedinMarketingData> queryWrapper = QueryGenerator.initQueryWrapper(okkiLinkedinMarketingData, req.getParameterMap());
+		Page<OkkiLinkedinMarketingData> page = new Page<OkkiLinkedinMarketingData>(pageNo, pageSize);
+		IPage<OkkiLinkedinMarketingData> pageList = okkiLinkedinMarketingDataService.page(page, queryWrapper);
+		return Result.OK(pageList);
+	}
+	
+	/**
+	 *   添加
+	 *
+	 * @param okkiLinkedinMarketingDataPage
+	 * @return
+	 */
+	@AutoLog(value = "Linkedin营销效果数据-添加")
+	@ApiOperation(value="Linkedin营销效果数据-添加", notes="Linkedin营销效果数据-添加")
+    @RequiresPermissions("linkedin:okki_linkedin_marketing_data:add")
+	@PostMapping(value = "/add")
+	public Result<String> add(@RequestBody OkkiLinkedinMarketingDataPage okkiLinkedinMarketingDataPage) {
+		OkkiLinkedinMarketingData okkiLinkedinMarketingData = new OkkiLinkedinMarketingData();
+		BeanUtils.copyProperties(okkiLinkedinMarketingDataPage, okkiLinkedinMarketingData);
+		okkiLinkedinMarketingDataService.saveMain(okkiLinkedinMarketingData, okkiLinkedinMarketingDataPage.getOkkiLinkedinMarketingDataDetailList());
+		return Result.OK("添加成功!");
+	}
+	
+	/**
+	 *  编辑
+	 *
+	 * @param okkiLinkedinMarketingDataPage
+	 * @return
+	 */
+	@AutoLog(value = "Linkedin营销效果数据-编辑")
+	@ApiOperation(value="Linkedin营销效果数据-编辑", notes="Linkedin营销效果数据-编辑")
+    @RequiresPermissions("linkedin:okki_linkedin_marketing_data:edit")
+	@RequestMapping(value = "/edit", method = {RequestMethod.PUT,RequestMethod.POST})
+	public Result<String> edit(@RequestBody OkkiLinkedinMarketingDataPage okkiLinkedinMarketingDataPage) {
+		OkkiLinkedinMarketingData okkiLinkedinMarketingData = new OkkiLinkedinMarketingData();
+		BeanUtils.copyProperties(okkiLinkedinMarketingDataPage, okkiLinkedinMarketingData);
+		OkkiLinkedinMarketingData okkiLinkedinMarketingDataEntity = okkiLinkedinMarketingDataService.getById(okkiLinkedinMarketingData.getId());
+		if(okkiLinkedinMarketingDataEntity==null) {
+			return Result.error("未找到对应数据");
+		}
+		okkiLinkedinMarketingDataService.updateMain(okkiLinkedinMarketingData, okkiLinkedinMarketingDataPage.getOkkiLinkedinMarketingDataDetailList());
+		return Result.OK("编辑成功!");
+	}
+	
+	/**
+	 *   通过id删除
+	 *
+	 * @param id
+	 * @return
+	 */
+	@AutoLog(value = "Linkedin营销效果数据-通过id删除")
+	@ApiOperation(value="Linkedin营销效果数据-通过id删除", notes="Linkedin营销效果数据-通过id删除")
+    @RequiresPermissions("linkedin:okki_linkedin_marketing_data:delete")
+	@DeleteMapping(value = "/delete")
+	public Result<String> delete(@RequestParam(name="id",required=true) String id) {
+		okkiLinkedinMarketingDataService.delMain(id);
+		return Result.OK("删除成功!");
+	}
+	
+	/**
+	 *  批量删除
+	 *
+	 * @param ids
+	 * @return
+	 */
+	@AutoLog(value = "Linkedin营销效果数据-批量删除")
+	@ApiOperation(value="Linkedin营销效果数据-批量删除", notes="Linkedin营销效果数据-批量删除")
+    @RequiresPermissions("linkedin:okki_linkedin_marketing_data:deleteBatch")
+	@DeleteMapping(value = "/deleteBatch")
+	public Result<String> deleteBatch(@RequestParam(name="ids",required=true) String ids) {
+		this.okkiLinkedinMarketingDataService.delBatchMain(Arrays.asList(ids.split(",")));
+		return Result.OK("批量删除成功!");
+	}
+	
+	/**
+	 * 通过id查询
+	 *
+	 * @param id
+	 * @return
+	 */
+	//@AutoLog(value = "Linkedin营销效果数据-通过id查询")
+	@ApiOperation(value="Linkedin营销效果数据-通过id查询", notes="Linkedin营销效果数据-通过id查询")
+	@GetMapping(value = "/queryById")
+	public Result<OkkiLinkedinMarketingData> queryById(@RequestParam(name="id",required=true) String id) {
+		OkkiLinkedinMarketingData okkiLinkedinMarketingData = okkiLinkedinMarketingDataService.getById(id);
+		if(okkiLinkedinMarketingData==null) {
+			return Result.error("未找到对应数据");
+		}
+		return Result.OK(okkiLinkedinMarketingData);
+
+	}
+	
+	/**
+	 * 通过id查询
+	 *
+	 * @param id
+	 * @return
+	 */
+	//@AutoLog(value = "Linkedin营销效果数据详情通过主表ID查询")
+	@ApiOperation(value="Linkedin营销效果数据详情主表ID查询", notes="Linkedin营销效果数据详情-通主表ID查询")
+	@GetMapping(value = "/queryOkkiLinkedinMarketingDataDetailByMainId")
+	public Result<List<OkkiLinkedinMarketingDataDetail>> queryOkkiLinkedinMarketingDataDetailListByMainId(@RequestParam(name="id",required=true) String id) {
+		List<OkkiLinkedinMarketingDataDetail> okkiLinkedinMarketingDataDetailList = okkiLinkedinMarketingDataDetailService.selectByMainId(id);
+		return Result.OK(okkiLinkedinMarketingDataDetailList);
+	}
+
+    /**
+    * 导出excel
+    *
+    * @param request
+    * @param okkiLinkedinMarketingData
+    */
+    @RequiresPermissions("linkedin:okki_linkedin_marketing_data:exportXls")
+    @RequestMapping(value = "/exportXls")
+    public ModelAndView exportXls(HttpServletRequest request, OkkiLinkedinMarketingData okkiLinkedinMarketingData) {
+      // Step.1 组装查询条件查询数据
+      QueryWrapper<OkkiLinkedinMarketingData> queryWrapper = QueryGenerator.initQueryWrapper(okkiLinkedinMarketingData, request.getParameterMap());
+      LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
+
+      //配置选中数据查询条件
+       String selections = request.getParameter("selections");
+       if(oConvertUtils.isNotEmpty(selections)) {
+            List<String> selectionList = Arrays.asList(selections.split(","));
+            queryWrapper.in("id",selectionList);
+       }
+       //Step.2 获取导出数据
+       List<OkkiLinkedinMarketingData> okkiLinkedinMarketingDataList = okkiLinkedinMarketingDataService.list(queryWrapper);
+
+      // Step.3 组装pageList
+      List<OkkiLinkedinMarketingDataPage> pageList = new ArrayList<OkkiLinkedinMarketingDataPage>();
+      for (OkkiLinkedinMarketingData main : okkiLinkedinMarketingDataList) {
+          OkkiLinkedinMarketingDataPage vo = new OkkiLinkedinMarketingDataPage();
+          BeanUtils.copyProperties(main, vo);
+          List<OkkiLinkedinMarketingDataDetail> okkiLinkedinMarketingDataDetailList = okkiLinkedinMarketingDataDetailService.selectByMainId(main.getId());
+          vo.setOkkiLinkedinMarketingDataDetailList(okkiLinkedinMarketingDataDetailList);
+          pageList.add(vo);
+      }
+
+      // Step.4 AutoPoi 导出Excel
+      ModelAndView mv = new ModelAndView(new JeecgEntityExcelView());
+      mv.addObject(NormalExcelConstants.FILE_NAME, "Linkedin营销效果数据列表");
+      mv.addObject(NormalExcelConstants.CLASS, OkkiLinkedinMarketingDataPage.class);
+      mv.addObject(NormalExcelConstants.PARAMS, new ExportParams("Linkedin营销效果数据数据", "导出人:"+sysUser.getRealname(), "Linkedin营销效果数据"));
+      mv.addObject(NormalExcelConstants.DATA_LIST, pageList);
+      return mv;
+    }
+
+    /**
+    * 通过excel导入数据
+    *
+    * @param request
+    * @param response
+    * @return
+    */
+    @RequiresPermissions("linkedin:okki_linkedin_marketing_data:importExcel")
+    @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<OkkiLinkedinMarketingDataPage> list = ExcelImportUtil.importExcel(file.getInputStream(), OkkiLinkedinMarketingDataPage.class, params);
+              for (OkkiLinkedinMarketingDataPage page : list) {
+                  OkkiLinkedinMarketingData po = new OkkiLinkedinMarketingData();
+                  BeanUtils.copyProperties(page, po);
+                  okkiLinkedinMarketingDataService.saveMain(po, page.getOkkiLinkedinMarketingDataDetailList());
+              }
+              return Result.OK("文件导入成功!数据行数:" + list.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("文件导入失败!");
+    }
+
+	 /**
+	  * 变更状态
+	  * @param okkiLinkedinMarketingData
+	  * @return
+	  */
+	 @PostMapping(value = "/status")
+	 public Result<String> changeStatus(@RequestBody OkkiLinkedinMarketingData okkiLinkedinMarketingData) throws Exception {
+		 boolean result = okkiLinkedinMarketingDataService.changeStatus(okkiLinkedinMarketingData);
+		 if (result) {
+			 return Result.OK("操作成功");
+		 }else {
+			 return Result.error("操作失败");
+		 }
+	 }
+}

+ 59 - 0
jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/okki/linkedin/entity/OkkiLinkedinMarketingData.java

@@ -0,0 +1,59 @@
+package org.jeecg.modules.okki.linkedin.entity;
+
+import java.io.Serializable;
+import java.io.UnsupportedEncodingException;
+import java.util.Date;
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.baomidou.mybatisplus.annotation.TableLogic;
+import lombok.Data;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import org.springframework.format.annotation.DateTimeFormat;
+import org.jeecgframework.poi.excel.annotation.Excel;
+import org.jeecg.common.aspect.annotation.Dict;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+
+/**
+ * @Description: Linkedin营销效果数据
+ * @Author: jeecg-boot
+ * @Date:   2024-05-16
+ * @Version: V1.0
+ */
+@ApiModel(value="okki_linkedin_marketing_data对象", description="Linkedin营销效果数据")
+@Data
+@TableName("okki_linkedin_marketing_data")
+public class OkkiLinkedinMarketingData implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+	/**主键*/
+	@TableId(type = IdType.ASSIGN_ID)
+    @ApiModelProperty(value = "主键")
+    private String id;
+	/**创建人*/
+    @ApiModelProperty(value = "创建人")
+    private String createBy;
+	/**更新人*/
+    @ApiModelProperty(value = "更新人")
+    private String updateBy;
+	/**更新日期*/
+	@JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
+    @DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
+    @ApiModelProperty(value = "更新日期")
+    private Date updateTime;
+	/**站点id*/
+	@Excel(name = "站点id", width = 15)
+    @ApiModelProperty(value = "站点id")
+    private String siteId;
+	/**同步状态*/
+	@Excel(name = "同步状态", width = 15, dicCode = "blog_status")
+    @Dict(dicCode = "blog_status")
+    @ApiModelProperty(value = "同步状态")
+    private Integer status;
+	/**创建日期*/
+	@JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
+    @DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
+    @ApiModelProperty(value = "创建日期")
+    private Date createTime;
+}

+ 64 - 0
jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/okki/linkedin/entity/OkkiLinkedinMarketingDataDetail.java

@@ -0,0 +1,64 @@
+package org.jeecg.modules.okki.linkedin.entity;
+
+import java.io.Serializable;
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.baomidou.mybatisplus.annotation.TableLogic;
+import lombok.Data;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import org.springframework.format.annotation.DateTimeFormat;
+import org.jeecgframework.poi.excel.annotation.Excel;
+import java.util.Date;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import java.io.UnsupportedEncodingException;
+
+/**
+ * @Description: Linkedin营销效果数据详情
+ * @Author: jeecg-boot
+ * @Date:   2024-05-16
+ * @Version: V1.0
+ */
+@ApiModel(value="okki_linkedin_marketing_data_detail对象", description="Linkedin营销效果数据详情")
+@Data
+@TableName("okki_linkedin_marketing_data_detail")
+public class OkkiLinkedinMarketingDataDetail implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+	/**主键*/
+	@TableId(type = IdType.ASSIGN_ID)
+    @ApiModelProperty(value = "主键")
+    private String id;
+	/**创建人*/
+    @ApiModelProperty(value = "创建人")
+    private String createBy;
+	/**更新人*/
+    @ApiModelProperty(value = "更新人")
+    private String updateBy;
+	/**更新日期*/
+	@JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
+    @DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
+    @ApiModelProperty(value = "更新日期")
+    private Date updateTime;
+	/**关联id*/
+    @ApiModelProperty(value = "关联id")
+    private String okkiLinkedinMarketingDataId;
+	/**文章id*/
+	@Excel(name = "文章id", width = 15)
+    @ApiModelProperty(value = "文章id")
+    private String articleId;
+	/**标题*/
+	@Excel(name = "标题", width = 15)
+    @ApiModelProperty(value = "标题")
+    private String title;
+	/**链接*/
+	@Excel(name = "链接", width = 15)
+    @ApiModelProperty(value = "链接")
+    private String url;
+	/**创建日期*/
+	@JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
+    @DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
+    @ApiModelProperty(value = "创建日期")
+    private Date createTime;
+}

+ 32 - 0
jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/okki/linkedin/mapper/OkkiLinkedinMarketingDataDetailMapper.java

@@ -0,0 +1,32 @@
+package org.jeecg.modules.okki.linkedin.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Param;
+import org.jeecg.modules.okki.linkedin.entity.OkkiLinkedinMarketingDataDetail;
+
+import java.util.List;
+
+/**
+ * @Description: Linkedin营销效果数据详情
+ * @Author: jeecg-boot
+ * @Date:   2024-05-16
+ * @Version: V1.0
+ */
+public interface OkkiLinkedinMarketingDataDetailMapper extends BaseMapper<OkkiLinkedinMarketingDataDetail> {
+
+	/**
+	 * 通过主表id删除子表数据
+	 *
+	 * @param mainId 主表id
+	 * @return boolean
+	 */
+	public boolean deleteByMainId(@Param("mainId") String mainId);
+
+  /**
+   * 通过主表id查询子表数据
+   *
+   * @param mainId 主表id
+   * @return List<OkkiLinkedinMarketingDataDetail>
+   */
+	public List<OkkiLinkedinMarketingDataDetail> selectByMainId(@Param("mainId") String mainId);
+}

+ 14 - 0
jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/okki/linkedin/mapper/OkkiLinkedinMarketingDataMapper.java

@@ -0,0 +1,14 @@
+package org.jeecg.modules.okki.linkedin.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.jeecg.modules.okki.linkedin.entity.OkkiLinkedinMarketingData;
+
+/**
+ * @Description: Linkedin营销效果数据
+ * @Author: jeecg-boot
+ * @Date:   2024-05-16
+ * @Version: V1.0
+ */
+public interface OkkiLinkedinMarketingDataMapper extends BaseMapper<OkkiLinkedinMarketingData> {
+
+}

+ 16 - 0
jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/okki/linkedin/mapper/xml/OkkiLinkedinMarketingDataDetailMapper.xml

@@ -0,0 +1,16 @@
+<?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.okki.linkedin.mapper.OkkiLinkedinMarketingDataDetailMapper">
+
+	<delete id="deleteByMainId" parameterType="java.lang.String">
+		DELETE 
+		FROM  okki_linkedin_marketing_data_detail 
+		WHERE
+			 okki_linkedin_marketing_data_id = #{mainId} 	</delete>
+	
+	<select id="selectByMainId" parameterType="java.lang.String" resultType="org.jeecg.modules.okki.linkedin.entity.OkkiLinkedinMarketingDataDetail">
+		SELECT * 
+		FROM  okki_linkedin_marketing_data_detail
+		WHERE
+			 okki_linkedin_marketing_data_id = #{mainId} 	</select>
+</mapper>

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

+ 13 - 0
jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/okki/linkedin/param/LinkedinMarketingDataParam.java

@@ -0,0 +1,13 @@
+package org.jeecg.modules.okki.linkedin.param;
+
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+public class LinkedinMarketingDataParam {
+
+    private List<LinkedinReportListParam> report_list;
+
+    private Integer count;
+}

+ 15 - 0
jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/okki/linkedin/param/LinkedinReportListParam.java

@@ -0,0 +1,15 @@
+package org.jeecg.modules.okki.linkedin.param;
+
+import lombok.Data;
+
+@Data
+public class LinkedinReportListParam {
+
+    private String id;
+
+    private String title;
+
+    private String url;
+
+    private String create_time;
+}

+ 22 - 0
jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/okki/linkedin/service/IOkkiLinkedinMarketingDataDetailService.java

@@ -0,0 +1,22 @@
+package org.jeecg.modules.okki.linkedin.service;
+
+import org.jeecg.modules.okki.linkedin.entity.OkkiLinkedinMarketingDataDetail;
+import com.baomidou.mybatisplus.extension.service.IService;
+import java.util.List;
+
+/**
+ * @Description: Linkedin营销效果数据详情
+ * @Author: jeecg-boot
+ * @Date:   2024-05-16
+ * @Version: V1.0
+ */
+public interface IOkkiLinkedinMarketingDataDetailService extends IService<OkkiLinkedinMarketingDataDetail> {
+
+	/**
+	 * 通过主表id查询子表数据
+	 *
+	 * @param mainId 主表id
+	 * @return List<OkkiLinkedinMarketingDataDetail>
+	 */
+	public List<OkkiLinkedinMarketingDataDetail> selectByMainId(String mainId);
+}

+ 49 - 0
jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/okki/linkedin/service/IOkkiLinkedinMarketingDataService.java

@@ -0,0 +1,49 @@
+package org.jeecg.modules.okki.linkedin.service;
+
+import org.jeecg.modules.okki.linkedin.entity.OkkiLinkedinMarketingDataDetail;
+import org.jeecg.modules.okki.linkedin.entity.OkkiLinkedinMarketingData;
+import com.baomidou.mybatisplus.extension.service.IService;
+import java.io.Serializable;
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * @Description: Linkedin营销效果数据
+ * @Author: jeecg-boot
+ * @Date:   2024-05-16
+ * @Version: V1.0
+ */
+public interface IOkkiLinkedinMarketingDataService extends IService<OkkiLinkedinMarketingData> {
+
+	/**
+	 * 添加一对多
+	 *
+	 * @param okkiLinkedinMarketingData
+	 * @param okkiLinkedinMarketingDataDetailList
+	 */
+	public void saveMain(OkkiLinkedinMarketingData okkiLinkedinMarketingData,List<OkkiLinkedinMarketingDataDetail> okkiLinkedinMarketingDataDetailList) ;
+	
+	/**
+	 * 修改一对多
+	 *
+	 * @param okkiLinkedinMarketingData
+	 * @param okkiLinkedinMarketingDataDetailList
+	 */
+	public void updateMain(OkkiLinkedinMarketingData okkiLinkedinMarketingData,List<OkkiLinkedinMarketingDataDetail> okkiLinkedinMarketingDataDetailList);
+	
+	/**
+	 * 删除一对多
+	 *
+	 * @param id
+	 */
+	public void delMain (String id);
+	
+	/**
+	 * 批量删除一对多
+	 *
+	 * @param idList
+	 */
+	public void delBatchMain (Collection<? extends Serializable> idList);
+
+	boolean changeStatus(OkkiLinkedinMarketingData okkiLinkedinMarketingData);
+}

+ 28 - 0
jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/okki/linkedin/service/impl/OkkiLinkedinMarketingDataDetailServiceImpl.java

@@ -0,0 +1,28 @@
+package org.jeecg.modules.okki.linkedin.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.jeecg.modules.okki.linkedin.entity.OkkiLinkedinMarketingDataDetail;
+import org.jeecg.modules.okki.linkedin.mapper.OkkiLinkedinMarketingDataDetailMapper;
+import org.jeecg.modules.okki.linkedin.service.IOkkiLinkedinMarketingDataDetailService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * @Description: Linkedin营销效果数据详情
+ * @Author: jeecg-boot
+ * @Date:   2024-05-16
+ * @Version: V1.0
+ */
+@Service
+public class OkkiLinkedinMarketingDataDetailServiceImpl extends ServiceImpl<OkkiLinkedinMarketingDataDetailMapper, OkkiLinkedinMarketingDataDetail> implements IOkkiLinkedinMarketingDataDetailService {
+	
+	@Autowired
+	private OkkiLinkedinMarketingDataDetailMapper okkiLinkedinMarketingDataDetailMapper;
+	
+	@Override
+	public List<OkkiLinkedinMarketingDataDetail> selectByMainId(String mainId) {
+		return okkiLinkedinMarketingDataDetailMapper.selectByMainId(mainId);
+	}
+}

+ 141 - 0
jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/okki/linkedin/service/impl/OkkiLinkedinMarketingDataServiceImpl.java

@@ -0,0 +1,141 @@
+package org.jeecg.modules.okki.linkedin.service.impl;
+
+import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import lombok.extern.slf4j.Slf4j;
+import org.jeecg.modules.okki.linkedin.entity.OkkiLinkedinMarketingData;
+import org.jeecg.modules.okki.linkedin.entity.OkkiLinkedinMarketingDataDetail;
+import org.jeecg.modules.okki.linkedin.mapper.OkkiLinkedinMarketingDataDetailMapper;
+import org.jeecg.modules.okki.linkedin.mapper.OkkiLinkedinMarketingDataMapper;
+import org.jeecg.modules.okki.linkedin.param.LinkedinMarketingDataParam;
+import org.jeecg.modules.okki.linkedin.param.LinkedinReportListParam;
+import org.jeecg.modules.okki.linkedin.service.IOkkiLinkedinMarketingDataService;
+import org.jeecg.modules.okki.utils.HttpClientUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.io.Serializable;
+import java.text.SimpleDateFormat;
+import java.util.*;
+
+/**
+ * @Description: Linkedin营销效果数据
+ * @Author: jeecg-boot
+ * @Date:   2024-05-16
+ * @Version: V1.0
+ */
+@Slf4j
+@Service
+public class OkkiLinkedinMarketingDataServiceImpl extends ServiceImpl<OkkiLinkedinMarketingDataMapper, OkkiLinkedinMarketingData> implements IOkkiLinkedinMarketingDataService {
+
+	@Value("${OKKI.BASE_URL}")
+	private String URL;
+
+	@Value("${OKKI.CLIENT_SECRET}")
+	private String CLIENT_SECRET;
+
+	@Autowired
+	private OkkiLinkedinMarketingDataMapper okkiLinkedinMarketingDataMapper;
+	@Autowired
+	private OkkiLinkedinMarketingDataDetailMapper okkiLinkedinMarketingDataDetailMapper;
+	
+	@Override
+	@Transactional(rollbackFor = Exception.class)
+	public void saveMain(OkkiLinkedinMarketingData okkiLinkedinMarketingData, List<OkkiLinkedinMarketingDataDetail> okkiLinkedinMarketingDataDetailList) {
+		okkiLinkedinMarketingDataMapper.insert(okkiLinkedinMarketingData);
+		if(okkiLinkedinMarketingDataDetailList!=null && okkiLinkedinMarketingDataDetailList.size()>0) {
+			for(OkkiLinkedinMarketingDataDetail entity:okkiLinkedinMarketingDataDetailList) {
+				//外键设置
+				entity.setOkkiLinkedinMarketingDataId(okkiLinkedinMarketingData.getId());
+				okkiLinkedinMarketingDataDetailMapper.insert(entity);
+			}
+		}
+	}
+
+	@Override
+	@Transactional(rollbackFor = Exception.class)
+	public void updateMain(OkkiLinkedinMarketingData okkiLinkedinMarketingData,List<OkkiLinkedinMarketingDataDetail> okkiLinkedinMarketingDataDetailList) {
+		okkiLinkedinMarketingDataMapper.updateById(okkiLinkedinMarketingData);
+		
+		//1.先删除子表数据
+		okkiLinkedinMarketingDataDetailMapper.deleteByMainId(okkiLinkedinMarketingData.getId());
+		
+		//2.子表数据重新插入
+		if(okkiLinkedinMarketingDataDetailList!=null && okkiLinkedinMarketingDataDetailList.size()>0) {
+			for(OkkiLinkedinMarketingDataDetail entity:okkiLinkedinMarketingDataDetailList) {
+				//外键设置
+				entity.setOkkiLinkedinMarketingDataId(okkiLinkedinMarketingData.getId());
+				okkiLinkedinMarketingDataDetailMapper.insert(entity);
+			}
+		}
+	}
+
+	@Override
+	@Transactional(rollbackFor = Exception.class)
+	public void delMain(String id) {
+		okkiLinkedinMarketingDataDetailMapper.deleteByMainId(id);
+		okkiLinkedinMarketingDataMapper.deleteById(id);
+	}
+
+	@Override
+	@Transactional(rollbackFor = Exception.class)
+	public void delBatchMain(Collection<? extends Serializable> idList) {
+		for(Serializable id:idList) {
+			okkiLinkedinMarketingDataDetailMapper.deleteByMainId(id.toString());
+			okkiLinkedinMarketingDataMapper.deleteById(id);
+		}
+	}
+
+	@Override
+	public boolean changeStatus(OkkiLinkedinMarketingData param) {
+		OkkiLinkedinMarketingData okkiLinkedinMarketingData = okkiLinkedinMarketingDataMapper.selectById(param.getId());
+		// 请求okki平台接口
+		Map<String, String> query = new TreeMap<>();
+		query.put("sign_method", "hmac-md5");
+		query.put("timestamp", String.valueOf(System.currentTimeMillis()));
+		query.put("site_id", String.valueOf(okkiLinkedinMarketingData.getSiteId()));
+		query.put("method", "linkedin_report");
+		okkiLinkedinMarketingData.setStatus(1);
+		LinkedinMarketingDataParam linkedinMarketingDataParam  = new LinkedinMarketingDataParam();
+		try {
+			String queryStr = HttpClientUtils.buildQueryString(query);
+			List<OkkiLinkedinMarketingDataDetail> okkiLinkedinMarketingDataDetails = okkiLinkedinMarketingDataDetailMapper.selectByMainId(okkiLinkedinMarketingData.getId());
+			ArrayList<LinkedinReportListParam> linkedinReportListParams = new ArrayList<>();
+			for (OkkiLinkedinMarketingDataDetail okkiLinkedinMarketingDataDetail : okkiLinkedinMarketingDataDetails) {
+				LinkedinReportListParam linkedinReportListParam = new LinkedinReportListParam();
+				linkedinReportListParam.setId(okkiLinkedinMarketingDataDetail.getId());
+				linkedinReportListParam.setTitle(okkiLinkedinMarketingDataDetail.getTitle());
+				linkedinReportListParam.setUrl(okkiLinkedinMarketingDataDetail.getUrl());
+				SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+				linkedinReportListParam.setCreate_time(format.format(okkiLinkedinMarketingDataDetail.getCreateTime()));
+				linkedinReportListParams.add(linkedinReportListParam);
+			}
+			linkedinMarketingDataParam.setReport_list(linkedinReportListParams);
+			linkedinMarketingDataParam.setCount(linkedinReportListParams.size());
+			String body = HttpClientUtils.toJsonString(linkedinMarketingDataParam);
+			String signStr = queryStr + body;
+			query.put("signature", HttpClientUtils.generateHmacMD5(signStr, CLIENT_SECRET));
+			String okkiUrl = URL + "?" + HttpClientUtils.buildQueryString(query);
+			log.info("url:" + okkiUrl + ",body:" + body);
+			String res = HttpClientUtils.doPost(okkiUrl, body);
+			log.info(res);
+			// {"code":0,"msg":"success","now":"2024-05-06 15:34:54","data":[]}
+			JSONObject jsonObject= JSONObject.parseObject(res);
+			if (jsonObject.get("code").equals(0)) {
+				int result = okkiLinkedinMarketingDataMapper.updateById(okkiLinkedinMarketingData);
+				if (result == 0) {
+					return false;
+				}else {
+					return true;
+				}
+			}else {
+				throw new RuntimeException(jsonObject.get("msg").toString());
+			}
+		} catch (Exception e) {
+			throw new RuntimeException(e);
+		}
+	}
+
+}

+ 59 - 0
jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/okki/linkedin/vo/OkkiLinkedinMarketingDataPage.java

@@ -0,0 +1,59 @@
+package org.jeecg.modules.okki.linkedin.vo;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import org.jeecg.common.aspect.annotation.Dict;
+import org.jeecg.modules.okki.linkedin.entity.OkkiLinkedinMarketingDataDetail;
+import org.jeecgframework.poi.excel.annotation.Excel;
+import org.jeecgframework.poi.excel.annotation.ExcelCollection;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.util.Date;
+import java.util.List;
+
+/**
+ * @Description: Linkedin营销效果数据
+ * @Author: jeecg-boot
+ * @Date:   2024-05-16
+ * @Version: V1.0
+ */
+@Data
+@ApiModel(value="okki_linkedin_marketing_dataPage对象", description="Linkedin营销效果数据")
+public class OkkiLinkedinMarketingDataPage {
+
+	/**主键*/
+	@ApiModelProperty(value = "主键")
+    private String id;
+	/**创建人*/
+	@ApiModelProperty(value = "创建人")
+    private String createBy;
+	/**更新人*/
+	@ApiModelProperty(value = "更新人")
+    private String updateBy;
+	/**更新日期*/
+	@JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
+    @DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
+	@ApiModelProperty(value = "更新日期")
+    private Date updateTime;
+	/**站点id*/
+	@Excel(name = "站点id", width = 15)
+	@ApiModelProperty(value = "站点id")
+    private String siteId;
+	/**同步状态*/
+	@Excel(name = "同步状态", width = 15, dicCode = "blog_status")
+    @Dict(dicCode = "blog_status")
+	@ApiModelProperty(value = "同步状态")
+    private Integer status;
+	/**创建日期*/
+	@JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
+    @DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
+	@ApiModelProperty(value = "创建日期")
+    private Date createTime;
+
+	@ExcelCollection(name="Linkedin营销效果数据详情")
+	@ApiModelProperty(value = "Linkedin营销效果数据详情")
+	private List<OkkiLinkedinMarketingDataDetail> okkiLinkedinMarketingDataDetailList;
+
+}

+ 1 - 1
jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/okki/showlist/service/impl/OkkiShowlistServiceImpl.java

@@ -267,7 +267,7 @@ public class OkkiShowlistServiceImpl extends ServiceImpl<OkkiShowlistMapper, Okk
 		List<OkkiAdvantage> okkiAdvantages = okkiAdvantageMapper.selectByMainId(id);
 		List<OkkiRecommendedProducts> okkiRecommendedProducts = okkiRecommendedProductsMapper.selectByMainId(id);
 		List<OkkiKeywords> okkiKeywords = okkiKeywordsMapper.selectByMainId(id);
-		List<OkkiKeywordsSeries> okkiKeywordsSeries = okkiKeywordsSeriesMapper.selectByMainId(id);
+//		List<OkkiKeywordsSeries> okkiKeywordsSeries = okkiKeywordsSeriesMapper.selectByMainId(id);
 		List<OkkiReview> okkiReviews = okkiReviewMapper.selectByMainId(id);
 		List<OkkiFaq> okkiFaqs = okkiFaqMapper.selectByMainId(id);
 		List<OkkiShowlistBlog> okkiShowlistBlogs = okkiShowlistBlogMapper.selectByMainId(id);

+ 3 - 3
jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/application-dev.yml

@@ -158,9 +158,9 @@ spring:
           slow-sql-millis: 5000
       datasource:
         master:
-          url: jdbc:mysql://127.0.0.1:3306/jeecg-boot-vue?characterEncoding=UTF-8&useUnicode=true&useSSL=false&tinyInt1isBit=false&allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai
-          username: root
-          password: root
+          url: jdbc:mysql://database-1.c0stwhsmuvxv.rds.cn-northwest-1.amazonaws.com.cn:3306/oms-dev?characterEncoding=UTF-8&useUnicode=true&useSSL=false&tinyInt1isBit=false&allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai
+          username: oms-dev
+          password: E6YdcbMt2whgQCq8
           driver-class-name: com.mysql.cj.jdbc.Driver
           # 多数据源配置
           #multi-datasource1:

+ 71 - 0
jeecgboot-vue3/src/views/okki/linkedin/OkkiLinkedinMarketingData.api.ts

@@ -0,0 +1,71 @@
+import {defHttp} from '/@/utils/http/axios';
+import { useMessage } from "/@/hooks/web/useMessage";
+
+const { createConfirm } = useMessage();
+
+enum Api {
+  list = '/linkedin/okkiLinkedinMarketingData/list',
+  save='/linkedin/okkiLinkedinMarketingData/add',
+  edit='/linkedin/okkiLinkedinMarketingData/edit',
+  deleteOne = '/linkedin/okkiLinkedinMarketingData/delete',
+  deleteBatch = '/linkedin/okkiLinkedinMarketingData/deleteBatch',
+  importExcel = '/linkedin/okkiLinkedinMarketingData/importExcel',
+  exportXls = '/linkedin/okkiLinkedinMarketingData/exportXls',
+  okkiLinkedinMarketingDataDetailList = '/linkedin/okkiLinkedinMarketingData/queryOkkiLinkedinMarketingDataDetailByMainId',
+}
+/**
+ * 导出api
+ * @param params
+ */
+export const getExportUrl = Api.exportXls;
+
+/**
+ * 导入api
+ */
+export const getImportUrl = Api.importExcel;
+/**
+ * 查询子表数据
+ * @param params
+ */
+export const okkiLinkedinMarketingDataDetailList = Api.okkiLinkedinMarketingDataDetailList;
+/**
+ * 列表接口
+ * @param params
+ */
+export const list = (params) =>
+  defHttp.get({url: Api.list, params});
+
+/**
+ * 删除单个
+ */
+export const deleteOne = (params,handleSuccess) => {
+  return defHttp.delete({url: Api.deleteOne, params}, {joinParamsToUrl: true}).then(() => {
+    handleSuccess();
+  });
+}
+/**
+ * 批量删除
+ * @param params
+ */
+export const batchDelete = (params, handleSuccess) => {
+  createConfirm({
+    iconType: 'warning',
+    title: '确认删除',
+    content: '是否删除选中数据',
+    okText: '确认',
+    cancelText: '取消',
+    onOk: () => {
+      return defHttp.delete({url: Api.deleteBatch, data: params}, {joinParamsToUrl: true}).then(() => {
+        handleSuccess();
+      });
+    }
+  });
+}
+/**
+ * 保存或者更新
+ * @param params
+ */
+export const saveOrUpdate = (params, isUpdate) => {
+  let url = isUpdate ? Api.edit : Api.save;
+  return defHttp.post({url: url, params});
+}

+ 95 - 0
jeecgboot-vue3/src/views/okki/linkedin/OkkiLinkedinMarketingData.data.ts

@@ -0,0 +1,95 @@
+import {BasicColumn} from '/@/components/Table';
+import {FormSchema} from '/@/components/Table';
+import { rules} from '/@/utils/helper/validator';
+import { render } from '/@/utils/common/renderUtils';
+import {JVxeTypes,JVxeColumn} from '/@/components/jeecg/JVxeTable/types'
+//列表数据
+export const columns: BasicColumn[] = [
+   {
+    title: '站点id',
+    align:"center",
+    dataIndex: 'siteId'
+   },
+   {
+    title: '同步状态',
+    align:"center",
+    dataIndex: 'status_dictText'
+   },
+   {
+    title: '创建日期',
+    align:"center",
+    dataIndex: 'createTime'
+   },
+];
+//查询数据
+export const searchFormSchema: FormSchema[] = [
+];
+//表单数据
+export const formSchema: FormSchema[] = [
+  {
+    label: '站点id',
+    field: 'siteId',
+    component: 'Input',
+  },
+	// TODO 主键隐藏字段,目前写死为ID
+	{
+	  label: '',
+	  field: 'id',
+	  component: 'Input',
+	  show: false
+	},
+];
+//子表单数据
+//子表表格配置
+export const okkiLinkedinMarketingDataDetailColumns: JVxeColumn[] = [
+    {
+      title: '文章id',
+      key: 'articleId',
+      type: JVxeTypes.input,
+      width:"200px",
+      placeholder: '请输入${title}',
+      defaultValue:'',
+    },
+    {
+      title: '标题',
+      key: 'title',
+      type: JVxeTypes.input,
+      width:"200px",
+      placeholder: '请输入${title}',
+      defaultValue:'',
+    },
+    {
+      title: '链接',
+      key: 'url',
+      type: JVxeTypes.input,
+      width:"200px",
+      placeholder: '请输入${title}',
+      defaultValue:'',
+    },
+    {
+      title: '创建日期',
+      key: 'createTime',
+      type: JVxeTypes.datetime,
+      width:"200px",
+      placeholder: '请输入${title}',
+      defaultValue:'',
+    },
+  ]
+
+// 高级查询数据
+export const superQuerySchema = {
+  siteId: {title: '站点id',order: 0,view: 'text', type: 'string',},
+  status: {title: '同步状态',order: 1,view: 'number', type: 'number',},
+  createTime: {title: '创建日期',order: 2,view: 'datetime', type: 'string',},
+  //子表高级查询
+  okkiLinkedinMarketingDataDetail: {
+    title: 'Linkedin营销效果数据详情',
+    view: 'table',
+    fields: {
+        articleId: {title: '文章id',order: 0,view: 'text', type: 'string',},
+        title: {title: '标题',order: 1,view: 'text', type: 'string',},
+        url: {title: '链接',order: 2,view: 'text', type: 'string',},
+        createTime: {title: '创建日期',order: 3,view: 'datetime', type: 'string',},
+    }
+  },
+};

+ 187 - 0
jeecgboot-vue3/src/views/okki/linkedin/OkkiLinkedinMarketingDataList.vue

@@ -0,0 +1,187 @@
+<template>
+  <div>
+    <!--引用表格-->
+   <BasicTable @register="registerTable" :rowSelection="rowSelection">
+     <!--插槽:table标题-->
+      <template #tableTitle>
+          <a-button type="primary" @click="handleAdd" preIcon="ant-design:plus-outlined"> 新增</a-button>
+          <a-button  type="primary" preIcon="ant-design:export-outlined" @click="onExportXls"> 导出</a-button>
+          <j-upload-button  type="primary" preIcon="ant-design:import-outlined" @click="onImportXls">导入</j-upload-button>
+          <a-dropdown v-if="selectedRowKeys.length > 0">
+              <template #overlay>
+                <a-menu>
+                  <a-menu-item key="1" @click="batchHandleDelete">
+                    <Icon icon="ant-design:delete-outlined"></Icon>
+                    删除
+                  </a-menu-item>
+                </a-menu>
+              </template>
+              <a-button>批量操作
+                <Icon icon="mdi:chevron-down"></Icon>
+              </a-button>
+        </a-dropdown>
+        <!-- 高级查询 -->
+        <super-query :config="superQueryConfig" @search="handleSuperQuery" />
+      </template>
+       <!--操作栏-->
+      <template #action="{ record }">
+        <TableAction :actions="getTableAction(record)" :dropDownActions="getDropDownAction(record)"/>
+      </template>
+      <!--字段回显插槽-->
+      <template v-slot:bodyCell="{ column, record, index, text }">
+      </template>
+    </BasicTable>
+    <!-- 表单区域 -->
+    <OkkiLinkedinMarketingDataModal @register="registerModal" @success="handleSuccess"></OkkiLinkedinMarketingDataModal>
+  </div>
+</template>
+
+<script lang="ts" name="linkedin-okkiLinkedinMarketingData" setup>
+  import {ref, reactive, computed, unref} from 'vue';
+  import {BasicTable, useTable, TableAction} from '/@/components/Table';
+  import { useListPage } from '/@/hooks/system/useListPage'
+  import {useModal} from '/@/components/Modal';
+  import OkkiLinkedinMarketingDataModal from './components/OkkiLinkedinMarketingDataModal.vue'
+  import {columns, searchFormSchema, superQuerySchema} from './OkkiLinkedinMarketingData.data';
+  import {list, deleteOne, batchDelete, getImportUrl,getExportUrl} from './OkkiLinkedinMarketingData.api';
+  import {downloadFile} from '/@/utils/common/renderUtils';
+  import { useUserStore } from '/@/store/modules/user';
+  const queryParam = reactive<any>({});
+  const userStore = useUserStore();
+  const checkedKeys = ref<Array<string | number>>([]);
+  //注册model
+  const [registerModal, {openModal}] = useModal();
+   //注册table数据
+  const { prefixCls,tableContext,onExportXls,onImportXls } = useListPage({
+      tableProps:{
+           title: 'Linkedin营销效果数据',
+           api: list,
+           columns,
+           canResize:false,
+           formConfig: {
+                //labelWidth: 120,
+                schemas: searchFormSchema,
+                autoSubmitOnEnter:true,
+                showAdvancedButton:true,
+                fieldMapToNumber: [
+                ],
+                fieldMapToTime: [
+                ],
+            },
+           actionColumn: {
+               width: 120,
+               fixed:'right'
+           },
+           beforeFetch: (params) => {
+             return Object.assign(params, queryParam);
+           },
+        },
+        exportConfig: {
+            name:"Linkedin营销效果数据",
+            url: getExportUrl,
+            params: queryParam,
+        },
+        importConfig: {
+            url: getImportUrl,
+            success: handleSuccess
+        },
+    })
+
+  const [registerTable, {reload},{ rowSelection, selectedRowKeys }] = tableContext
+
+  // 高级查询配置
+  const superQueryConfig = reactive(superQuerySchema);
+
+  /**
+   * 高级查询事件
+   */
+  function handleSuperQuery(params) {
+    Object.keys(params).map((k) => {
+      queryParam[k] = params[k];
+    });
+    reload();
+  }
+   /**
+    * 新增事件
+    */
+  function handleAdd() {
+     openModal(true, {
+       isUpdate: false,
+       showFooter: true,
+     });
+  }
+   /**
+    * 编辑事件
+    */
+  function handleEdit(record: Recordable) {
+     openModal(true, {
+       record,
+       isUpdate: true,
+       showFooter: true,
+     });
+   }
+   /**
+    * 详情
+   */
+  function handleDetail(record: Recordable) {
+     openModal(true, {
+       record,
+       isUpdate: true,
+       showFooter: false,
+     });
+   }
+   /**
+    * 删除事件
+    */
+  async function handleDelete(record) {
+     await deleteOne({id: record.id}, handleSuccess);
+   }
+   /**
+    * 批量删除事件
+    */
+  async function batchHandleDelete() {
+     await batchDelete({ids: selectedRowKeys.value}, handleSuccess);
+   }
+   /**
+    * 成功回调
+    */
+  function handleSuccess() {
+      (selectedRowKeys.value = []) && reload();
+   }
+   /**
+      * 操作栏
+      */
+  function getTableAction(record){
+       return [
+         {
+           label: '编辑',
+           onClick: handleEdit.bind(null, record),
+         }
+       ]
+   }
+
+
+  /**
+   * 下拉操作栏
+   */
+  function getDropDownAction(record){
+    return [
+      {
+        label: '详情',
+        onClick: handleDetail.bind(null, record),
+      }, {
+        label: '删除',
+        popConfirm: {
+          title: '是否确认删除',
+          confirm: handleDelete.bind(null, record),
+          placement: 'topLeft',
+        }
+      }
+    ]
+  }
+
+</script>
+
+<style scoped>
+
+</style>

+ 26 - 0
jeecgboot-vue3/src/views/okki/linkedin/V20240516_1__menu_insert_OkkiLinkedinMarketingData.sql

@@ -0,0 +1,26 @@
+-- 注意:该页面对应的前台目录为views/linkedin文件夹下
+-- 如果你想更改到其他目录,请修改sql中component字段对应的值
+
+
+INSERT INTO sys_permission(id, parent_id, name, url, component, component_name, redirect, menu_type, perms, perms_type, sort_no, always_show, icon, is_route, is_leaf, keep_alive, hidden, hide_tab, description, status, del_flag, rule_flag, create_by, create_time, update_by, update_time, internal_or_external) 
+VALUES ('2024051604434610120', NULL, 'Linkedin营销效果数据', '/linkedin/okkiLinkedinMarketingDataList', 'linkedin/OkkiLinkedinMarketingDataList', NULL, NULL, 0, NULL, '1', 0.00, 0, NULL, 1, 0, 0, 0, 0, NULL, '1', 0, 0, 'admin', '2024-05-16 16:43:12', NULL, NULL, 0);
+
+-- 权限控制sql
+-- 新增
+INSERT INTO sys_permission(id, parent_id, name, url, component, is_route, component_name, redirect, menu_type, perms, perms_type, sort_no, always_show, icon, is_leaf, keep_alive, hidden, hide_tab, description, create_by, create_time, update_by, update_time, del_flag, rule_flag, status, internal_or_external)
+VALUES ('2024051604434610121', '2024051604434610120', '添加Linkedin营销效果数据', NULL, NULL, 0, NULL, NULL, 2, 'linkedin:okki_linkedin_marketing_data:add', '1', NULL, 0, NULL, 1, 0, 0, 0, NULL, 'admin', '2024-05-16 16:43:12', NULL, NULL, 0, 0, '1', 0);
+-- 编辑
+INSERT INTO sys_permission(id, parent_id, name, url, component, is_route, component_name, redirect, menu_type, perms, perms_type, sort_no, always_show, icon, is_leaf, keep_alive, hidden, hide_tab, description, create_by, create_time, update_by, update_time, del_flag, rule_flag, status, internal_or_external)
+VALUES ('2024051604434610122', '2024051604434610120', '编辑Linkedin营销效果数据', NULL, NULL, 0, NULL, NULL, 2, 'linkedin:okki_linkedin_marketing_data:edit', '1', NULL, 0, NULL, 1, 0, 0, 0, NULL, 'admin', '2024-05-16 16:43:12', NULL, NULL, 0, 0, '1', 0);
+-- 删除
+INSERT INTO sys_permission(id, parent_id, name, url, component, is_route, component_name, redirect, menu_type, perms, perms_type, sort_no, always_show, icon, is_leaf, keep_alive, hidden, hide_tab, description, create_by, create_time, update_by, update_time, del_flag, rule_flag, status, internal_or_external)
+VALUES ('2024051604434610123', '2024051604434610120', '删除Linkedin营销效果数据', NULL, NULL, 0, NULL, NULL, 2, 'linkedin:okki_linkedin_marketing_data:delete', '1', NULL, 0, NULL, 1, 0, 0, 0, NULL, 'admin', '2024-05-16 16:43:12', NULL, NULL, 0, 0, '1', 0);
+-- 批量删除
+INSERT INTO sys_permission(id, parent_id, name, url, component, is_route, component_name, redirect, menu_type, perms, perms_type, sort_no, always_show, icon, is_leaf, keep_alive, hidden, hide_tab, description, create_by, create_time, update_by, update_time, del_flag, rule_flag, status, internal_or_external)
+VALUES ('2024051604434610124', '2024051604434610120', '批量删除Linkedin营销效果数据', NULL, NULL, 0, NULL, NULL, 2, 'linkedin:okki_linkedin_marketing_data:deleteBatch', '1', NULL, 0, NULL, 1, 0, 0, 0, NULL, 'admin', '2024-05-16 16:43:12', NULL, NULL, 0, 0, '1', 0);
+-- 导出excel
+INSERT INTO sys_permission(id, parent_id, name, url, component, is_route, component_name, redirect, menu_type, perms, perms_type, sort_no, always_show, icon, is_leaf, keep_alive, hidden, hide_tab, description, create_by, create_time, update_by, update_time, del_flag, rule_flag, status, internal_or_external)
+VALUES ('2024051604434610125', '2024051604434610120', '导出excel_Linkedin营销效果数据', NULL, NULL, 0, NULL, NULL, 2, 'linkedin:okki_linkedin_marketing_data:exportXls', '1', NULL, 0, NULL, 1, 0, 0, 0, NULL, 'admin', '2024-05-16 16:43:12', NULL, NULL, 0, 0, '1', 0);
+-- 导入excel
+INSERT INTO sys_permission(id, parent_id, name, url, component, is_route, component_name, redirect, menu_type, perms, perms_type, sort_no, always_show, icon, is_leaf, keep_alive, hidden, hide_tab, description, create_by, create_time, update_by, update_time, del_flag, rule_flag, status, internal_or_external)
+VALUES ('2024051604434610126', '2024051604434610120', '导入excel_Linkedin营销效果数据', NULL, NULL, 0, NULL, NULL, 2, 'linkedin:okki_linkedin_marketing_data:importExcel', '1', NULL, 0, NULL, 1, 0, 0, 0, NULL, 'admin', '2024-05-16 16:43:12', NULL, NULL, 0, 0, '1', 0);

+ 171 - 0
jeecgboot-vue3/src/views/okki/linkedin/components/OkkiLinkedinMarketingDataForm.vue

@@ -0,0 +1,171 @@
+<template>
+  <div>
+  <!-- 子表单区域 -->
+    <a-tabs v-model:activeKey="activeKey" animated @change="handleChangeTabs">
+     <!--主表区域 -->
+     <a-tab-pane tab="Linkedin营销效果数据" :key="refKeys[0]" :forceRender="true" :style="tabsStyle">
+       <BasicForm @register="registerForm" ref="formRef"/>
+     </a-tab-pane>
+  <!--子表单区域 -->
+      <a-tab-pane tab="Linkedin营销效果数据详情" key="okkiLinkedinMarketingDataDetail" :forceRender="true" :style="tabsStyle">
+        <JVxeTable
+          keep-source
+          resizable
+          ref="okkiLinkedinMarketingDataDetail"
+          v-if="okkiLinkedinMarketingDataDetailTable.show"
+          :loading="okkiLinkedinMarketingDataDetailTable.loading"
+          :columns="okkiLinkedinMarketingDataDetailTable.columns"
+          :dataSource="okkiLinkedinMarketingDataDetailTable.dataSource"
+          :height="340"
+          :disabled="formDisabled"
+          :rowNumber="true"
+          :rowSelection="true"
+          :toolbar="true"
+          />
+      </a-tab-pane>
+    </a-tabs>
+
+    <div style="width: 100%;text-align: center;margin-top: 10px;" v-if="showFlowSubmitButton">
+      <a-button preIcon="ant-design:check-outlined" style="width: 126px" type="primary" @click="handleSubmit">提 交</a-button>
+    </div>
+  </div>
+</template>
+
+<script lang="ts" setup>
+    import { defHttp } from '/@/utils/http/axios';
+    import {ref, computed, unref,reactive, onMounted, defineProps } from 'vue';
+    import {BasicForm, useForm} from '/@/components/Form/index';
+    import { JVxeTable } from '/@/components/jeecg/JVxeTable'
+    import { useJvxeMethod } from '/@/hooks/system/useJvxeMethods.ts'
+    import {formSchema,okkiLinkedinMarketingDataDetailColumns} from '../OkkiLinkedinMarketingData.data';
+    import {saveOrUpdate,okkiLinkedinMarketingDataDetailList} from '../OkkiLinkedinMarketingData.api';
+    import { VALIDATE_FAILED } from '/@/utils/common/vxeUtils'
+    const refKeys = ref(['okkiLinkedinMarketingData','okkiLinkedinMarketingDataDetail', ]);
+    const activeKey = ref('okkiLinkedinMarketingData');
+    const okkiLinkedinMarketingDataDetail = ref();
+    const tableRefs = {okkiLinkedinMarketingDataDetail, };
+    const okkiLinkedinMarketingDataDetailTable = reactive({
+          loading: false,
+          dataSource: [],
+          columns:okkiLinkedinMarketingDataDetailColumns,
+          show: false
+    })
+
+    const props = defineProps({
+      formData: { type: Object, default: ()=>{} },
+      formBpm: { type: Boolean, default: true }
+    });
+    const formDisabled = computed(()=>{
+      if(props.formBpm === true){
+        if(props.formData.disabled === false){
+          return false;
+        }
+      }
+      return true;
+    });
+    // 是否显示提交按钮
+    const showFlowSubmitButton = computed(()=>{
+      if(props.formBpm === true){
+        if(props.formData.disabled === false){
+          return true
+        }
+      }
+      return false
+    });
+    
+    //表单配置
+    const [registerForm, {setProps,resetFields, setFieldsValue, validate}] = useForm({
+        labelWidth: 150,
+        schemas: formSchema,
+        showActionButtonGroup: false,
+        baseColProps: {span: 24}
+    });
+
+    onMounted(()=>{
+      initFormData();
+    });
+    //渲染流程表单数据
+    const queryByIdUrl = '/linkedin/okkiLinkedinMarketingData/queryById';
+    async function initFormData(){
+      if(props.formBpm === true){
+        await reset();
+        let params = {id: props.formData.dataId};
+        const data = await defHttp.get({url: queryByIdUrl, params});
+        //表单赋值
+        await setFieldsValue({
+          ...data
+        });
+        requestSubTableData(okkiLinkedinMarketingDataDetailList, {id: data.id}, okkiLinkedinMarketingDataDetailTable, ()=>{
+          okkiLinkedinMarketingDataDetailTable.show = true;
+        })
+        // 隐藏底部时禁用整个表单
+        setProps({ disabled: formDisabled.value })
+      }
+    }
+
+    //方法配置
+    const [handleChangeTabs,handleSubmit,requestSubTableData,formRef] = useJvxeMethod(requestAddOrEdit,classifyIntoFormData,tableRefs,activeKey,refKeys);
+    // 弹窗tabs滚动区域的高度
+    const tabsStyle = computed(() => {
+      let height: Nullable<string> = null
+      let minHeight = '100px'
+      // 弹窗wrapper
+      let overflow = 'auto';
+      return {height, minHeight, overflow};
+    })
+
+    async function reset(){
+      await resetFields();
+      activeKey.value = 'okkiLinkedinMarketingData';
+      okkiLinkedinMarketingDataDetailTable.dataSource = [];
+    }
+    function classifyIntoFormData(allValues) {
+         let main = Object.assign({}, allValues.formValue)
+         return {
+           ...main, // 展开
+           okkiLinkedinMarketingDataDetailList: allValues.tablesValue[0].tableData,
+         }
+       }
+    //表单提交事件
+    async function requestAddOrEdit(values) {
+      //提交表单
+      await saveOrUpdate(values, true);
+    }
+</script>
+
+<style lang="less" scoped>
+/** 时间和数字输入框样式 */
+    :deep(.ant-input-number){
+        width: 100%
+    }
+
+    :deep(.ant-calendar-picker){
+        width: 100%
+    }
+</style>
+
+<style lang="less">
+// Online表单Tab风格专属样式
+.j-cgform-tab-modal {
+  .ant-modal-header {
+    padding-top: 8px;
+    padding-bottom: 8px;
+    border-bottom: none !important;
+  }
+
+  .ant-modal .ant-modal-body > .scrollbar,
+  .ant-tabs-nav .ant-tabs-tab {
+    padding-top: 0;
+  }
+
+  .ant-tabs-top-bar {
+    width: calc(100% - 55px);
+    position: relative;
+    left: -14px;
+  }
+
+  .ant-tabs .ant-tabs-top-content > .ant-tabs-tabpane {
+    overflow: hidden auto;
+  }
+}
+</style>

+ 158 - 0
jeecgboot-vue3/src/views/okki/linkedin/components/OkkiLinkedinMarketingDataModal.vue

@@ -0,0 +1,158 @@
+<template>
+  <BasicModal ref="modalRef" destroyOnClose wrapClassName="j-cgform-tab-modal" v-bind="$attrs" @register="registerModal" :width="800" @ok="handleSubmit">
+  <!-- 子表单区域 -->
+    <a-tabs v-model:activeKey="activeKey" animated @change="handleChangeTabs">
+     <!--主表区域 -->
+     <a-tab-pane tab="Linkedin营销效果数据" :key="refKeys[0]" :forceRender="true" :style="tabsStyle">
+       <BasicForm @register="registerForm" ref="formRef"/>
+     </a-tab-pane>
+  <!--子表单区域 -->
+      <a-tab-pane tab="Linkedin营销效果数据详情" key="okkiLinkedinMarketingDataDetail" :forceRender="true" :style="tabsStyle">
+        <JVxeTable
+          keep-source
+          resizable
+          ref="okkiLinkedinMarketingDataDetail"
+          :loading="okkiLinkedinMarketingDataDetailTable.loading"
+          :columns="okkiLinkedinMarketingDataDetailTable.columns"
+          :dataSource="okkiLinkedinMarketingDataDetailTable.dataSource"
+          :height="340"
+          :disabled="formDisabled"
+          :rowNumber="true"
+          :rowSelection="true"
+          :toolbar="true"
+          />
+      </a-tab-pane>
+    </a-tabs>
+  </BasicModal>
+</template>
+
+<script lang="ts" setup>
+    import {ref, computed, unref,reactive} from 'vue';
+    import {BasicModal, useModalInner} from '/@/components/Modal';
+    import {BasicForm, useForm} from '/@/components/Form/index';
+    import { JVxeTable } from '/@/components/jeecg/JVxeTable'
+    import { useJvxeMethod } from '/@/hooks/system/useJvxeMethods.ts'
+    import {formSchema,okkiLinkedinMarketingDataDetailColumns} from '../OkkiLinkedinMarketingData.data';
+    import {saveOrUpdate,okkiLinkedinMarketingDataDetailList} from '../OkkiLinkedinMarketingData.api';
+    import { VALIDATE_FAILED } from '/@/utils/common/vxeUtils'
+    // Emits声明
+    const emit = defineEmits(['register','success']);
+    const isUpdate = ref(true);
+    const formDisabled = ref(false);
+    const modalRef = ref();
+    const refKeys = ref(['okkiLinkedinMarketingData','okkiLinkedinMarketingDataDetail', ]);
+    const activeKey = ref('okkiLinkedinMarketingData');
+    const okkiLinkedinMarketingDataDetail = ref();
+    const tableRefs = {okkiLinkedinMarketingDataDetail, };
+    const okkiLinkedinMarketingDataDetailTable = reactive({
+          loading: false,
+          dataSource: [],
+          columns:okkiLinkedinMarketingDataDetailColumns
+    })
+    //表单配置
+    const [registerForm, {setProps,resetFields, setFieldsValue, validate}] = useForm({
+        //labelWidth: 150,
+        schemas: formSchema,
+        showActionButtonGroup: false,
+        baseColProps: {span: 24}
+    });
+     //表单赋值
+    const [registerModal, {setModalProps, closeModal}] = useModalInner(async (data) => {
+        //重置表单
+        await reset();
+        setModalProps({confirmLoading: false,showCancelBtn:data?.showFooter,showOkBtn:data?.showFooter});
+        isUpdate.value = !!data?.isUpdate;
+        formDisabled.value = !data?.showFooter;
+        if (unref(isUpdate)) {
+            //表单赋值
+            await setFieldsValue({
+                ...data.record,
+            });
+             requestSubTableData(okkiLinkedinMarketingDataDetailList, {id:data?.record?.id}, okkiLinkedinMarketingDataDetailTable)
+        }
+        // 隐藏底部时禁用整个表单
+       setProps({ disabled: !data?.showFooter })
+    });
+    //方法配置
+    const [handleChangeTabs,handleSubmit,requestSubTableData,formRef] = useJvxeMethod(requestAddOrEdit,classifyIntoFormData,tableRefs,activeKey,refKeys);
+    // 弹窗tabs滚动区域的高度
+    const tabsStyle = computed(() => {
+      let height: Nullable<string> = null
+      let minHeight = '100px'
+      let maxHeight: Nullable<string> = '500px'
+      // 弹窗wrapper
+      let modalWrapperRef = modalRef.value?.modalWrapperRef
+      if (modalWrapperRef) {
+        if (modalWrapperRef.fullScreen) {
+          height = 'calc(' + modalWrapperRef.spinStyle.height + ' - 50px)';
+          maxHeight = null
+        }
+      }
+      let overflow = 'auto';
+      return {height, minHeight, maxHeight, overflow};
+    })
+
+    async function reset(){
+      await resetFields();
+      activeKey.value = 'okkiLinkedinMarketingData';
+      okkiLinkedinMarketingDataDetailTable.dataSource = [];
+    }
+    function classifyIntoFormData(allValues) {
+         let main = Object.assign({}, allValues.formValue)
+         return {
+           ...main, // 展开
+           okkiLinkedinMarketingDataDetailList: allValues.tablesValue[0].tableData,
+         }
+       }
+    //表单提交事件
+    async function requestAddOrEdit(values) {
+        try {
+            setModalProps({confirmLoading: true});
+            //提交表单
+            await saveOrUpdate(values, isUpdate.value);
+            //关闭弹窗
+            closeModal();
+            //刷新列表
+            emit('success');
+        } finally {
+            setModalProps({confirmLoading: false});
+        }
+    }
+</script>
+
+<style lang="less" scoped>
+/** 时间和数字输入框样式 */
+    :deep(.ant-input-number){
+        width: 100%
+    }
+
+    :deep(.ant-calendar-picker){
+        width: 100%
+    }
+</style>
+
+<style lang="less">
+// Online表单Tab风格专属样式
+.j-cgform-tab-modal {
+  .ant-modal-header {
+    padding-top: 8px;
+    padding-bottom: 8px;
+    border-bottom: none !important;
+  }
+
+  .ant-modal .ant-modal-body > .scrollbar,
+  .ant-tabs-nav .ant-tabs-tab {
+    padding-top: 0;
+  }
+
+  .ant-tabs-top-bar {
+    width: calc(100% - 55px);
+    position: relative;
+    left: -14px;
+  }
+
+  .ant-tabs .ant-tabs-top-content > .ant-tabs-tabpane {
+    overflow: hidden auto;
+  }
+}
+</style>