Pārlūkot izejas kodu

feat:roi短剧数量

pudongliang 4 mēneši atpakaļ
vecāks
revīzija
b640f02c41
36 mainītis faili ar 258 papildinājumiem un 110 dzēšanām
  1. 6 0
      pom.xml
  2. 1 1
      portal/dist/assets/accountGroup-gxywsH4V.js
  3. 1 1
      portal/dist/assets/adPlanConf-BCIxiJ0v.js
  4. 1 1
      portal/dist/assets/auth-D2VlC4E-.js
  5. 1 1
      portal/dist/assets/conversion-DckJKH-q.js
  6. 0 0
      portal/dist/assets/detail-CJpvgGTZ.js
  7. 1 1
      portal/dist/assets/drama-DraB1Q15.js
  8. 0 0
      portal/dist/assets/index-B0IMmz9J.js
  9. 0 0
      portal/dist/assets/index-BSjp28g4.js
  10. 0 0
      portal/dist/assets/index-BqT3lR4P.js
  11. 0 0
      portal/dist/assets/index-C4gIQ4qi.js
  12. 0 0
      portal/dist/assets/index-CTI3OMrW.js
  13. 1 1
      portal/dist/assets/index-ClkJ0dy1.js
  14. 0 0
      portal/dist/assets/index-CrK45iSX.js
  15. 0 0
      portal/dist/assets/index-CwExpFti.js
  16. 0 0
      portal/dist/assets/index-Djjg4ULK.js
  17. 0 0
      portal/dist/assets/index-DzARqsQh.js
  18. 0 0
      portal/dist/assets/index-DzkzXIUd.js
  19. 0 0
      portal/dist/assets/index-cY0oqNok.js
  20. 0 0
      portal/dist/assets/index-gQIG_Zsk.js
  21. 1 1
      portal/dist/assets/ossFile-BJHL-jrG.js
  22. 0 0
      portal/dist/assets/request-Db_y4xFI.js
  23. 1 1
      portal/dist/assets/user-BhSiUb9o.js
  24. 1 1
      portal/dist/index.html
  25. 65 18
      portal/src/views/ad-plan-conf/index.vue
  26. 38 0
      src/main/java/com/moka/gdtauto/BaseCodeGenerator.java
  27. 1 0
      src/main/java/com/moka/gdtauto/controller/AccountGroupController.java
  28. 83 58
      src/main/java/com/moka/gdtauto/controller/AdPlanConfController.java
  29. 2 1
      src/main/java/com/moka/gdtauto/controller/TencentAssetDramaController.java
  30. 2 0
      src/main/java/com/moka/gdtauto/controller/vo/CreateAdPlanConfRequest.java
  31. 2 0
      src/main/java/com/moka/gdtauto/controller/vo/UpdateAdPlanConfRequest.java
  32. 2 0
      src/main/java/com/moka/gdtauto/entity/AdPlan.java
  33. 2 1
      src/main/java/com/moka/gdtauto/service/TencentAssetDramaService.java
  34. 43 0
      src/main/java/com/moka/gdtauto/task/SyncDramaAssetTask.java
  35. 2 22
      src/main/java/com/moka/gdtauto/task/TokenRefreshTask.java
  36. 1 1
      src/test/java/com/moka/gdtauto/service/TencentAssetDramaTest.java

+ 6 - 0
pom.xml

@@ -90,6 +90,12 @@
             <artifactId>mybatis-plus-jsqlparser</artifactId>
         </dependency>
 
+        <dependency>
+            <groupId>com.baomidou</groupId>
+            <artifactId>mybatis-plus-generator</artifactId>
+            <version>${mybatis-plus.version}</version>
+        </dependency>
+
         <!-- Dynamic DataSource -->
          <dependency>
             <groupId>com.baomidou</groupId>

+ 1 - 1
portal/dist/assets/accountGroup-B-ANCzZP.js → portal/dist/assets/accountGroup-gxywsH4V.js

@@ -1 +1 @@
-import{r as u}from"./request--HXk_9Id.js";function c(t){return u({url:"/api/account-group/create",method:"post",data:t})}function e(t){return u({url:"/api/account-group/update",method:"post",data:t})}function n(t){return u({url:`/api/account-group/${t}`,method:"delete"})}function a(t=1,o=10){return u({url:"/api/account-group/list",method:"get",params:{pageNum:t,pageSize:o}})}function p(){return u({url:"/api/account-group/all",method:"get"})}function i(t){return u({url:`/api/account-group/${t}/accounts`,method:"get"})}export{i as a,p as b,c,n as d,a as g,e as u};
+import{r as u}from"./request-Db_y4xFI.js";function c(t){return u({url:"/api/account-group/create",method:"post",data:t})}function e(t){return u({url:"/api/account-group/update",method:"post",data:t})}function n(t){return u({url:`/api/account-group/${t}`,method:"delete"})}function a(t=1,o=10){return u({url:"/api/account-group/list",method:"get",params:{pageNum:t,pageSize:o}})}function p(){return u({url:"/api/account-group/all",method:"get"})}function i(t){return u({url:`/api/account-group/${t}/accounts`,method:"get"})}export{i as a,p as b,c,n as d,a as g,e as u};

+ 1 - 1
portal/dist/assets/adPlanConf-4lCV7fO_.js → portal/dist/assets/adPlanConf-BCIxiJ0v.js

