Browse Source

优化目标

xiuli.gao 1 year ago
parent
commit
cfa847c9db

+ 1 - 1
src/api/api.ts

@@ -86,7 +86,7 @@ export enum Api{
86 86
     directPacket_add = '/api/ad/targetingsAdd',
87 87
     directPacket_list = '/api/ad/targetingGet',
88 88
     directPacket_edit = '/api/ad/targetingsUp',
89
-    directPacket_get_behavior_list = '/api/ad/getOptimizationGoal',
89
+    directPacket_get_behavior_list = 'api/ad/moreOptimizationGoal',
90 90
     directPacket_get_customer_base_list = '/api/ad/customAudiencesGet',
91 91
     directPacket_user_os_list = '/api/ad/userOsList',
92 92
     directPacket_location_list = '/api/ad/targetingTagsGet',

+ 5 - 0
src/assets/style/element/index.scss

@@ -59,4 +59,9 @@
59 59
   .el-drawer__body{
60 60
     padding-top: 0;
61 61
   }
62
+}
63
+.select-self {
64
+  .el-select-dropdown__list{
65
+    padding-bottom: 40px !important;
66
+  }
62 67
 }

+ 94 - 13
src/components/businessMoudle/batchGdt/configArea/basicInfo/components/select.vue

@@ -1,27 +1,59 @@
1 1
 <template>
2 2
   <div class="flex-baseline marB15">
3
-    <div class="form-block-item-title" v-if="title&&title!=''">{{ title }}</div>
3
+    <div class="form-block-item-title" v-if="title && title != ''">{{ title }}</div>
4 4
     <div class="flex-center" style="flex:1;flex-wrap: wrap;">
5
-      <el-select v-model="selectValue" filterable clearable :placeholder="placeholder" @change="onChange">
6
-        <el-option
7
-          v-for="item in list"
8
-          :key="item.value"
9
-          :label="item.label"
10
-          :value="item.value"
11
-        />
5
+      <el-select v-model="selectValue" popper-class="select-self" style="width:300px" filterable clearable
6
+        :placeholder="placeholder" @change="onChange">
7
+        <el-option v-for="item in selectList" :key="item.value" :label="item.label" :value="item.value" />
8
+        <template v-slot:empty v-if="isMoreTarget">
9
+          <div class="dropdown_footer" style="position: relative;">若找不到所需目标?请点这里:<span class="c-theme pointer"
10
+              @click="OnClickMore">更多目标</span></div>
11
+        </template>
12
+        <div class="dropdown_footer" v-if="isMoreTarget">若找不到所需目标?请点这里:<span class="c-theme pointer"
13
+            @click="OnClickMore">更多目标</span></div>
12 14
       </el-select>
13 15
       <slot name="content_item"></slot>
14 16
     </div>
15 17
   </div>
16
-  
18
+
19
+  <el-dialog class="gdt-dialog" append-to-body v-model="moreVisible" :title="title" width="480px" align-center>
20
+    <div class="deepexternalaction-tip">
21
+      <el-icon color="#ff9b48"><WarningFilled /></el-icon>请确保账户在广点通下可以使用该深度优化目标投放广告 </div>
22
+    <div class="flex" style="margin-bottom: 30px;">
23
+      <div class="form-block-item-title" v-if="title && title != ''">{{ title }}</div>
24
+      <div class="flex-center" style="flex:1;flex-wrap: wrap;">
25
+        <el-select v-model="moreValue" style="width:300px" filterable clearable
26
+          placeholder="请选择">
27
+          <el-option v-for="item in moreList" :key="item.value" :label="item.label" :value="item.value" />
28
+        </el-select>
29
+      </div>
30
+    </div>
31
+    <template #footer>
32
+      <span class="dialog-footer">
33
+        <el-button @click="moreVisible = false" size="default">取 消</el-button>
34
+        <el-button type="primary" @click="dialogSubmit" size="default">确 定</el-button>
35
+      </span>
36
+    </template>
37
+  </el-dialog>
17 38
 </template>
18 39
 <script setup lang="ts">
19 40
 import { onBeforeMount, ref } from 'vue'
41
+import { moreOptimizationGoal } from '../ts/basicApi'
42
+import { ElMessage } from 'element-plus'
43
+import _ from 'lodash'
20 44
 interface IList {
21 45
   value: string,
22 46
   label: string
23 47
 }
