|
@@ -1,13 +1,13 @@
|
1
|
1
|
<template>
|
2
|
2
|
<el-dialog class="gdt-dialog" :close-on-click-modal="false" :destroy-on-close="true" key="copywriterDialog"
|
3
|
3
|
v-model="visible" title="选择文案" width="1000px" top="40px" :before-close="handleClose">
|
4
|
|
- <div v-loading="loading">
|
|
4
|
+ <div v-loading="loading" style="overflow-y: auto; max-height: 75vh;">
|
5
|
5
|
<div class="flex marT15">
|
6
|
6
|
<label class="form-block-item-title">多文案测试</label>
|
7
|
7
|
<div class="flex">
|
8
|
|
- <el-radio-group v-model="multiCopyTesting" size="default" @change="multiCopyTestingChange">
|
9
|
|
- <el-radio-button :label="0">不开启</el-radio-button>
|
10
|
|
- <el-radio-button :label="1">文案(1-30字)</el-radio-button>
|
|
8
|
+ <el-radio-group v-model="multiCopyTesting" size="small" @change="multiCopyTestingChange">
|
|
9
|
+ <el-radio-button :label="0" size="small">不开启</el-radio-button>
|
|
10
|
+ <el-radio-button :label="1" size="small">文案(1-30字)</el-radio-button>
|
11
|
11
|
</el-radio-group>
|
12
|
12
|
<el-tooltip placement="right" effect="light">
|
13
|
13
|
<template #content><span v-html="tooltip"></span></template>
|
|
@@ -43,18 +43,40 @@
|
43
|
43
|
</div>
|
44
|
44
|
<div style="color:#999;line-height: 26px;margin-top: 2px;" class="flex" v-if="multiCopyTesting == 1">已选择 {{
|
45
|
45
|
text_list?.length || 0 }} 条,将合并为 {{ text_list?.length || 0 }} 组
|
46
|
|
- <template v-if="count_info && JSON.stringify(count_info) != '{}'">
|
|
46
|
+ <template v-if="maxLength > 0 && maxLength != -1">
|
|
47
|
+ <span style="color:#555">(上限:{{ maxLength }}组)</span>
|
|
48
|
+ </template>
|
|
49
|
+ <!-- <template v-if="count_info && JSON.stringify(count_info) != '{}'">
|
47
|
50
|
<span style="color:#555">(上限:{{ count_info?.adNum }}组)</span>
|
48
|
51
|
<el-tooltip placement="right" content="上限:自动分配文案组时,文案组上限=已有广告数" effect="light">
|
49
|
52
|
<span><el-icon class="questionFilled" style="margin-top:6px;">
|
50
|
53
|
<QuestionFilled />
|
51
|
54
|
</el-icon></span>
|
52
|
55
|
</el-tooltip>
|
53
|
|
- </template>
|
|
56
|
+ </template> -->
|
54
|
57
|
</div>
|
55
|
58
|
</div>
|
|
59
|
+ <div class="marT25" v-if="multiCopyTesting == 1">
|
|
60
|
+ <RadioGroup
|
|
61
|
+ class="rule-wrap"
|
|
62
|
+ :radioList="writerShareRadioList.list"
|
|
63
|
+ :echoVal="writerShareRadioList.radioVal"
|
|
64
|
+ :title="writerShareRadioList.name"
|
|
65
|
+ :haveNotes="writerShareRadioList.haveNotes"
|
|
66
|
+ @returnEvent="onChangeWriterShare"></RadioGroup>
|
|
67
|
+
|
|
68
|
+ <template v-if="writerShareRadioList.radioVal == 2">
|
|
69
|
+ <RadioGroup
|
|
70
|
+ class="rule-wrap"
|
|
71
|
+ :radioList="writerRuleRadioList.list"
|
|
72
|
+ :echoVal="writerRuleRadioList.radioVal"
|
|
73
|
+ :title="writerRuleRadioList.name"
|
|
74
|
+ :haveNotes="writerRuleRadioList.haveNotes"
|
|
75
|
+ @returnEvent="onChangeWriterRule"></RadioGroup>
|
|
76
|
+ </template>
|
|
77
|
+ </div>
|
56
|
78
|
<div class="fix-table" v-if="multiCopyTesting == 1">
|
57
|
|
- <TextLibrary ref="TextLibraryRef" immobilizationHeight="40vh" tableSize="small" source="writerHelper" :select_num="count_info?.adNum" @select="selectEvent"></TextLibrary>
|
|
79
|
+ <TextLibrary ref="TextLibraryRef" immobilizationHeight="40vh" tableSize="small" source="writerHelper" :select_num="maxLength" @select="selectEvent"></TextLibrary>
|
58
|
80
|
</div>
|
59
|
81
|
|
60
|
82
|
</div>
|
|
@@ -68,15 +90,25 @@
|
68
|
90
|
<WriterHelper ref="WriterHelperRef" @close="writerHelperClose"></WriterHelper>
|
69
|
91
|
</template>
|
70
|
92
|
<script setup lang="ts">
|
71
|
|
-import { nextTick, onBeforeMount, ref } from 'vue';
|
|
93
|
+import { nextTick, onBeforeMount, ref, reactive } from 'vue';
|
72
|
94
|
import { emojiList } from "@/common/emoji";
|
73
|
95
|
import TextLibrary from '@/components/businessMoudle/textLibrary/index.vue'
|
74
|
96
|
import WriterHelper from './writerHelper.vue'
|
75
|
97
|
import { ElMessage } from 'element-plus';
|
76
|
98
|
import _ from 'lodash';
|
|
99
|
+import RadioGroup from '@/components/businessMoudle/batchGdt3/configArea/directPacket/common/radioGroup.vue'
|
|
100
|
+
|
|
101
|
+interface radioFace{
|
|
102
|
+ value:number | string,
|
|
103
|
+ name:string,
|
|
104
|
+ EgName:string,
|
|
105
|
+ radioVal:any,
|
|
106
|
+ haveNotes:boolean,
|
|
107
|
+ list:any
|
|
108
|
+}
|
77
|
109
|
const props = defineProps({
|
78
|
110
|
accIdsList: {
|
79
|
|
- type: Array<{ id: string, name: string }>,
|
|
111
|
+ type: Array,
|
80
|
112
|
default: () => []
|
81
|
113
|
},
|
82
|
114
|
count_info: {
|
|
@@ -90,7 +122,15 @@ const props = defineProps({
|
90
|
122
|
adTemplateItem: {
|
91
|
123
|
type: Object,
|
92
|
124
|
default: () => { }
|
93
|
|
- }
|
|
125
|
+ },
|
|
126
|
+ cMaterial: {
|
|
127
|
+ type:Object,
|
|
128
|
+ default: () => ({})
|
|
129
|
+ },
|
|
130
|
+ directObj: {
|
|
131
|
+ type:Object,
|
|
132
|
+ default: () => ({})
|
|
133
|
+ },
|
94
|
134
|
})
|
95
|
135
|
const emit = defineEmits<{
|
96
|
136
|
(event: "close", val?: any): void;
|
|
@@ -107,6 +147,34 @@ const WriterHelperRef = ref()
|
107
|
147
|
const TextLibraryRef = ref()
|
108
|
148
|
const allocation = ref(1) // 创意文案分配方式 1自动分配 2程序化测试
|
109
|
149
|
const tooltip = `您可以选择某一种文案,进行多条文案测试;<br/>测试文案为变量,将会出现在最下方,以列表形式多选;<br/>非测试文案为常量,会保持在上方;`
|
|
150
|
+
|
|
151
|
+const writerShareRadioList = reactive<radioFace>({
|
|
152
|
+ value:'1',
|
|
153
|
+ name:'文案分配方式',
|
|
154
|
+ EgName:'writerShare',
|
|
155
|
+ radioVal:'1',
|
|
156
|
+ haveNotes:true,
|
|
157
|
+ list:[
|
|
158
|
+ {name:'按广告分配',value:'1', notes: '按广告分配:一个广告一组文案,选择的文案数量不超过广告总数,当文案数量小于广告数量时,进行轮询分配;'},
|
|
159
|
+ {name:'按创意分配',value:'2', notes: '按创意分配:一个创意一组文案,选择的文案数量不超过创意总数,当文案数量小于创意数量时,进行轮询分配;'},
|
|
160
|
+ ]
|
|
161
|
+})
|
|
162
|
+const writerRuleRadioList = reactive<radioFace>({
|
|
163
|
+ value:'1',
|
|
164
|
+ name:'分配规则',
|
|
165
|
+ EgName:'writerRule',
|
|
166
|
+ radioVal:'1',
|
|
167
|
+ haveNotes:true,
|
|
168
|
+ list:[
|
|
169
|
+ {name:'自动分配',value:'1', notes: '自动匹配:将文案组自动分配至广告或创意中。'},
|
|
170
|
+ {name:'程序化分配',value:'2', notes: '程序化测试:文案组与创意组进行叉乘测试,生成更多的创意。'},
|
|
171
|
+ ]
|
|
172
|
+})
|
|
173
|
+const maxLength = ref(-1)
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
|
110
|
178
|
onBeforeMount(() => {
|
111
|
179
|
init()
|
112
|
180
|
})
|
|
@@ -201,7 +269,9 @@ const submitEvent = () => {
|
201
|
269
|
}
|
202
|
270
|
emit('close', {
|
203
|
271
|
'multiCopyTesting': multiCopyTesting.value,
|
204
|
|
- 'text_list': text_list.value
|
|
272
|
+ 'text_list': text_list.value,
|
|
273
|
+ 'writerShareRadioList': writerShareRadioList.radioVal,
|
|
274
|
+ 'writerRuleRadioList': writerRuleRadioList.radioVal,
|
205
|
275
|
})
|
206
|
276
|
visible.value = false
|
207
|
277
|
}
|
|
@@ -252,7 +322,84 @@ const initFun = (flag, obj) => {
|
252
|
322
|
}
|
253
|
323
|
}
|
254
|
324
|
})
|
|
325
|
+ handleSetMaxLength()
|
255
|
326
|
}
|
|
327
|
+
|
|
328
|
+const handleSetMaxLength = async () => { // 计算可选数量上限
|
|
329
|
+ const accountLength = props.accIdsList.length
|
|
330
|
+ const directObj = props.directObj
|
|
331
|
+ const { accountShareRule, creativeRule, list: cMaterialList } = props.cMaterial
|
|
332
|
+ const { radioVal: writerShareVal } = writerShareRadioList
|
|
333
|
+ const { radioVal: writerRuleVal } = writerRuleRadioList
|
|
334
|
+ console.log('accountLength => ', accountLength)
|
|
335
|
+ console.log('directObj => ', directObj)
|
|
336
|
+ console.log('accountShareRule => ', accountShareRule)
|
|
337
|
+ console.log('creativeRule => ', creativeRule)
|
|
338
|
+ console.log('cMaterialList => ', cMaterialList)
|
|
339
|
+ console.log('writerShareVal => ', writerShareVal)
|
|
340
|
+ console.log('writerRuleVal => ', writerRuleVal)
|
|
341
|
+
|
|
342
|
+ if (writerShareVal == 1) { // 按广告分配 数量上限为广告数(定向包数)
|
|
343
|
+ let maxL = 0
|
|
344
|
+ directObj.chooseList.forEach((direct) => {
|
|
345
|
+ maxL = maxL + direct.chooseList.length
|
|
346
|
+ })
|
|
347
|
+ maxLength.value = maxL
|
|
348
|
+ } else if (writerShareVal == 2 && writerRuleVal == 1) { // 按创意分配 && 自动分配 上限为创意数
|
|
349
|
+ if (accountShareRule == 1 && creativeRule == 1) { // 创意素材分配方式:按账号全部复用 && 按创意全部相同
|
|
350
|
+ const materialLength = cMaterialList.length // 素材数
|
|
351
|
+ let directLength = 0 // 广告数(定向包数)
|
|
352
|
+ directObj.chooseList.forEach((direct) => {
|
|
353
|
+ directLength = directLength + direct.chooseList.length
|
|
354
|
+ })
|
|
355
|
+ maxLength.value = materialLength * directLength
|
|
356
|
+ } else if (accountShareRule == 1 && creativeRule == 2) { // 创意素材分配方式:按账号全部复用 && 按创意平均分配
|
|
357
|
+ const materialLength = cMaterialList.length // 素材数
|
|
358
|
+ maxLength.value = materialLength * accountLength
|
|
359
|
+ } else if (accountShareRule == 2 && creativeRule == 2) { // 创意素材分配方式:按账号平均分配 && 按创意平均分配
|
|
360
|
+ const materialLength = cMaterialList.length // 素材数
|
|
361
|
+ maxLength.value = materialLength
|
|
362
|
+ } else if (accountShareRule == 2 && creativeRule == 1) { // 创意素材分配方式:按账号平均分配 && 按创意全部相同
|
|
363
|
+ const materialLength = cMaterialList.length // 素材数
|
|
364
|
+ if (materialLength < accountLength) { // 素材数 < 账号数
|
|
365
|
+ let maxL = 0
|
|
366
|
+ directObj.chooseList.forEach((direct) => {
|
|
367
|
+ maxL = maxL + direct.chooseList.length
|
|
368
|
+ })
|
|
369
|
+ maxLength.value = maxL
|
|
370
|
+ } else {
|
|
371
|
+ let total:any = materialLength // 要分配的素材数
|
|
372
|
+ let count:any = accountLength // 分给几个账号
|
|
373
|
+ let base:any = Math.floor(total / count);
|
|
374
|
+ let rest:any = total % count;
|
|
375
|
+ let arr:any = []; // 记录每个账号分多少个素材
|
|
376
|
+ for(let i=0; i<count; i++) {
|
|
377
|
+ let idx = base + (i<rest?1:0)
|
|
378
|
+ arr.push(idx)
|
|
379
|
+ }
|
|
380
|
+ let maxL = 0
|
|
381
|
+ directObj.chooseList.forEach((direct, idx) => {
|
|
382
|
+ maxL = maxL + direct.chooseList.length * arr[idx]
|
|
383
|
+ })
|
|
384
|
+ maxLength.value = maxL
|
|
385
|
+ }
|
|
386
|
+ }
|
|
387
|
+ } else if (writerShareVal == 2 && writerRuleVal == 2) { // 按创意分配 && 程序化分配 无上限
|
|
388
|
+ maxLength.value = -1
|
|
389
|
+ }
|
|
390
|
+
|
|
391
|
+ await nextTick()
|
|
392
|
+ TextLibraryRef.value.tableListRef.clearSelected()
|
|
393
|
+}
|
|
394
|
+const onChangeWriterShare = (val) => {
|
|
395
|
+ writerShareRadioList.radioVal = val
|
|
396
|
+ handleSetMaxLength()
|
|
397
|
+}
|
|
398
|
+const onChangeWriterRule = (val) => {
|
|
399
|
+ writerRuleRadioList.radioVal = val
|
|
400
|
+ handleSetMaxLength()
|
|
401
|
+}
|
|
402
|
+
|
256
|
403
|
// 暴露自己的属性供父组件使用
|
257
|
404
|
defineExpose({
|
258
|
405
|
initFun
|
|
@@ -296,4 +443,13 @@ defineExpose({
|
296
|
443
|
left: 430px;
|
297
|
444
|
width: 40px;
|
298
|
445
|
}
|
|
446
|
+
|
|
447
|
+.rule-wrap {
|
|
448
|
+ margin-top: 10px;
|
|
449
|
+ :deep(.spanTitle) {
|
|
450
|
+ color: #515a6e;
|
|
451
|
+ font-size: 14px;
|
|
452
|
+ width: 135px !important;
|
|
453
|
+ }
|
|
454
|
+}
|
299
|
455
|
</style>
|