@@ -1 +1 @@
-import{r as a}from"./request--HXk_9Id.js";function r(n){return a({url:"/api/ad-plan-conf/reCreate",method:"post",data:n})}function o(n){return a({url:"/api/ad-plan-conf/generate-plan",method:"post",data:n})}function l(n){return a({url:`/api/ad-plan-conf/reGeneratePlan/${n}`,method:"get"})}function d(n){return a({url:"/api/ad-plan-conf/create",method:"post",data:n})}function u(n){return a({url:"/api/ad-plan-conf/update",method:"post",data:n})}function p(n){return a({url:`/api/ad-plan-conf/${n}`,method:"delete"})}function i(n=1,e=10){return a({url:"/api/ad-plan-conf/list",method:"get",params:{pageNum:n,pageSize:e}})}function f(n){return a({url:`/api/ad-plan-conf/${n}`,method:"get"})}function c(n){return a({url:"/api/ad-plan/list",method:"get",params:n})}function s(n){return a({url:`/api/ad-plan-creative/plan/${n}`,method:"get"})}export{o as a,f as b,d as c,p as d,c as e,l as f,i as g,s as h,r,u};
+import{r as a}from"./request-Db_y4xFI.js";function r(n){return a({url:"/api/ad-plan-conf/reCreate",method:"post",data:n})}function o(n){return a({url:"/api/ad-plan-conf/generate-plan",method:"post",data:n})}function l(n){return a({url:`/api/ad-plan-conf/reGeneratePlan/${n}`,method:"get"})}function d(n){return a({url:"/api/ad-plan-conf/create",method:"post",data:n})}function u(n){return a({url:"/api/ad-plan-conf/update",method:"post",data:n})}function p(n){return a({url:`/api/ad-plan-conf/${n}`,method:"delete"})}function i(n=1,e=10){return a({url:"/api/ad-plan-conf/list",method:"get",params:{pageNum:n,pageSize:e}})}function f(n){return a({url:`/api/ad-plan-conf/${n}`,method:"get"})}function c(n){return a({url:"/api/ad-plan/list",method:"get",params:n})}function s(n){return a({url:`/api/ad-plan-creative/plan/${n}`,method:"get"})}export{o as a,f as b,d as c,p as d,c as e,l as f,i as g,s as h,r,u};

+ 1 - 1
portal/dist/assets/auth-Gu-V_Nzc.js → portal/dist/assets/auth-D2VlC4E-.js

@@ -1 +1 @@
-import{r as t}from"./request--HXk_9Id.js";function i(){return t({url:"/api/gdt/auth/authorize-url",method:"get"})}function n(r){return t({url:"/api/gdt/auth/refresh",method:"post",params:r})}function u(){return t({url:"/api/gdt/auth/list",method:"get"})}function a(){return u()}function o(){return t({url:"/api/gdt/auth/expiring",method:"get"})}export{o as a,a as b,i as g,u as l,n as r};
+import{r as t}from"./request-Db_y4xFI.js";function i(){return t({url:"/api/gdt/auth/authorize-url",method:"get"})}function n(r){return t({url:"/api/gdt/auth/refresh",method:"post",params:r})}function u(){return t({url:"/api/gdt/auth/list",method:"get"})}function a(){return u()}function o(){return t({url:"/api/gdt/auth/expiring",method:"get"})}export{o as a,a as b,i as g,u as l,n as r};

+ 1 - 1
portal/dist/assets/conversion-3s92Ajx3.js → portal/dist/assets/conversion-DckJKH-q.js

@@ -1 +1 @@
-import{r as t}from"./request--HXk_9Id.js";function e(n,o){return t({url:"/api/gdt/conversion/sync",method:"post",params:{orgAccountId:n,accountId:o}})}function s(n=1,o=20){return t({url:"/api/gdt/conversion/list",method:"get",params:{page:n,pageSize:o}})}function i(n){return t({url:"/api/gdt/conversion/detail",method:"get",params:{conversionId:n}})}function a(){return t({url:"/api/gdt/conversion/all",method:"get"})}export{s as a,i as b,a as g,e as s};
+import{r as t}from"./request-Db_y4xFI.js";function e(n,o){return t({url:"/api/gdt/conversion/sync",method:"post",params:{orgAccountId:n,accountId:o}})}function s(n=1,o=20){return t({url:"/api/gdt/conversion/list",method:"get",params:{page:n,pageSize:o}})}function i(n){return t({url:"/api/gdt/conversion/detail",method:"get",params:{conversionId:n}})}function a(){return t({url:"/api/gdt/conversion/all",method:"get"})}export{s as a,i as b,a as g,e as s};

Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 0
portal/dist/assets/detail-CJpvgGTZ.js


+ 1 - 1
portal/dist/assets/drama-CQYy29sQ.js → portal/dist/assets/drama-DraB1Q15.js