24 48
 const props = defineProps({
49
+  GoalType: {
50
+    type: Number,
51
+    default: 1,
52
+  },
53
+  isMoreTarget: {
54
+    type: Boolean,
55
+    default: false
56
+  },
25 57
   title: {
26 58
     type: String,
27 59
     default: ''
@@ -32,22 +64,71 @@ const props = defineProps({
32 64
   },
33 65
   list: {
34 66
     type: Array<IList>,
35
-    default: ()=>{[]}
67
+    default: () => { [] }
36 68
   },
37 69
   fillBack: {
38
-    type:String
70
+    type: String
39 71
   }
40 72
 })
41 73
 const emit = defineEmits<{
42 74
   (event: "change", val: any): void;
43 75
 }>();
76
+const moreVisible = ref(false)
44 77
 const selectValue = ref('')
45
-onBeforeMount(()=>{
78
+const moreValue = ref('')
79
+const moreList = ref<any[]>([])
80
+const selectList = ref(_.cloneDeep(props.list))
81
+onBeforeMount(() => {
46 82
   selectValue.value = props.fillBack || '';
47 83
   emit('change', selectValue.value)
48 84
 })
49 85
 const onChange = () => {
50 86
   emit('change', selectValue.value)
51 87
 }
88
+const OnClickMore = () => {
89
+  moreOptimizationGoal({ type: props.GoalType }).then((res: any) => {
90
+    moreVisible.value = true
91
+    moreList.value = res
92
+  }).catch(() => {
93
+    ElMessage.warning('暂无更多数据!')
94
+  })
95
+}
96
+const dialogSubmit = () => {
97
+  if(!moreValue.value || moreValue.value == ''){
98
+    ElMessage.warning('请选择目标!')
99
+    return;
100
+  }
101
+  if(selectList.value.filter((v)=>v.value == moreValue.value).length == 0){
102
+    moreList.value.forEach((item)=>{
103
+      if(item.value == moreValue.value) {
104
+        selectList.value.push(item)
105
+      }
106
+    })
107
+  }
108
+  selectValue.value = moreValue.value
109
+  moreVisible.value = false
110
+}
52 111
 </script>
53
-<style lang="scss" scoped>@import "@/assets/style/batchDialogGdt.scss";</style>
112
+<style lang="scss" scoped>
113
+@import "@/assets/style/batchDialogGdt.scss";
114
+
115
+.dropdown_footer {
116
+  position: absolute;
117
+  right: 0;
118
+  bottom: 0;
119
+  left: 0;
120
+  font-size: 14px;
121
+  background-color: #e6ecf5;
122
+  line-height: 40px;
123
+  text-align: center;
124
+}
125
+.deepexternalaction-tip{
126
+  color: #606266;
127
+  font-size: 14px;
128
+  line-height: 30px;
129
+  word-break: break-all;
130
+  display: flex;
131
+  align-items: center;
132
+  margin: 20px 0 15px;
133
+}
134
+</style>

+ 64 - 87
src/components/businessMoudle/batchGdt/configArea/basicInfo/index.vue

@@ -141,7 +141,7 @@
141 141
             @change="radioChange" :fillBack="props.dataFillBack['conversion_tracking_scene']"></MyRadio>
142 142
         </template>
143 143
         <!-- 优化目标 -->
144
-        <MySelect v-if="form.bid_mode == 'BID_MODE_OCPM' || form.bid_mode == 'BID_MODE_OCPC'" :list="optimizationGoal_1"
144
+        <MySelect v-if="form.bid_mode == 'BID_MODE_OCPM' || form.bid_mode == 'BID_MODE_OCPC'" :GoalType="1" :isMoreTarget="true" :list="optimizationGoal_1"
145 145
           title="优化目标" placeholder="请选择优化目标" :fillBack="props.dataFillBack['optimization_goal']"
146 146
           @change="(val) => { onChangeKey({ val, key: 'optimization_goal' }) }">
147 147
         </MySelect>
@@ -150,7 +150,8 @@
150 150
           :info="scheduleBidInfo.forward_link_assist_enabled"
151 151
           :fillBack="props.dataFillBack['forward_link_assist_enabled']" @change="radioChange">
152 152
           <template v-slot:content_item v-if="form.forward_link_assist_enabled == '1'">
153
-            <MySelect class="block marT15" :list="optimizationGoal_1" title="" placeholder="请选择助攻行为"
153
+            <div style="height: 15px;width:1px;"></div>
154
+            <MySelect class="block marT15" :list="moreOptimizationGoalList" title="" placeholder="请选择助攻行为"
154 155
               :fillBack="props.dataFillBack['forward_link_assist']"
155 156
               @change="(val) => { onChangeKey({ val, key: 'forward_link_assist' }) }"></MySelect>
156 157
           </template>
@@ -210,7 +211,7 @@
210 211
             :info="scheduleBidInfo.deep_optimize_type" @change="radioChange">
211 212
             <template v-slot:default v-if="form.deep_optimize_type != 0">
212 213
               <MyRadio :info="scheduleBidInfo.deep_conversion_type" :fillBack="props.dataFillBack['deep_conversion_type']" @change="radioChange"></MyRadio>
213
-              <MySelect class="marT15" :list="optimizationGoal_2" title="深度优化目标" placeholder="请选择深度优化目标" :fillBack="deep_conversion_behavior_spec.target" 
214
+              <MySelect class="marT15" :GoalType="form.deep_conversion_type == 'DEEP_CONVERSION_BEHAVIOR' ? 2 : 3" :isMoreTarget="true" :list="optimizationGoal_2" title="深度优化目标" placeholder="请选择深度优化目标" :fillBack="deep_conversion_behavior_spec.target" 
214 215
                 @change="(val) => { deep_conversion_behavior_spec.target = val; }">
215 216
               </MySelect>
216 217
               <!-- 优化转化行为 -->
@@ -303,11 +304,11 @@
303 304
 </template>
304 305
 <script setup lang="ts">
305 306
 import { ref, reactive, watch, onBeforeMount, computed, nextTick } from 'vue'
306
-import { basicInfoJson, scheduleBid, conversion_tracking_way, optimizationGoal_1, optimizationGoal_2 } from './ts/information'
307
+import { basicInfoJson, scheduleBid, conversion_tracking_way } from './ts/information'
307 308
 import { specificPositionAll, expand_targeting, unbreakable_targeting } from './ts/other'
308 309
 import { scene, wechatScene, positionMapping, search_expand_targeting_switch } from './ts/scene'
309 310
 import { FillBackData } from './ts/fillBack'
310
-import { adPresetsSet } from './ts/basicApi'
311
+import { adPresetsSet,getOptimizationGoal, moreOptimizationGoal } from './ts/basicApi'
311 312
 import { getDay, deepCopy } from "@/common/common";
312 313
 import MyRadio from './components/radio.vue'
313 314
 import AdPosition from './components/adPosition.vue'
@@ -321,6 +322,7 @@ import wildcard from './components/wildcard.vue'
321 322
 import WeekTime from './components/weekTime.vue'
322 323
 import { ElMessage } from "element-plus";
323 324
 import _ from 'lodash'
325
+
324 326
 const props = defineProps({
325 327
   visible: {
326 328
     type: Boolean,
@@ -329,6 +331,10 @@ const props = defineProps({
329 331
   dataFillBack: {
330 332
     type: Object,
331 333
     default: () => { }
334
+  },
335
+  promoted_object_type: {
336
+    type: String,
337
+    default: ''
332 338
   }
333 339
 })
334 340
 const emit = defineEmits<{
@@ -343,6 +349,9 @@ const site_ids_arr_1: any = ref([])
343 349
 const site_ids_arr_2: any = ref([])
344 350
 const scheduleBidInfo = reactive(scheduleBid)
345 351
 const specificPositionInfo2 = specificPositionAll()
352
+const optimizationGoal_1 = ref<any[]>([])
353
+const optimizationGoal_2 = ref<any[]>([])
354
+const moreOptimizationGoalList = ref<any[]>([])
346 355
 const defaultAdPositionList = ['SITE_SET_KANDIAN', 'SITE_SET_QQ_MUSIC_GAME', 'SITE_SET_TENCENT_NEWS', 'SITE_SET_TENCENT_VIDEO', 'SITE_SET_MOBILE_UNION']
347 356
 let adPositionList: any = ref([]);// 广告版位默认列表
348 357
 const deep_conversion_behavior_spec: any = reactive({ // 深度目标优化 - 优化转化行为
@@ -408,7 +417,9 @@ const computed_deep_conversion_behavior_spec_fillBack2 = () => {
408 417
 const form: any = reactive(props.dataFillBack || {})
409 418
 const basicInfoJsonInfo: any = reactive(basicInfoJson)
410 419
 onBeforeMount(() => {
411
-  
420
+  moreOptimizationGoal({type: 1}).then((res:any)=>{//助攻行为
421
+    moreOptimizationGoalList.value = res
422
+  })
412 423
 })
413 424
 /**提交保存 */
414 425
 const submitEvent = () => {
@@ -461,7 +472,12 @@ const submitEvent = () => {
461 472
   if (flag) return
462 473
 
463 474
   FillBackData({
464
-    data: form, type: 'me', 'updateScene': basicInfoJsonInfo['场景'], cb: (data: { params: any, copywriting: [] }) => {
475
+    data: form, 
476
+    type: 'me', 
477
+    updateScene: basicInfoJsonInfo['场景'], 
478
+    optimizationGoal_1: optimizationGoal_1.value,
479
+    optimizationGoal_2: optimizationGoal_2.value,
480
+    cb: (data: { params: any, copywriting: [] }) => {
465 481
       if (adSet.value) {
466 482
         loading.value = true;
467 483
         // let setParams = _.cloneDeep(data.params)
@@ -487,6 +503,20 @@ const handleClose = () => {
487 503
 /**特定版位回调 */
488 504
 const onChangeAdPosition = (val: string) => {
489 505
   form['site_ids'] = val;
506
+  getOptimizationGoal({
507
+    site_set: val.split(','),
508
+    promoted_object_type: props.promoted_object_type
509
+  }).then((res:any)=>{
510
+    res.forEach((item)=>{
511
+      item.label = item.name;
512
+      item.value = item.goal;
513
+    })
514
+    optimizationGoal_1.value = res.filter((v)=>{return v.name && v.name != '' && v.goal && v.goal != ''});
515
+    console.log('optimizationGoal_1',optimizationGoal_1.value)
516
+  }).catch((res)=>{
517
+    optimizationGoal_1.value = [];
518
+    optimizationGoal_2.value = [];
519
+  })
490 520
   watchSiteIds()// 版位变化
491 521
 }
492 522
 const change_site_table = () => {
@@ -567,6 +597,9 @@ const radioChange = (obj: object) => {
567 597
     if(keys_arr.includes('bid_way')){//优化目标出价方式变化
568 598
       watch_deep_conversion()
569 599
     }
600
+    if(keys_arr.includes('deep_conversion_type')){//深度转化类型
601
+      changeOptimizationGoal()
602
+    }
570 603
   }
571 604
 }
572 605
 
@@ -633,10 +666,34 @@ const onChangeKey = ({ val, key }) => {
633 666
   }else if(key == 'bid_amount'){
634 667
     form[key] = val;
635 668
     computed_deep_conversion_behavior_spec_fillBack2()
669
+  }else if(key == 'optimization_goal'){// 优化目标
670
+    form[key] = val;
671
+    changeOptimizationGoal()
636 672
   }else{
637 673
     form[key] = val;
638 674
   }
639 675
 }
676
+/**优化目标 及 深度转化类型 变化 ==> 导致 深度优化目标 发生变化 */
677
+const changeOptimizationGoal = () => {
678
+  optimizationGoal_1.value.forEach((item)=>{
679
+    if(item.goal == form.optimization_goal){
680
+      let deep_info:any[] = []
681
+      if(form.deep_conversion_type == 'DEEP_CONVERSION_BEHAVIOR'){//优化转化行为
682
+        deep_info = _.cloneDeep(item.deep_behaviors) || []
683
+      }else if (form.deep_conversion_type == 'DEEP_CONVERSION_WORTH') {//优化ROI
684
+        deep_info = _.cloneDeep(item.deep_worths) || []
685
+      }
686
+      deep_info = deep_info.filter((v)=>{
687
+        return v.name && v.name != '' && v.goal && v.goal != ''
688
+      })
689
+      deep_info.forEach((v)=>{
690
+        v.label = v.name;
691
+        v.value = v.goal;
692
+      })
693
+      optimizationGoal_2.value = deep_info
694
+    }
695
+  })
696
+}
640 697
 const onChangeWechat = (flag) => {
641 698
   if (flag) {
642 699
     adPositionList.value = ['SITE_SET_MOMENTS', 'SITE_SET_WECHAT', 'SITE_SET_WECHAT_PLUGIN'].concat(defaultAdPositionList)
@@ -701,29 +758,6 @@ const watch_deep_conversion = (type?) => {
701 758
     });
702 759
   }
703 760
 }
704
-/**自动扩量监听 */
705
-// watch([
706
-//   () => form.expand_enabled
707
-// ], (newValue, oldValue) => {
708
-//   let obj = basicInfoJsonInfo['定向扩展']['smart_targeting_switch']
709
-//   if (newValue[0] == '1') {
710
-//     obj.data.list[1].disabled = true;
711
-//   } else {
712
-//     obj.data.list[1].disabled = false;
713
-//   }
714
-// }, { immediate: true})
715
-
716
-/**智能定向监听 */
717
-// watch([
718
-//   () => form.smart_targeting_switch
719
-// ], (newValue, oldValue) => {
720
-//   let obj = basicInfoJsonInfo['定向扩展']['expand_enabled']
721
-//   if (newValue[0] == '1') {
722
-//     obj.data.list[1].disabled = true;
723
-//   } else {
724
-//     obj.data.list[1].disabled = false;
725
-//   }
726
-// }, { immediate: true})
727 761
 /**监听出价 - 更改 -》 分版位出价 */
728 762
 watch([
729 763
   () => form.bid_way,
@@ -822,65 +856,8 @@ watch(
822 856
     checkedWechat.value = props.dataFillBack.bid_site_wechat_enabled == '1' ? true : false; // 支持微信朋友圈&微信公众号与小程序版位
823 857
     watch_deep_conversion()
824 858
   }, { immediate: true})
825
-/**监听数据回显 */
826
-// watch(
827
-//   () => props.dataFillBack,
828
-//   (newValue, oldValue) => {
829
-//     if (!newValue.id) return;
830
-//      form.daily_budget_radio = newValue?.daily_budget ? '2' : '1';
831
-//      for(let i in newValue){
832
-//       form[i] = newValue[i]
833
-//      }
834
-//     form.bid_scene_radio = newValue?.bid_scene == 'BID_SCENE_NORMAL_AVERAGE' || newValue?.bid_scene == 'BID_SCENE_NORMAL_TARGET' ? '' : newValue?.bid_scene;
835
-//     if(form.bid_way == '2'){
836
-//       let arr = form.bid_range?.split('-') || [];
837
-//       form.bid_range_1 = {
838
-//         con: form.bid_range,
839
-//         min: arr.length > 0 ? arr[0] : '',
840
-//         max: arr.length > 1 ? arr[1] : '',
841
-//       }
842
-//     }
843
-//     watchSiteIds()
844
-//     if (form.bid_site == '1') { // 分版位出价
845
-//       if (newValue.bid_site_details){
846
-//         let bid_site_details = JSON.parse(newValue.bid_site_details)
847
-//         site_ids_arr_1.value.forEach((item) => {
848
-//           item.coefficient = bid_site_details[item.value] || 1;
849
-//           item.offer = getOffer(bid_site_details[item.value], 'site')
850
-//         });
851
-//       }
852
-//     }
853
-//     if (newValue.deep_conversion_behavior_spec || newValue.deep_conversion_worth_spec) {
854
-//       let deep_spec = JSON.parse(newValue.deep_conversion_behavior_spec)
855
-//       if(newValue.deep_conversion_type == 'DEEP_CONVERSION_WORTH') { // 优化ROI
856
-//         deep_spec = JSON.parse(newValue.deep_conversion_worth_spec)
857
-//       }
858
-//       deep_conversion_behavior_spec.target = deep_spec.target;
859
-//       deep_conversion_behavior_spec.rate = deep_spec.rate || '';
860
-//       deep_conversion_behavior_spec.price = newValue.deep_conversion_type == 'DEEP_CONVERSION_WORTH' ? deep_spec.roi : deep_spec.price;
861
-//       deep_conversion_behavior_spec.min = deep_spec.min;
862
-//       deep_conversion_behavior_spec.max = deep_spec.max;
863
-//       deep_conversion_behavior_spec_fillBack.min = deep_spec.min;
864
-//       deep_conversion_behavior_spec_fillBack.max = deep_spec.max;
865
-//       deep_conversion_behavior_spec_fillBack2.value = newValue.deep_conversion_type == 'DEEP_CONVERSION_WORTH' ? deep_spec.roi : deep_spec.price;
866
-//     }
867
-//     if (form.deep_bid_site == '1') { // 分版位深度出价
868
-//       if (newValue.deep_bid_site_details){
869
-//         let deep_bid_site_details = JSON.parse(newValue.deep_bid_site_details)
870
-//         site_ids_arr_2.value.forEach((item) => {
871
-//           item.coefficient = deep_bid_site_details[item.value] || 1;
872
-//           item.offer = getOffer(deep_bid_site_details[item.value], 'deep_bit_site')
873
-//         });
874
-//       }
875
-//     }
876
-//     first_day_begin_time.flag = newValue.first_day_begin_time && newValue.first_day_begin_time != '' ? true : false;
877
-//     first_day_begin_time.value = newValue.first_day_begin_time.slice(0,5)
878
-//     checkedWechat.value = newValue.bid_site_wechat_enabled == '1' ? true : false; // 支持微信朋友圈&微信公众号与小程序版位
879
-//     watch_deep_conversion()
880
-//   }, { immediate: true})
881 859
 </script>
882 860
 <style lang="scss" scoped>@import "@/assets/style/batchDialogGdt.scss";
883
-
884 861
 .flex-1 {
885 862
   flex: 1;
886 863
 }</style>

+ 38 - 12
src/components/businessMoudle/batchGdt/configArea/basicInfo/ts/basicApi.ts

@@ -27,21 +27,47 @@ export async function getSceneSpecTags(params: ISceneSpecTags) {
27 27
     return []
28 28
   }
29 29
 }
30
-/**1优化目标/助攻行为   2深度优化目标 */
30
+/** 优化目标下拉列表 */
31 31
 interface IOptimizationGoal {
32
-  type: '1' | '2'
32
+  site_set: string[],
33
+  promoted_object_type: string
33 34
 }
34
-export async function getOptimizationGoal(params: IOptimizationGoal) {
35
-  const res: any = await http.get('/api/ad/getOptimizationGoal', params)
36
-  if (res.errNo == 0) {
37
-    let arr:Array<{label:string, value: string}> = [];
38
-    for(let i in res.rst){
39
-      arr.push({label: res.rst[i], value: i})
35
+export function getOptimizationGoal(params: IOptimizationGoal) {
36
+  return new Promise( async (resolve, reject)=>{
37
+    const res: any = await http.get('/api/ad/getOptimizationGoal', params)
38
+    if (res.errNo == 0 && Array.isArray(res.rst)) {
39
+      // let arr:Array<{label:string, value: string}> = [];
40
+      // res.rst.forEach((item)=>{
41
+      //   arr.push({label: item.name, value: item.goal})
42
+      // })
43
+      resolve(res.rst)
44
+    } else {
45
+      reject()
40 46
     }
41
-    return arr
42
-  } else {
43
-    return []
44
-  }
47
+  })
48
+}
49
+
50
+/** 优化目标-更多  
51
+ * 1优化目标/助攻行为   
52
+ * 2深度优化转化目标 
53
+ * 3深度优化roi目标
54
+*/
55
+interface IMoreOptimizationGoal {
56
+  type: number,
57
+}
58
+export function moreOptimizationGoal(params: IMoreOptimizationGoal) {
59
+  return new Promise( async (resolve, reject)=>{
60
+    const res: any = await http.get('api/ad/moreOptimizationGoal', params)
61
+    if (res.errNo == 0 && res.rst) {
62
+      let arr:Array<{label:string, value: string}> = [];
63
+      for(let key in res.rst){
64
+        arr.push({label: res.rst[key], value: key})
65
+      }
66
+      resolve(arr)
67
+    } else {
68
+      reject()
69
+    }
70
+  })
45 71
 }
46 72
 
47 73
 /**通配符 */

+ 5 - 3
src/components/businessMoudle/batchGdt/configArea/basicInfo/ts/fillBack.ts

@@ -1,5 +1,5 @@
1 1
 import { ElMessage } from "element-plus";
2
-import { basicInfoJson, scheduleBid, optimizationGoal_1, optimizationGoal_2 } from './information'
2
+import { basicInfoJson, scheduleBid } from './information'
3 3
 import { specificPositionAll } from './other'
4 4
 import { scene } from './scene'
5 5
 import { number, time } from "echarts";
@@ -106,9 +106,11 @@ interface IFillBackData {
106 106
   data: any,
107 107
   type: 'me' | 'api',
108 108
   cb?: Function,
109
-  updateScene?: any
109
+  updateScene?: any,
110
+  optimizationGoal_1: any[],
111
+  optimizationGoal_2: any[]
110 112
 }
111
-export const FillBackData = ({ data, type, updateScene = {}, cb }: IFillBackData) => {
113
+export const FillBackData = ({ data, type, updateScene = {}, cb, optimizationGoal_1, optimizationGoal_2 }: IFillBackData) => {
112 114
   let copywriting: string[] = [];
113 115
   let site_ids: string[] = [];//广告版位
114 116
   let params: any = {}

+ 0 - 4
src/components/businessMoudle/batchGdt/configArea/basicInfo/ts/information.ts

@@ -1,7 +1,3 @@
1
-import { getOptimizationGoal } from './basicApi'
2
-export const optimizationGoal_1 = await getOptimizationGoal({ type: '1' })
3
-export const optimizationGoal_2 = await getOptimizationGoal({ type: '2' })
4
-
5 1
 export const conversion_tracking_way = [
6 2
   { label: '点击归因', value: '1' },
7 3
   { label: '曝光归因', value: '2'},

+ 1 - 1
src/components/businessMoudle/batchGdt/configArea/index.vue

@@ -124,7 +124,7 @@
124 124
                     @submitIsOver="switch_complate_flag_creaBasicInfo"
125 125
   ></OriginalityBasic>
126 126
   <!-- 广告基本信息 -->
127
-  <BasicInfo :visible="basicInfoData.visible" :dataFillBack="basicInfoData.fillBack" @close="basicInfoClose"></BasicInfo>
127
+  <BasicInfo :visible="basicInfoData.visible" :dataFillBack="basicInfoData.fillBack" :promoted_object_type="pageInfo.targetValue" @close="basicInfoClose"></BasicInfo>
128 128
   <!-- 扩量种子人群 -->
129 129
   <ExpandPopulation :visible="basicInfoData.outerConfig.expandPopulation.visible" :accIdsList="pageInfo.accIdsList" :fillback="basicInfoData.outerConfig['expandPopulation'].value" @close="(obj)=>{basicOuterClose({val: obj?.val || null, type: obj?.type || null, key:'expandPopulation'})}" title="扩量种子人群"></ExpandPopulation>
130 130
   <!-- 一方数据助攻 - 智能定向 -->

+ 417 - 0
src/components/businessMoudle/gdtList/account.vue

@@ -0,0 +1,417 @@
1
+<template>
2
+  <div>
3
+    <div class="screenBox_mini">
4
+      <Input ref="InputRef_text" title="关键词" placeholderTxt="关键词" @changeEvent="()=>init()" @clearEvent="()=>init()"/>
5
+      <Select ref="acRef"
6
+              title="账号"
7
+              selectWidth="160px"
8
+              @changeEvent="()=>init()" @clearEvent="()=>init()"
9
+              :isMultiple="true"
10
+              :optObj="{k:'account_id',la:'account_id',val:'account_id'}"
11
+              :options="pageInfo.acList"/>
12
+      <Select ref="statusRef"
13
+              title="状态"
14
+              selectWidth="160px"
15
+              @changeEvent="()=>init()" @clearEvent="()=>init()"
16
+              :options="pageInfo.statusList"/>
17
+      <TimeScreen title="时间" selectWidth="260px" :haveQuick="false" :clearFlag="true" :valueIsKong="true"
18
+                  ref="timeRef"
19
+                  @init="()=>init()"></TimeScreen>
20
+      <span class="pointer c-theme lMar10" @click="clearEvent">清空</span>
21
+      <el-button class="lMarauto" type="primary" @click="goNewPlanEvent">新建计划</el-button>
22
+    </div>
23
+    <div>
24
+      <div class="bMar10 flex">
25
+        <Dropdown title="批量操作" :list="tableInfo.moreList" @close="dropdownEvent" class="rMar10"
26
+                  :disabledFlag="tableInfo.multipleSelection&&tableInfo.multipleSelection.length == 0"></Dropdown>
27
+        <div>已选 : <span>{{tableInfo.multipleSelection&&tableInfo.multipleSelection.length}}</span></div>
28
+<!--        <el-button class="lMarauto" type="primary" @click="customIndEvent">自定义指标</el-button>-->
29
+
30
+        <div  class="lMarauto">
31
+          <Indicators type="media_base" @refresh="IndicatorsRefreshList"></Indicators>
32
+        </div>
33
+      </div>
34
+我是账户列表
35
+      <el-table v-loading="loading" ref="tableRef" :data="tableInfo.tableList"
36
+                :header-cell-style="tableHeaderStyle"
37
+                :key="tableInfo.updateKey" style="width: 100%"
38
+                border empty-text="暂无数据"
39
+                row-key="campaign_id"
40
+                max-height="calc(100vh - 294px)">
41
+        <el-table-column fixed width="80" >
42
+          <template #header>
43
+            <div class="flex">
44
+              <el-checkbox v-model="tableInfo.chooseAll" @change="allChooseCheckboxEvent"></el-checkbox>
45
+              <el-dropdown class="lMar10" @command="handleCommandChoosePage">
46
+                <el-icon color="#3173FF"><i-ep-ArrowDownBold /></el-icon>
47
+                <template #dropdown>
48
+                  <el-dropdown-menu>
49
+                    <el-dropdown-item command="1">当前页</el-dropdown-item>
50
+                    <el-dropdown-item command="2">全部</el-dropdown-item>
51
+                  </el-dropdown-menu>
52
+                </template>
53
+              </el-dropdown>
54
+            </div>
55
+          </template>
56
+          <template #default="scope">
57
+            <div class="checkBoxSelf flex"
58
+                 @click="singleChooseCheckboxEvent(tableInfo.multipleSelection.findIndex(n=>n.campaign_id == scope.row.campaign_id),scope.row)"
59
+                 :class="tableInfo.multipleSelection.findIndex(n=>n.campaign_id == scope.row.campaign_id)>=0 ? 'active' : ''">
60
+              <el-icon color="#fff" v-if="tableInfo.multipleSelection.findIndex(n=>n.campaign_id == scope.row.campaign_id)>=0"><i-ep-Check /></el-icon>
61
+            </div>
62
+          </template>
63
+        </el-table-column>
64
+        <template v-for="item in tableInfo.descol">
65
+          <el-table-column :fixed="item.isfixed" :min-width="item.minWidth ? item.minWidth : '80px'">
66
+            <template #header>
67
+              <div class="flex"
68
+                   :style="{ justifyContent: item.alignSelf ? item.alignSelf : 'center' }"
69
+                   :class="[tableInfo.sortKey == item.column ? 'active_css' : '',item.isSort ? 'pointer' : '']"
70
+                   @click="item.isSort&&sortEvent(item.column)">
71
+                {{ item.name }}
72
+                <el-tooltip v-if="item.notes" effect="dark" :content="item.notes"><i-ep-QuestionFilled class="lMar5 c-999 f14 pointer" /></el-tooltip>
73
+                <div v-if="item.isSort">
74
+                  <div class="sortItem"><el-icon :color="tableInfo.sortKey == item.column ? '#3173FF' : ''"><i-ep-CaretBottom /></el-icon></div>
75
+                </div>
76
+              </div>
77
+            </template>
78
+            <template #default="scope">
79
+              <div class="flex" :style="{ justifyContent: item.alignSelf ? item.alignSelf : 'center' }">
80
+
81
+              <div v-if="item.column == 'campaign_name'">
82
+                <span class="c-theme flex campaignName">
83
+                  <span class="pointer" @click="goAdvertEvent(scope.row.campaign_id)">{{scope.row[item.column]}}</span>
84
+                  <el-icon color="#3173FF" class="pointer lMarauto f16 icon" @click="edit_campaign_name_event(scope.row)"><i-ep-Edit /></el-icon>
85
+                </span>
86
+              </div>
87
+              <div v-else-if="item.column == 'configured_status'">
88
+                <span class="c-green" v-if="scope.row[item.column] == 'AD_STATUS_NORMAL'">正常</span>
89
+                <span class="c-red" v-else-if="scope.row[item.column] == 'AD_STATUS_SUSPEND'">暂停</span>
90
+                <span v-else>-</span>
91
+              </div>
92
+              <div v-else-if="item.column == 'speed_mode'">
93
+                <span v-if="scope.row[item.column] == 'SPEED_MODE_STANDARD'">标准投</span>
94
+                <span v-else-if="scope.row[item.column] == 'SPEED_MODE_FAST'">加速投放</span>
95
+                <span v-else>-</span>
96
+              </div>
97
+              <div v-else-if="item.column == 'operate'">
98
+                <div class="flex">
99
+                  <span class="c-theme pointer" @click="editPlanEvent(scope.row)">修改</span>
100
+                  <span class="lMar10"
101
+                        :class="scope.row.configured_status == 'AD_STATUS_NORMAL' ? 'pointer-drop c-green-opa' : 'pointer c-green'"
102
+                        @click="scope.row.configured_status == 'AD_STATUS_SUSPEND'&&batchPlanEvent(scope.row,1)">启用</span>
103
+                </div>
104
+                <div>
105
+                    <span :class="scope.row.configured_status == 'AD_STATUS_SUSPEND' ? 'pointer-drop c-red-opa' : 'pointer c-red'"
106
+                          @click="scope.row.configured_status == 'AD_STATUS_NORMAL'&&batchPlanEvent(scope.row,2)">暂停</span>
107
+                  <Popconfirm key="dele" @confirm="batchPlanEvent(scope.row,3)" :slotFlag="true">
108
+                    <template #con>
109
+                      <span class="pointer lMar10">删除</span>
110
+                    </template>
111
+                  </Popconfirm>
112
+
113
+                </div>
114
+
115
+
116
+              </div>
117
+              <div class="flex c-theme pointer" v-else-if="item.column == 'daily_budget'" @click="editPlanEvent(scope.row)">
118
+                {{scope.row[item.column] ? NumberHandle(scope.row[item.column]) : '不限'}}
119
+              </div>
120
+
121
+
122
+              <div class="cellDiv" :class="tableInfo.sortKey == item.column ? 'active_css' : ''" v-else>
123
+                <el-tooltip :disabled="!(scope.row[item.column] && scope.row[item.column].length >30)" effect="dark" :content="scope.row[item.column]+''">
124
+                  <div class="clampTwo line21" style="flex: 1">
125
+                    {{ scope.row[item.column] || scope.row[item.column]==0 ?
126
+                      (item.cancleForMat ? (scope.row[item.column] ? scope.row[item.column] : '-') : NumberHandle(scope.row[item.column])) : '-'}}
127
+                    <span v-if="item.hasPercent&&(scope.row[item.column] || scope.row[item.column] ==0)">%</span>
128
+                  </div>
129
+                </el-tooltip>
130
+              </div>
131
+              </div>
132
+            </template>
133
+          </el-table-column>
134
+        </template>
135
+      </el-table>
136
+
137
+      <div class="paginationBox flex" style="justify-content: center" v-if="Number(tableInfo.total) > 0">
138
+        <el-pagination
139
+            v-model:currentPage="tableInfo.currentPage"
140
+            v-model:page-size="tableInfo.pageSize"
141
+            background
142
+            :total="tableInfo.total"
143
+            @current-change="handleCurrentChange" />
144
+      </div>
145
+    </div>
146
+
147
+    <EditIpt ref="planEditIptRef" title="推广计划" @confirm="planEditConfirm"></EditIpt>
148
+    <TargetEdit ref="TargetEditRef" title="计划设置" @confirm="init"></TargetEdit>
149
+  </div>
150
+</template>
151
+<script setup lang="ts">
152
+import {getCurrentInstance, nextTick, onMounted, reactive, ref} from "vue";
153
+import Select from '@/components/capsulationMoudle/_select.vue'
154
+import TimeScreen from '@/components/capsulationMoudle/timeScreen.vue'
155
+import Input from '@/components/capsulationMoudle/_input.vue'
156
+import EditIpt from '@/components/businessMoudle/gdtList/dialog/editIpt.vue'
157
+import TargetEdit from '@/components/businessMoudle/gdtList/dialog/target.vue'
158
+import Dropdown from '@/components/capsulationMoudle/_dropdown.vue'
159
+import Popconfirm from '@/components/capsulationMoudle/_popconfirm.vue'
160
+import noData from '@/components/capsulationMoudle/noData.vue'
161
+import {listTs} from "@/components/businessMoudle/gdtList/ts/list";
162
+import {Api} from "@/api/api";
163
+import {ElMessage} from "element-plus";
164
+import {batchGdt_edit, batchGdt_list, reactiveTableAndAny} from "@/api/ApiModel";
165
+import Indicators from './indicators/index.vue'
166
+
167
+const { proxy } = getCurrentInstance() as any;
168
+// 全局方法定义
169
+const NumberHandle = proxy.$NumberHandle
170
+
171
+const emit = defineEmits<{
172
+  (event: "goNewPlan"): void;
173
+  (event: "goAdvert",campaign_id:any): void;
174
+}>();
175
+const goNewPlanEvent = () => {
176
+  emit('goNewPlan')
177
+}
178
+const goAdvertEvent = (campaign_id:any) => {
179
+  emit('goAdvert',campaign_id)
180
+}
181
+
182
+const loading = ref<boolean>(false)
183
+const tableInfo = reactive<reactiveTableAndAny>({
184
+  tableList:[],
185
+  tableList_all:[],
186
+  descol:[
187
+    { name:'计划名称',column:'campaign_name',slotFlag: true,isfixed:true,alignSelf:'left'},
188
+    { name:'操作',column:'operate',slotFlag: true,isfixed:true},
189
+    { name:'账号ID',column:'account_id',cancleForMat:true},
190
+    { name:'计划ID',column:'campaign_id',cancleForMat:true},
191
+    { name:'计划类型',column:'campaign_type'},
192
+    { name:'推广目标类型',column:'promoted_object_type'},
193
+    { name:'日预算(元)',column:'daily_budget',slotFlag: true},
194
+    // { name:'总预算',column:'total_budget'},
195
+    { name:'投放日期',column:'created_time'},
196
+    { name:'客户状态',column:'configured_status',slotFlag: true},
197
+    { name:'投放速度',column:'speed_mode',slotFlag: true},
198
+  ],
199
+  multipleSelection:[],
200
+  updateKey:1,
201
+  chooseAll:false,
202
+  sortKey:'',
203
+  moreList:[
204
+    {value:'1',label:'启用'},
205
+    {value:'2',label:'暂停'},
206
+    {value:'3',label:'删除'},
207
+  ],
208
+  currentPage:1,
209
+  pageSize:20,
210
+  total:0,
211
+  totalPages:0,//共多少页
212
+})
213
+
214
+
215
+
216
+//批量操作
217
+const batchEvent = () => {
218
+
219
+}
220
+
221
+// 启用 暂停 删除
222
+const batchPlanApi = async (arr?:any,val?:any) => {
223
+  const paramsModel = reactive<batchGdt_edit>({
224
+    campaign_infos:JSON.stringify(arr),
225
+    flag:val?val:0
226
+  })
227
+  let res:any = await proxy.$http.post(Api.batchGdt_plan_batch_edit,paramsModel)
228
+  ElMessage.info(res.errMsg)
229
+  if(res&&res.errNo=='0'){
230
+    init()
231
+    tableInfo.multipleSelection = []
232
+  }else{
233
+    loading.value = false
234
+  }
235
+}
236
+const batchPlanEvent = async (row?:any,val?:any) => {
237
+  loading.value = true
238
+  let arr:any = []
239
+  arr.push({
240
+    account_id:row.account_id,
241
+    campaign_id:row.campaign_id
242
+  })
243
+  batchPlanApi(arr,val)
244
+
245
+}
246
+const dropdownEvent = (val: string | number | object) => {
247
+  loading.value = true
248
+  let arr:any = []
249
+  tableInfo.multipleSelection.forEach(item=>{
250
+    arr.push({
251
+      account_id:item.account_id,
252
+      campaign_id:item.campaign_id
253
+    })
254
+  })
255
+  batchPlanApi(arr,val)
256
+}
257
+
258
+//修改计划
259
+const editPlanEvent = (row:any) => {
260
+  nextTick(()=>{
261
+    TargetEditRef.value!.switchShow(true,row)
262
+  })
263
+}
264
+//修改计划名称
265
+const edit_campaign_name_event = (row:any) => {
266
+  nextTick(()=>{
267
+    planEditIptRef.value!.switchShow(true,row.campaign_name)
268
+  })
269
+}
270
+//推广计划 - 确定
271
+const planEditConfirm = () => {
272
+
273
+}
274
+
275
+
276
+//排序
277
+const sortEvent = (row:any) => {
278
+
279
+}
280
+
281
+//列表
282
+const init = async (page?:any,totalPages?:any) => {
283
+  loading.value = true
284
+  const paramsModel = reactive<batchGdt_list>({
285
+    account_ids:acRef.value!.value,
286
+    keyword:InputRef_text.value!.value,
287
+    status:statusRef.value!.value,
288
+    start:timeRef.value!.dateVal&&timeRef.value!.dateVal[0],
289
+    end:timeRef.value!.dateVal&&timeRef.value!.dateVal[1],
290
+    page:page?page:1,
291
+    pageSize:totalPages ? totalPages : tableInfo.pageSize
292
+  })
293
+  let res:any = await proxy.$http.get(Api.batchGdt_plan_list,paramsModel)
294
+  loading.value = false
295
+  if(res&&res.errNo=='0'){
296
+    if(totalPages){
297
+      tableInfo.tableList_all = res.rst.data
298
+    }else{
299
+      tableInfo.tableList = res.rst.data
300
+      tableInfo.total = res.rst.pageInfo.total
301
+      tableInfo.totalPages = res.rst.pageInfo.total
302
+    }
303
+  }else{
304
+    ElMessage.error(res.errMsg)
305
+  }
306
+}
307
+
308
+//分页
309
+const handleCurrentChange = (val) => {
310
+  tableInfo.currentPage = val
311
+  init(val)
312
+}
313
+
314
+
315
+//清空值
316
+const clearChooseVal = ()=>{
317
+  tableInfo.chooseAll = false
318
+  tableInfo.multipleSelection = []
319
+}
320
+//添加值
321
+const multipleSelection_add = (item?:any) => {
322
+  let idx:number = tableInfo.multipleSelection.findIndex(n=>n.campaign_id == item.campaign_id)
323
+  if(idx<0){
324
+    tableInfo.multipleSelection.push(item)
325
+  }
326
+}
327
+//删除值
328
+const multipleSelection_splice = (item?:any) => {
329
+  let idx:number = tableInfo.multipleSelection.findIndex(n=>n.campaign_id == item.campaign_id)
330
+  if(idx>=0){
331
+    tableInfo.multipleSelection.splice(idx,1)
332
+  }
333
+}
334
+const handleCommandChoosePage = async (command: string | number | object)=>{
335
+  let arr:any = tableInfo.tableList
336
+  clearChooseVal()
337
+  tableInfo.chooseAll = true
338
+  if(command == 2){ // 全部
339
+    await init(1,tableInfo.totalPages)
340
+    arr = tableInfo.tableList_all
341
+  }
342
+  arr.forEach(item=>{
343
+    multipleSelection_add(item)
344
+  })
345
+}
346
+//全选
347
+const allChooseCheckboxEvent = (val:string | number | boolean)=>{
348
+  tableInfo.tableList.forEach(item=>{
349
+    if(val){
350
+      multipleSelection_add(item)
351
+    }else{
352
+      tableInfo.multipleSelection = []
353
+    }
354
+  })
355
+}
356
+//单选
357
+const singleChooseCheckboxEvent = (idx:number,row:any)=>{
358
+  if(idx==-1){
359
+    tableInfo.multipleSelection.push(row)
360
+  }else{
361
+    tableInfo.multipleSelection.splice(idx,1)
362
+    tableInfo.chooseAll = false
363
+  }
364
+}
365
+
366
+const IndicatorsRefreshList = () => {
367
+  //这里刷新列表
368
+}
369
+
370
+const {
371
+  init_acList,
372
+  pageInfo,
373
+  timeRef,
374
+  acRef,
375
+  statusRef,
376
+  InputRef_text,
377
+  clearEvent,
378
+  tableHeaderStyle,
379
+  planEditIptRef,
380
+  TargetEditRef,
381
+  customIndEvent
382
+} = listTs()
383
+
384
+onMounted(()=>{
385
+  nextTick(async ()=>{
386
+    await init_acList()
387
+    await init()
388
+  })
389
+})
390
+</script>
391
+<style lang="scss" scoped>
392
+.campaignName{
393
+  .icon{
394
+    color: #3173FF;
395
+    opacity: 0;
396
+  }
397
+  &:hover{
398
+    .icon{
399
+      opacity: 1;
400
+    }
401
+  }
402
+}
403
+.checkBoxSelf{
404
+  width: 13px;
405
+  height: 13px;
406
+  border: 1px solid #d9d9d9;
407
+  border-radius: 2px;
408
+  &:hover{
409
+    cursor: pointer;
410
+    border: 1px solid #3173FF;
411
+  }
412
+  &.active{
413
+    border: 1px solid #3173FF;
414
+    background-color: #3173FF;
415
+  }
416
+}
417
+</style>

+ 3 - 0
src/components/businessMoudle/gdtList/index.vue

@@ -9,6 +9,7 @@
9 9
   <!-- 表格组件 -->
10 10
   <keep-alive>
11 11
     <div>
12
+      <account v-show="typeAc == 'account'"  @goAdvert="goAdvert"  @goNewPlan="goNewPlan"></account>
12 13
       <plan v-show="typeAc == 'plan'"  @goAdvert="goAdvert"  @goNewPlan="goNewPlan"></plan>
13 14
       <advert v-show="typeAc == 'advert'" ref="advertRef"
14 15
               @goNewPlan="goNewPlan"
@@ -21,6 +22,7 @@ import {getCurrentInstance, markRaw, nextTick, onBeforeMount, onMounted, reactiv
21 22
 import { useRouter } from "vue-router";
22 23
 import advert from "@/components/businessMoudle/gdtList/advert.vue";
23 24
 import plan from "@/components/businessMoudle/gdtList/plan.vue";
25
+import account from "@/components/businessMoudle/gdtList/account.vue";
24 26
 import {publicSwitchType} from "@/components/businessMoudle/switchType";
25 27
 import {reactiveTableAndAny} from "@/api/ApiModel";
26 28
 
@@ -32,6 +34,7 @@ const acIdx = shallowRef(plan)
32 34
 
33 35
 // 类型切换公共ts
34 36
 const typeListParams = reactive([
37
+  {name:'媒体账户',key:'account',compName:markRaw(account)},
35 38
   {name:'推广计划',key:'plan',compName:markRaw(plan)},
36 39
   {name:'广告',key:'advert',compName:markRaw(advert)},
37 40
 ])