@@ -1 +1 @@
-import{r as t}from"./request--HXk_9Id.js";function n(a){return t({url:"/api/gdt/asset/drama/sync",method:"post",params:{accountId:a}})}function m(a=1,s=20,r=""){return t({url:"/api/gdt/asset/drama/list",method:"get",params:{dramaName:r,page:a,pageSize:s}})}function d(a){return t({url:"/api/gdt/asset/drama/myDramaAssets",method:"get",params:{dramaName:a}})}function o(){return t({url:"/api/gdt/asset/drama/sync/conf/myConf",method:"get"})}function u(a){return t({url:"/api/gdt/asset/drama/sync/conf/add",method:"post",data:a})}function i(a){return t({url:"/api/gdt/asset/drama/sync/conf/delete",method:"post",params:{id:a}})}export{o as a,u as b,i as d,m as g,d as m,n as s};
+import{r as t}from"./request-Db_y4xFI.js";function n(a){return t({url:"/api/gdt/asset/drama/sync",method:"post",params:{accountId:a}})}function m(a=1,s=20,r=""){return t({url:"/api/gdt/asset/drama/list",method:"get",params:{dramaName:r,page:a,pageSize:s}})}function d(a){return t({url:"/api/gdt/asset/drama/myDramaAssets",method:"get",params:{dramaName:a}})}function o(){return t({url:"/api/gdt/asset/drama/sync/conf/myConf",method:"get"})}function u(a){return t({url:"/api/gdt/asset/drama/sync/conf/add",method:"post",data:a})}function i(a){return t({url:"/api/gdt/asset/drama/sync/conf/delete",method:"post",params:{id:a}})}export{o as a,u as b,i as d,m as g,d as m,n as s};

Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 0
portal/dist/assets/index-B0IMmz9J.js


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 0
portal/dist/assets/index-BSjp28g4.js


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 0
portal/dist/assets/index-BqT3lR4P.js


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 0
portal/dist/assets/index-C4gIQ4qi.js


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 0
portal/dist/assets/index-CTI3OMrW.js


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 1 - 1
portal/dist/assets/index-ClkJ0dy1.js


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 0
portal/dist/assets/index-CrK45iSX.js


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 0
portal/dist/assets/index-CwExpFti.js


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 0
portal/dist/assets/index-Djjg4ULK.js


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 0
portal/dist/assets/index-DzARqsQh.js


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 0
portal/dist/assets/index-DzkzXIUd.js


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 0
portal/dist/assets/index-cY0oqNok.js


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 0
portal/dist/assets/index-gQIG_Zsk.js


+ 1 - 1
portal/dist/assets/ossFile-D7DM59st.js → portal/dist/assets/ossFile-BJHL-jrG.js

@@ -1 +1 @@
-import{r as t}from"./request--HXk_9Id.js";function i(e){return t({timeout:3e5,url:"/api/oss-file/upload",method:"post",data:e,headers:{"Content-Type":"multipart/form-data"}})}function o(e){return t({url:"/api/oss-file/list",method:"get",params:e})}function r(e){return t({url:`/api/oss-file/${e}`,method:"delete"})}function l(e){return t({url:"/api/oss-file/batch",method:"delete",params:{fileIds:e}})}export{l as b,r as d,o as g,i as u};
+import{r as t}from"./request-Db_y4xFI.js";function i(e){return t({timeout:3e5,url:"/api/oss-file/upload",method:"post",data:e,headers:{"Content-Type":"multipart/form-data"}})}function o(e){return t({url:"/api/oss-file/list",method:"get",params:e})}function r(e){return t({url:`/api/oss-file/${e}`,method:"delete"})}function l(e){return t({url:"/api/oss-file/batch",method:"delete",params:{fileIds:e}})}export{l as b,r as d,o as g,i as u};

Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 0
portal/dist/assets/request-Db_y4xFI.js


+ 1 - 1
portal/dist/assets/user-Bm-0GMf4.js → portal/dist/assets/user-BhSiUb9o.js

@@ -1 +1 @@
-import{r as e}from"./request--HXk_9Id.js";function s(){return e({url:"/api/user/list",method:"get"})}function u(r){return e({url:"/api/user/info",method:"get",params:r})}function n(r){return e({url:"/api/user/user-token-url",method:"get",params:r})}function o(r){return e({url:"/api/user/login",method:"post",params:r})}function a(r){return e({url:"/api/user/change-password",method:"post",params:r})}export{u as a,s as b,a as c,n as g,o as l};
+import{r as e}from"./request-Db_y4xFI.js";function s(){return e({url:"/api/user/list",method:"get"})}function u(r){return e({url:"/api/user/info",method:"get",params:r})}function n(r){return e({url:"/api/user/user-token-url",method:"get",params:r})}function o(r){return e({url:"/api/user/login",method:"post",params:r})}function a(r){return e({url:"/api/user/change-password",method:"post",params:r})}export{u as a,s as b,a as c,n as g,o as l};

+ 1 - 1
portal/dist/index.html

@@ -5,7 +5,7 @@
     <link rel="icon" type="image/svg+xml" href="/vite.svg" />
     <meta name="viewport" content="width=device-width, initial-scale=1.0" />
     <title>腾讯广告自动化管理后台</title>
-    <script type="module" crossorigin src="/assets/index-CQyQCG_b.js"></script>
+    <script type="module" crossorigin src="/assets/index-ClkJ0dy1.js"></script>
     <link rel="stylesheet" crossorigin href="/assets/index-BeI5MTU7.css">
   </head>
   <body>

+ 65 - 18
portal/src/views/ad-plan-conf/index.vue

@@ -61,7 +61,8 @@
         </el-table-column>
         <el-table-column prop="accountGroupId" label="账号组ID" width="100" />
         <el-table-column prop="conversionId" label="转化ID" width="120" />
-        <el-table-column prop="dramaId" label="短剧ID" width="100" />
+        <el-table-column prop="dramaId" label="短剧ID" width="120" />
+        <el-table-column prop="dramaAmount" label="短剧数量" width="100" />
         <el-table-column prop="wxCorpid" label="企微主体ID" width="150" show-overflow-tooltip />
         <el-table-column label="创建时间" width="180">
           <template #default="{ row }">
@@ -238,6 +239,10 @@
         </el-form-item>
 
         <el-form-item label="短剧ID" prop="dramaId" v-if="formData.adType === 2">
+          <el-radio-group v-model="dramaSort">
+            <el-radio label="最新" :value="1" />
+            <el-radio label="最老" :value="0" />
+          </el-radio-group>
           <el-select
             :disabled="valueDisabled"
             v-model="formData.dramaId"
@@ -246,7 +251,7 @@
             filterable
           >
             <el-option
-              v-for="drama in dramaList"
+              v-for="drama in sortedDramaList"
               :key="drama.id"
               :label="`${drama.marketingAssetName}[${drama.marketingAssetId}]`"
               :value="drama.marketingAssetId"
@@ -254,6 +259,18 @@
           </el-select>
         </el-form-item>
 
+        <el-form-item label="每户几部剧" prop="dramaAmount" v-if="formData.adType === 2">
+          <el-input-number
+            v-model="formData.dramaAmount"
+            :min="0"
+            :precision="0"
+            :step="1"
+            placeholder="请输入短剧每户几部剧"
+            style="width: 100%"
+            :controls="true"
+          />
+        </el-form-item>
+
         <el-form-item label="落地页IDs" prop="pageIds">
           <el-input
             v-model="formData.pageIds"
@@ -399,16 +416,7 @@
         </template>
         </el-table-column>
         <el-table-column prop="adgroupName" label="计划名称" width="200" show-overflow-tooltip />
-        <el-table-column prop="accountId" label="账号ID" width="200" show-overflow-tooltip />
-        <el-table-column prop="target" label="定向模版ID" width="150" show-overflow-tooltip />
-        <el-table-column prop="site" label="版位模版ID" width="150" show-overflow-tooltip />
-        <el-table-column prop="adType" label="广告类型" width="150">
-          <template #default="{ row }">
-            <el-tag :type="getAdTypeColor(row.adType)">
-              {{ getAdTypeText(row.adType) }}
-            </el-tag>
-          </template>
-        </el-table-column>
+        <el-table-column prop="accountId" label="账号ID" width="120" show-overflow-tooltip />
         <el-table-column prop="bidAmount" label="出价金额" width="120">
           <template #default="{ row }">
             ¥{{ (row.bidAmount / 100).toFixed(2) }}
@@ -419,9 +427,10 @@
             {{ row.deepConversionWorthRate }}
           </template>
         </el-table-column>
+          <el-table-column prop="dramaId" label="短剧ID" width="120" />
+        <el-table-column prop="dramaName" label="短剧名称" width="120" show-overflow-tooltip />
         <el-table-column prop="conversionId" label="转化ID" width="120" />
         <el-table-column prop="wxCorpid" label="企微主体ID" width="150" show-overflow-tooltip />
-        <el-table-column prop="dramaId" label="短剧ID" width="100" />
       </el-table>
       <template #footer>
         <!--生成计划按钮tip提示先进行预览操作-->
@@ -566,6 +575,7 @@ const currentPage = ref(1)
 const pageSize = ref(10)
 const total = ref(0)
 
+const dramaSort = ref(1)
 const dramaList = ref([])
 
 // 对话框
@@ -630,6 +640,13 @@ const bidAmountYuan = computed({
     formData.value.bidAmount = Math.round(val * 100)
   }
 })
+const sortedDramaList = computed(() => {
+  if (dramaSort.value === 1) {
+    return dramaList.value.sort((a, b) => b.marketingAssetId - a.marketingAssetId)
+  } else {
+    return dramaList.value.sort((a, b) => a.marketingAssetId - b.marketingAssetId)
+  }
+})
 
 // 表单验证规则
 const formRules = {
@@ -651,8 +668,8 @@ const formRules = {
   wxCorpid: [
     { required: true, message: '请输入企微主体ID', trigger: 'blur' }
   ],
-  dramaId: [
-    { required: true, message: '请输入短剧ID', trigger: 'blur' }
+  dramaAmount: [
+    { required: true, message: '请输入短剧每户几部剧', trigger: 'blur' }
   ],
   pageIds: [
     { required: true, message: '请输入页面ID', trigger: 'blur' }
@@ -741,6 +758,9 @@ const handleAdTypeChange = () => {
 }
 
 const handleCreate = () => {
+  //1,2,3,4,5,6,7,8,9,10
+  //随机一个1-10
+  const site = Math.floor(Math.random() * 10) + 1
   dialogTitle.value = '创建配置'
   editingId.value = null
   formData.value = {
@@ -748,12 +768,13 @@ const handleCreate = () => {
     accountGroupId: null,
     adType: 1,
     bidAmount: 150,
-    deepConversionWorthRate: 0.2,
+    deepConversionWorthRate: 100.00,
     conversionId: null,
     targets: '1',
-    sites: '1,2,3,4,5,6,7,8,9,10',
+    sites: site + '',
     wxCorpid: '',
     dramaId: null,
+    dramaAmount: 0,
     imageIds: '',
     pageIds: '',
     creativeFileUrls: '',
@@ -783,6 +804,7 @@ const handleEdit = (row) => {
     sites: row.sites,
     wxCorpid: row.wxCorpid || '',
     dramaId: row.dramaId,
+    dramaAmount: row.dramaAmount || 1,
     imageIds: row.imageIds || '',
     pageIds: row.pageIds || '',
     creativeFileUrls: row.creativeFileUrls || '',
@@ -830,7 +852,18 @@ const handleDelete = async (row) => {
   }
 }
 
+
 const handleReCreate = async () => {
+  await formRef.value.validate()
+  console.log(formData.value)
+  const { adType, dramaId, dramaAmount } = formData.value
+  if (adType === 2) {
+    if (dramaId == null && dramaAmount < 1) {
+      ElMessage.warning('请设置短剧配置')
+      return
+    }
+  }
+
   const res = await reCreateAdPlanConf(formData.value)
   if (res.success) {
     ElMessage.success('预览成功')
@@ -843,6 +876,14 @@ const handleReCreate = async () => {
 }
 
 const handleGeneratePlan = async () => {
+    await formRef.value.validate()
+    const { adType, dramaId, dramaAmount } = formData.value
+  if (adType === 2) {
+    if (dramaId == null && dramaAmount < 1) {
+      ElMessage.warning('请设置短剧配置')
+      return
+    }
+  }
     const data = { ...formData.value }
     data.id = editingId.value
     const res = await generatePlan(data)
@@ -859,7 +900,13 @@ const handleGeneratePlan = async () => {
 const handleSubmit = async () => {
   try {
     await formRef.value.validate()
-    
+    const { adType, dramaId, dramaAmount } = formData.value
+    if (adType === 2) {
+      if (dramaId == null &&  dramaAmount < 1) {
+        ElMessage.warning('请设置短剧配置')
+        return
+      }
+    }
     submitting.value = true
     const data = { ...formData.value }
 

+ 38 - 0
src/main/java/com/moka/gdtauto/BaseCodeGenerator.java

@@ -0,0 +1,38 @@
+package com.moka.gdtauto;
+
+import java.nio.file.Paths;
+import java.util.Collections;
+
+import com.baomidou.mybatisplus.generator.FastAutoGenerator;
+import com.baomidou.mybatisplus.generator.config.OutputFile;
+import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
+
+public class BaseCodeGenerator {
+    public static void main(String[] args) {
+        String url = "jdbc:mysql://rm-uf65d6xsxrp743w3aio.mysql.rds.aliyuncs.com:3306/gdt_auto?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai&useSSL=false&allowPublicKeyRetrieval=true";
+        FastAutoGenerator.create(url, "gdt_auto", "QA_GDT_AUTO%$PDL")
+        .globalConfig(builder -> builder
+                .author("mokamvp")
+                .outputDir(Paths.get(System.getProperty("user.dir")) + "/src/main/java")
+                .commentDate("yyyy-MM-dd")
+        )
+        .packageConfig(builder -> builder
+                .parent("com.moka.gdtauto")
+                .entity("entity")
+                .mapper("mapper")
+                .service("service")
+                .serviceImpl("service.impl")
+                .pathInfo(Collections.singletonMap(OutputFile.xml, System.getProperty("user.dir") + "/src/main/resources/mapper"))
+        )
+        .strategyConfig(builder -> builder
+                .addInclude("vn_admin_user")
+                .addTablePrefix("vn_")
+                .entityBuilder().enableFileOverride()
+                .mapperBuilder().enableFileOverride()
+                .serviceBuilder().enableFileOverride()
+                .controllerBuilder().enableRestStyle().enableFileOverride()
+        )
+        .templateEngine(new FreemarkerTemplateEngine())
+        .execute();
+    }
+}

+ 1 - 0
src/main/java/com/moka/gdtauto/controller/AccountGroupController.java

@@ -135,6 +135,7 @@ public class AccountGroupController {
             @AuthUser SysUser sysUser) {
         try {
             List<AccountGroup> accountGroups = accountGroupService.lambdaQuery()
+                    .eq(AccountGroup::getUserId, sysUser.getId())
                     .list();
             return Result.success(accountGroups, "查询成功");
         } catch (Exception e) {

+ 83 - 58
src/main/java/com/moka/gdtauto/controller/AdPlanConfController.java

@@ -10,11 +10,13 @@ import com.moka.gdtauto.entity.AccountGroup;
 import com.moka.gdtauto.entity.AccountGroupAccountRelationship;
 import com.moka.gdtauto.entity.AdPlanConf;
 import com.moka.gdtauto.entity.SysUser;
+import com.moka.gdtauto.entity.TencentAssetDrama;
 import com.moka.gdtauto.entity.AdPlan;
 import com.moka.gdtauto.entity.AdPlanCreative;
 import com.moka.gdtauto.service.SysUserService;
 
 import com.moka.gdtauto.mapper.AccountGroupAccountRelationshipMapper;
+import com.moka.gdtauto.mapper.TencentAssetDramaMapper;
 import com.moka.gdtauto.service.AccountGroupService;
 import com.moka.gdtauto.service.AdPlanConfService;
 import io.swagger.v3.oas.annotations.Operation;
@@ -50,6 +52,7 @@ public class AdPlanConfController {
     private final AccountGroupAccountRelationshipMapper relationshipMapper;
     private final SysUserService sysUserService;
     private final AccountGroupService accountGroupService;
+    private final TencentAssetDramaMapper tencentAssetDramaMapper;
 
     @Operation(summary = "预创建广告计划配置", description = "根据账户分组ID和配置ID,重新创建广告计划配置")
     @PostMapping("/reCreate")
@@ -62,7 +65,7 @@ public class AdPlanConfController {
                     new LambdaQueryWrapper<AccountGroupAccountRelationship>()
                             .eq(AccountGroupAccountRelationship::getGroupId, request.getAccountGroupId()));
 
-            List<AdPlan> plans = buildPlans(request, accountGroup, relationships);
+            List<AdPlan> plans = buildPlans(sysUser.getJobNumber(), request, accountGroup, relationships);
 
             return Result.success(plans, "重新创建广告计划配置成功");
         } catch (Exception e) {
@@ -71,7 +74,7 @@ public class AdPlanConfController {
         }
     }
 
-    private List<AdPlan> buildPlans(UpdateAdPlanConfRequest request, AccountGroup accountGroup,
+    private List<AdPlan> buildPlans(String jobNumber, UpdateAdPlanConfRequest request, AccountGroup accountGroup,
             List<AccountGroupAccountRelationship> relationships) {
         String dateTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"));
         String accountGroupName = accountGroup.getGroupName();
@@ -80,65 +83,87 @@ public class AdPlanConfController {
         String[] creativeUrlArray = creativeFileUrls.split(",");
         String[] creativeNameArray = creativeFileNames != null ? creativeFileNames.split(",") : new String[0];
         List<AdPlan> plans = new ArrayList<>();
-        int i = 0;
+        Integer dramaAmount = request.getDramaAmount();
+        Long dramaId = request.getDramaId();
+        //获取短剧 relationships.size * dramaAmount
+        List<TencentAssetDrama> dramas = List.of();
+        if (dramaAmount > 0) {
+            // 随机获取短剧 order by RAND() limit dramaAmount
+            dramas = tencentAssetDramaMapper.selectList(new LambdaQueryWrapper<TencentAssetDrama>().eq(TencentAssetDrama::getJobNumber, jobNumber).last("order by rand() limit " + dramaAmount * relationships.size()));
+            if (dramas.size() < dramaAmount * relationships.size()) {
+                throw new IllegalArgumentException("短剧数量不足,请在短剧资产管理同步");
+            }
+        } else {
+            if (dramaId != null) {
+                throw new IllegalArgumentException("请设置短剧相关配置");
+            }
+            dramas = tencentAssetDramaMapper.selectList(new LambdaQueryWrapper<TencentAssetDrama>().eq(TencentAssetDrama::getMarketingAssetId, dramaId).orderByDesc(TencentAssetDrama::getId).last("limit 1"));
+        }
+    
+        String targets = request.getTargets();
+        String sites = request.getSites();
+        String[] targetArray = targets.split(",");
+        String[] siteArray = sites.split(",");
+        int dramaIndex = 0;
         for (AccountGroupAccountRelationship relationship : relationships) {
             Long accountId = relationship.getAccountId();
-
-            String targets = request.getTargets();
-            String sites = request.getSites();
-
-            String[] targetArray = targets.split(",");
-            String[] siteArray = sites.split(",");
-            for (String target : targetArray) {
-                for (String site : siteArray) {
-                    i++;
-                    // 创建广告计划配置
-                    // 广告名称:一般是“账户分组名”+“日期时间”+"自增编号"
-                    String planName = accountGroupName.trim() + "-" + dateTime + "-" + i;
-                    AdPlan adPlan = new AdPlan();
-                    adPlan.setAdPlanConfId(request.getId());
-                    adPlan.setAccountId(accountId);
-                    adPlan.setAdgroupId(0L);
-                    adPlan.setAdgroupName(planName);
-                    adPlan.setAdType(request.getAdType());
-                    adPlan.setTarget(target);
-                    adPlan.setSite(site);
-                    adPlan.setConversionId(request.getConversionId());
-                    adPlan.setDramaId(request.getDramaId());
-                    adPlan.setBidAmount(request.getBidAmount());
-                    //adType=2-ROI
-                    if (request.getAdType().equals(2)) {
-                        adPlan.setDeepConversionWorthRate(request.getDeepConversionWorthRate());
-                    } else {
-                        adPlan.setDeepConversionWorthRate(BigDecimal.ZERO);
-                    }
-                    adPlan.setWxCorpid(request.getWxCorpid());
-                    plans.add(adPlan);
-                    List<AdPlanCreative> adPlanCreatives = new ArrayList<>();
-                    adPlan.setAdCreatives(adPlanCreatives);
-                    int j = 0;
-                    for (String creativeUrl : creativeUrlArray) {
-                        String fileName = (j < creativeNameArray.length && creativeNameArray[j] != null
-                                && !creativeNameArray[j].isEmpty())
-                                        ? creativeNameArray[j]
-                                        : creativeUrl.substring(creativeUrl.lastIndexOf("/") + 1);
-                        String creativeName = accountGroupName.trim() + "-" + dateTime + "-" + j + "-" + fileName;
-                        AdPlanCreative adPlanCreative = new AdPlanCreative();
-                        adPlanCreative.setCreativeFileUrl(creativeUrl);
-                        adPlanCreative.setCreativeId(0L);
-                        adPlanCreative.setCreativeName(creativeName);
-                        adPlanCreative.setCreativeText(request.getCreativeText());
-                        adPlanCreative.setImageId(0L);
-                        adPlanCreative.setBrandImageId(0L);
-                        adPlanCreative.setBrandName(request.getBrandName());
-                        adPlanCreative.setBrandImageUrl(request.getBrandImageUrl());
-                        adPlanCreative.setButtonText(request.getButtonText());
-                        adPlanCreative.setPageIds(request.getPageIds());
-                        adPlanCreatives.add(adPlanCreative);
-                        j++;
-                    }
+            for (int k = 0; k < dramaAmount; k++) {
+                Long assetId = dramas.get(dramaIndex).getMarketingAssetId();
+                String dramaName = dramas.get(dramaIndex).getMarketingAssetName();
+                dramaIndex++;
+                for (String target : targetArray) {
+                        for (String site : siteArray) {
+                        // 创建广告计划配置
+                        // 广告名称:一般是“账户分组名”+“日期时间”+"自增编号"
+                        String planName = accountGroupName.trim() + "-" + dateTime + "-" + dramaIndex;
+                        AdPlan adPlan = new AdPlan();
+                        adPlan.setAdPlanConfId(request.getId());
+                        adPlan.setAccountId(accountId);
+                        adPlan.setAdgroupId(0L);
+                        adPlan.setAdgroupName(planName);
+                        adPlan.setAdType(request.getAdType());
+                        adPlan.setTarget(target);
+                        adPlan.setSite(site);
+                        adPlan.setConversionId(request.getConversionId());
+                        adPlan.setDramaId(assetId);
+                        adPlan.setDramaName(dramaName);
+                        adPlan.setBidAmount(request.getBidAmount());
+                        //adType=2-ROI
+                        if (request.getAdType().equals(2)) {
+                            adPlan.setDeepConversionWorthRate(request.getDeepConversionWorthRate());
+                        } else {
+                            adPlan.setDeepConversionWorthRate(BigDecimal.ZERO);
+                        }
+                        adPlan.setWxCorpid(request.getWxCorpid());
+                        plans.add(adPlan);
+                        List<AdPlanCreative> adPlanCreatives = new ArrayList<>();
+                        adPlan.setAdCreatives(adPlanCreatives);
+                        int j = 0;
+                        for (String creativeUrl : creativeUrlArray) {
+                            j++;
+                            String fileName = (j < creativeNameArray.length && creativeNameArray[j] != null
+                                    && !creativeNameArray[j].isEmpty())
+                                            ? creativeNameArray[j]
+                                            : creativeUrl.substring(creativeUrl.lastIndexOf("/") + 1);
+                            String creativeName = accountGroupName.trim() + "-" + dateTime + "-" + j + "-" + fileName;
+                            AdPlanCreative adPlanCreative = new AdPlanCreative();
+                            adPlanCreative.setCreativeFileUrl(creativeUrl);
+                            adPlanCreative.setCreativeId(0L);
+                            adPlanCreative.setCreativeName(creativeName);
+                            adPlanCreative.setCreativeText(request.getCreativeText());
+                            adPlanCreative.setImageId(0L);
+                            adPlanCreative.setBrandImageId(0L);
+                            adPlanCreative.setBrandName(request.getBrandName());
+                            adPlanCreative.setBrandImageUrl(request.getBrandImageUrl());
+                            adPlanCreative.setButtonText(request.getButtonText());
+                            adPlanCreative.setPageIds(request.getPageIds());
+                            adPlanCreatives.add(adPlanCreative);
+                        }
                 }
             }
+            }
+            
+            
         }
         return plans;
     }
@@ -172,7 +197,7 @@ public class AdPlanConfController {
                 BeanUtils.copyProperties(request, adPlanConf);
                 adPlanConfService.updateAdPlanConf(adPlanConf);
             }
-            List<AdPlan> plans = buildPlans(request, accountGroup, relationships);
+            List<AdPlan> plans = buildPlans(sysUser.getJobNumber(), request, accountGroup, relationships);
             for (AdPlan plan : plans) {
                 plan.setAdPlanConfId(confId);
             }

+ 2 - 1
src/main/java/com/moka/gdtauto/controller/TencentAssetDramaController.java

@@ -98,7 +98,7 @@ public class TencentAssetDramaController {
             LambdaQueryWrapper<TencentAssetDrama> wrapper = new LambdaQueryWrapper<>();
             wrapper.eq(TencentAssetDrama::getIsDeleted, 0)
                    .eq(TencentAssetDrama::getJobNumber, user.getJobNumber())
-                   .orderByDesc(TencentAssetDrama::getUpdateTime)
+                   .orderByDesc(TencentAssetDrama::getMarketingAssetId)
                    .last("LIMIT " + offset + ", " + pageSize);
             if (StringUtils.isNotBlank(dramaName)) {
                 wrapper.like(TencentAssetDrama::getMarketingAssetName, dramaName);
@@ -125,6 +125,7 @@ public class TencentAssetDramaController {
             if (StringUtils.isNotBlank(dramaName)) {
                 wrapper.like(TencentAssetDrama::getMarketingAssetName, dramaName);
             }
+            wrapper.orderByDesc(TencentAssetDrama::getMarketingAssetId);
             List<TencentAssetDrama> assetList = assetDramaService.list(wrapper);
             return Result.success(assetList, "查询成功");
         } catch (Exception e) {

+ 2 - 0
src/main/java/com/moka/gdtauto/controller/vo/CreateAdPlanConfRequest.java

@@ -44,6 +44,8 @@ public class CreateAdPlanConfRequest {
 
     @Schema(description = "短剧ID", example = "1")
     private Long dramaId;
+    @Schema(description = "短剧每户几部剧", example = "1")
+    private Integer dramaAmount;
 
     @Schema(description = "图片IDs,多个用逗号分隔", example = "1,2,3")
     private String imageIds;

+ 2 - 0
src/main/java/com/moka/gdtauto/controller/vo/UpdateAdPlanConfRequest.java

@@ -44,6 +44,8 @@ public class UpdateAdPlanConfRequest {
 
     @Schema(description = "短剧ID", example = "1")
     private Long dramaId;
+    @Schema(description = "短剧每户几部剧", example = "1")
+    private Integer dramaAmount;
 
     @Schema(description = "图片IDs,多个用逗号分隔", example = "1,2,3")
     private String imageIds;

+ 2 - 0
src/main/java/com/moka/gdtauto/entity/AdPlan.java

@@ -80,6 +80,8 @@ public class AdPlan {
      * 短剧ID
      */
     private Long dramaId;
+    private String dramaName;
+    
 
     /**
      * 图片ID

+ 2 - 1
src/main/java/com/moka/gdtauto/service/TencentAssetDramaService.java

@@ -38,6 +38,7 @@ public class TencentAssetDramaService extends ServiceImpl<TencentAssetDramaMappe
 
     /**
      * 获取短剧资产列表
+     * https://developers.e.qq.com/v3.0/docs/api/marketing_target_assets/get
      * 
      * @param orgAccountId 组织账户ID
      * @param jobNumber 工号
@@ -93,7 +94,7 @@ public class TencentAssetDramaService extends ServiceImpl<TencentAssetDramaMappe
         log.info("开始同步短剧资产, jobNumber: {}, orgAccountId: {}, accountId: {}", jobNumber, orgAccountId, accountId);
 
         int totalCount = 0; // 总同步数量
-        int maxRecords = 1000; // 最多同步1000条
+        int maxRecords = 2000; // 最多同步1000条
         Long page = 1L;
         Long pageSize = 100L;
         

+ 43 - 0
src/main/java/com/moka/gdtauto/task/SyncDramaAssetTask.java

@@ -0,0 +1,43 @@
+package com.moka.gdtauto.task;
+
+import java.util.List;
+
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Component;
+
+import com.moka.gdtauto.common.Constant;
+import com.moka.gdtauto.entity.AssetDramaSyncConf;
+import com.moka.gdtauto.service.AssetDramaSyncConfService;
+import com.moka.gdtauto.service.TencentAssetDramaService;
+
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import net.javacrumbs.shedlock.spring.annotation.SchedulerLock;
+
+@Slf4j
+@Component
+@RequiredArgsConstructor
+public class SyncDramaAssetTask {
+    private final AssetDramaSyncConfService assetDramaSyncConfService;
+    private final TencentAssetDramaService tencentAssetDramaService;
+    
+
+    // 每小时
+    @Scheduled(cron = "0 0 * * * ?")
+    @SchedulerLock(name = "syncDramaAsset", lockAtMostFor = "4m", lockAtLeastFor = "1m")
+    public void syncDramaAsset() {
+        log.info("开始执行短剧资产同步任务");
+        List<AssetDramaSyncConf> confList = assetDramaSyncConfService.list();
+        confList.forEach(conf -> {
+            String jobNumber = conf.getJobNumber();
+            Long accountId = conf.getAccountId();
+            try {
+                log.info("开始同步短剧资产,jobNumber:{} accountId:{}", jobNumber, accountId);
+                int count = tencentAssetDramaService.syncMarketingAssets(jobNumber, Constant.MAIN_ORG_ACCOUNT_ID, accountId);
+                log.info("同步短剧资产完成,jobNumber:{} accountId:{} count:{}", jobNumber, accountId, count);
+            } catch (Exception e) {
+                log.error("同步短剧资产失败", e);
+            }
+        });
+    }
+}

+ 2 - 22
src/main/java/com/moka/gdtauto/task/TokenRefreshTask.java

@@ -29,8 +29,8 @@ public class TokenRefreshTask {
      * 刷新即将过期的访问令牌
      * 每10分钟执行一次,刷新30分钟内即将过期的token
      */
-    // @Scheduled(cron = "0 */10 * * * ?")
-    // @SchedulerLock(name = "refreshExpiringTokens", lockAtMostFor = "9m", lockAtLeastFor = "1m")
+    @Scheduled(cron = "0 */10 * * * ?")
+    @SchedulerLock(name = "refreshExpiringTokens", lockAtMostFor = "9m", lockAtLeastFor = "1m")
     public void refreshExpiringTokens() {
         log.info("开始执行Token刷新定时任务");
         
@@ -66,24 +66,4 @@ public class TokenRefreshTask {
             log.error("Token刷新任务执行异常", e);
         }
     }
-
-    /**
-     * 清理已过期的刷新令牌
-     * 每天凌晨3点执行一次
-     */
-    @Scheduled(cron = "0 0 3 * * ?")
-    @SchedulerLock(name = "cleanExpiredTokens", lockAtMostFor = "9m", lockAtLeastFor = "1m")
-    public void cleanExpiredTokens() {
-        log.info("开始执行过期Token清理任务");
-        
-        try {
-            // 这里可以添加清理逻辑,例如标记过期的授权为失效状态
-            // 或者发送告警通知管理员重新授权
-            
-            log.info("过期Token清理任务完成");
-            
-        } catch (Exception e) {
-            log.error("过期Token清理任务执行异常", e);
-        }
-    }
 }

+ 1 - 1
src/test/java/com/moka/gdtauto/service/TencentAssetDramaTest.java

@@ -15,7 +15,7 @@ import org.springframework.test.context.ActiveProfiles;
 
 /**
  * 腾讯广告短剧资产测试
- * 
+ * https://developers.e.qq.com/v3.0/docs/api/marketing_target_assets/get
  * @author moka
  * @since 2026-02-06
  */

Daži faili netika attēloti, jo izmaiņu fails ir pārāk liels