猎羽广告

index.vue 27KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783
  1. <template>
  2. <div class="flex titleBox">
  3. <span>程序化批量/广点通</span>
  4. </div>
  5. <div class="areaBox" style="margin-top:10px;">
  6. <div class="areaTitle">
  7. 配置区
  8. <el-button class="lMar20" type="primary" @click="openStrategyGroups">选择策略组</el-button>
  9. <div class="strategy-title" v-if="pageInfo.groupsConfig && pageInfo.groupsConfig?.id">
  10. 已选:{{ pageInfo.groupsConfig.name }}
  11. <el-icon class="lMar8 pointer" @click="closeSeletedGroup"><Close /></el-icon>
  12. </div>
  13. <span class="smallTitle lMarauto">预览广告数 : <span class="c-theme">{{NumberHandle(pageInfo.num_total.adNum)||0}}</span></span>
  14. </div>
  15. <div class="areaCon">
  16. <div class="screenArea">
  17. <Select ref="accRef"
  18. :clearFlag="true"
  19. :isMultiple="true"
  20. title="媒体账户"
  21. selectWidth="160px"
  22. @clearEvent="accClearEvent"
  23. @changeEvent="accEvent"
  24. @visibleEvent="accVisibleEvent"
  25. :optObj="{k:'account_id',la:'account_id',val:'account_id'}"
  26. :options="pageInfo.accountList"/>
  27. <Select ref="targetRef"
  28. :clearFlag="false"
  29. title="推广目标"
  30. selectWidth="160px"
  31. :optObj="{k:'name',la:'desc',val:'name'}"
  32. @changeEvent="targetChange"
  33. :options="pageInfo.targetList"/>
  34. <el-button type="primary" class="lMarauto" @click="openRuleConfig">规则配置</el-button>
  35. </div>
  36. <div class="configArea">
  37. <div v-for="item in pageInfo.adTitleList" :key="item.id"
  38. :style=" {width:item.name == '广告' ? 'calc((100vw - 40px - 32px) / 6 * 2)' : 'calc((100vw - 40px - 32px) / 6 * 4)'}">
  39. <div class="bigTitle" :class="item.name == '广告创意' ? 'no_left_boder' : ''">{{item.name}}</div>
  40. <div class="flex">
  41. <div class="blockBox" v-for="sub in item.subList" :key="sub.id" :class="sub.name == '广告基本信息' ? '' : 'no_left_boder'">
  42. <div class="smallTitle">
  43. {{sub.name}}
  44. <span class="chooseCss" v-if="sub.haveChooseNum">已选: {{NumberHandle(sub.chooseNum) || 0}}</span>
  45. </div>
  46. <div class="showInfoArea">
  47. <template v-if="sub.name == '创意文案'">
  48. <Copywriter ref="CopywriterRef" :num_total="pageInfo.num_total" :basicInfoData="basicInfoData.fillBack" :adTemplateItem="originalityBasicInfoData?.apiResult?.adTemplateItem || {}" @writerCallBack="writerCallBack"></Copywriter>
  49. </template>
  50. <template v-if="sub.name == '落地页'">
  51. <LandPage ref="LandPageRef" :accIdsList="pageInfo.accIdsList" :page_type="originalityBasicInfoData?.receiveForm?.landingPageExample?.page_type" @landPage="landPageEvent"></LandPage>
  52. </template>
  53. <div class="noData" v-if="!sub.haveContent">暂无数据 </div>
  54. <!-- 定向包展示 -->
  55. <template v-if="sub.name == '定向包'">
  56. <DirectPacketExhibition :showFlag="sub.haveContent" ref="DirectPacketExhibitionRef" @updateHaveContent="updateHaveContent"></DirectPacketExhibition>
  57. </template>
  58. <div v-if="sub.name == '广告基本信息'">
  59. <template v-for="(item) in basicInfoData.copywriting">
  60. <div class="bMar8 lH16 c-515a6e" v-if="item?.indexOf('投放日期:') != -1">{{ item }}{{Number(pageInfo.RuleConfigObj?.start_day) > 0 ? `- 规则配置已设置自动延后 ${pageInfo.RuleConfigObj?.start_day} 天,实际开始日期为:${AddDays(basicInfoData?.fillBack?.begin_date, Number(pageInfo?.RuleConfigObj?.start_day))}` : ''}}</div>
  61. <div class="bMar8 lH16 c-515a6e" v-else>{{ item }}</div>
  62. </template>
  63. </div>
  64. <div v-if="sub.name == '创意基本信息'">
  65. <template v-for="(main_item, main_index) in originalityBasicInfoData.receiveForm">
  66. <template v-if="String(main_index) == 'profiles' || String(main_index) == 'brand'">
  67. <div class="bMar8 lH16 c-515a6e">{{ `${String(main_index) == 'brand' ? '品牌名称' : '昵称'}:` }}{{ main_item.api_value.name }}</div>
  68. <div class="bMar8 lH16 c-515a6e">{{ `${String(main_index) == 'brand' ? '品牌标识图' : '头像'}:` }}
  69. <img :src="main_item.api_value.oss_url" class="oss_url_img" alt="">
  70. </div>
  71. </template>
  72. <template v-if="main_item.copywriting && main_item.copywriting.length > 0">
  73. <template v-for="item in main_item.copywriting">
  74. <div class="bMar8 lH16 c-515a6e">{{ item }}</div>
  75. </template>
  76. </template>
  77. </template>
  78. </div>
  79. <div v-if="sub.name == '创意素材'">
  80. <template v-for="cItem in cMaterial.list" :key="cItem.id">
  81. <div class="flex bMar8">
  82. <template v-for="cSub in cItem.list" :key="cItem.id+cSub.subId">
  83. <div class="flex" style="width: 100%;justify-content: center"
  84. v-if="cMaterial.haveCoverOrVideo == 2 || cMaterial.haveCoverOrVideo == 1">
  85. <video :src="cSub.videoUrl" height="50"></video>
  86. </div>
  87. <div style="width: 100%;justify-content: center" class="lMar10 flex" v-if="cMaterial.haveCoverOrVideo == 3 || cMaterial.haveCoverOrVideo == 1">
  88. <img :src="cSub.picUrl" height="50"/>
  89. </div>
  90. </template>
  91. </div>
  92. </template>
  93. </div>
  94. </div>
  95. <div class="btn" @click="openDialogEvent(sub)">{{sub.haveContent ? '编辑' : '添加'}}</div>
  96. </div>
  97. </div>
  98. </div>
  99. </div>
  100. <div class="btnArea">
  101. <span class="" v-if="pageInfo.accIdsList && pageInfo.accIdsList.length>0">
  102. <template v-for="(item,index) in basicInfoData.outerConfig">
  103. <el-button plain class="rMar10 outerButton" v-if="item.enabled" @click="basicOuterClick(index)">
  104. <el-icon :class="['outerIcon', !item.isComplete || 'outerIconActive']"><CircleCheck v-if="!item.isComplete" /><SuccessFilled v-else/></el-icon>
  105. {{item.name}}
  106. </el-button>
  107. </template>
  108. </span>
  109. <span class="lMarauto">
  110. <el-button type="primary" @click="openPreAreaEvent" v-loading.fullscreen.lock="openPreAreaLoading">批量预览广告</el-button>
  111. <el-button type="primary" @click="openSaveStrategyGroups" v-loading.fullscreen.lock="openPreAreaLoading">保存策略组</el-button>
  112. </span>
  113. </div>
  114. </div>
  115. </div>
  116. <!-- 预览区-->
  117. <PreviewArea ref="PreviewAreaRef" @continueCreate="continueCreate"></PreviewArea>
  118. <!--规则配置-->
  119. <RuleConfig ref="RuleConfigRef" @ExposeEvent="val=>pageInfo.RuleConfigObj = val"></RuleConfig>
  120. <!-- 创意素材-->
  121. <!-- :max_creative_num="pageInfo.RuleConfigObj?.adcreative_max || 0" -->
  122. <CreativeMaterial ref="CreativeMaterialRef"
  123. :haveCoverOrVideo="cMaterial.haveCoverOrVideo"
  124. :haveShowVideoObj = "cMaterial.haveShowVideoObj"
  125. :video_tips="cMaterial.video_tips"
  126. :image_tips="cMaterial.image_tips"
  127. @closeLoading="close_reuse_loading"
  128. :maxNum_imageList="cMaterial.array_property?.max_number || 1"
  129. @assignEvent="assignEvent_CreativeMaterial"></CreativeMaterial>
  130. <!-- 创意基本信息 -->
  131. <OriginalityBasic ref="originalityBasicRef" :visible="originalityBasicInfoData.visible" :key="originalityBasicInfoData.positionKey"
  132. :adBasicInfo="basicInfoData.fillBack" :accIdsList="pageInfo.accIdsList"
  133. :promoted_object_type="pageInfo.targetValue" @close="originalityBasicClose"
  134. @submitIsOver="switch_complate_flag_creaBasicInfo"
  135. ></OriginalityBasic>
  136. <!-- 广告基本信息 -->
  137. <BasicInfo :visible="basicInfoData.visible"
  138. :dataFillBack="basicInfoData.fillBack"
  139. :promoted_object_type="pageInfo.targetValue"
  140. :ruleConfigObj="pageInfo.RuleConfigObj"
  141. @close="basicInfoClose"></BasicInfo>
  142. <!-- 扩量种子人群 -->
  143. <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>
  144. <!-- 一方数据助攻 - 智能定向 -->
  145. <ExpandPopulation :visible="basicInfoData.outerConfig.targetingPartyData.visible" :accIdsList="pageInfo.accIdsList" :fillback="basicInfoData.outerConfig['targetingPartyData'].value" @close="(obj)=>{basicOuterClose({val: obj?.val || null, type: obj?.type || null, key:'targetingPartyData'})}" title="一方数据助攻"></ExpandPopulation>
  146. <!-- 精准匹配归因 -->
  147. <AttributionOuter :visible="basicInfoData.outerConfig.attributionOuter.visible" :accIdsList="pageInfo.accIdsList" :fillback="basicInfoData.outerConfig['attributionOuter'].value" @close="(obj)=>{basicOuterClose({val: obj?.val || null, type: obj?.type || null , key:'attributionOuter'})}"></AttributionOuter>
  148. <!-- 配置视频号 -->
  149. <WeChatVideoAccount :visible="basicInfoData.outerConfig.weChatVideoAccount.visible" :accIdsList="pageInfo.accIdsList" :fillback="basicInfoData.outerConfig['weChatVideoAccount']" :acc_plan_ad_count="pageInfo.acc_plan_ad_count" @close="(obj: IOuterConfigRule)=>{basicOuterClose({ ...obj, key:'weChatVideoAccount'})}"></WeChatVideoAccount>
  150. <!-- 优量汇流量包 -->
  151. <UnionPosition :visible="basicInfoData.outerConfig.unionPosition.visible" :accIdsList="pageInfo.accIdsList" :infoSelect="basicInfoData.outerConfig.unionPosition.infoSelect" :fillback="basicInfoData.outerConfig['unionPosition'].value" @close="(obj)=>{basicOuterClose({val: obj?.val || null, type: obj?.type || null , key:'unionPosition'})}"></UnionPosition>
  152. <!-- 复用配置 -->
  153. <ResuseConfig ref="ResuseConfigRef" @aNewConfig="aNewConfigEvent" @reuse="reuseEvent"></ResuseConfig>
  154. <!-- 策略组列表 -->
  155. <StrategyGroupsList ref="StrategyGroupsListRef" @close="strategyGroupsUse"></StrategyGroupsList>
  156. <!-- 保存策略组弹框 -->
  157. <StrategyGroupsDialog ref="StrategyGroupsDialogRef"></StrategyGroupsDialog>
  158. </template>
  159. <script setup lang="ts">
  160. import {getCurrentInstance, nextTick, onMounted, reactive, ref, provide, computed,toRef,watch} from "vue";
  161. import {adqParam, reactiveTableAndAny} from "@/api/ApiModel";
  162. import Select from '@/components/capsulationMoudle/_select.vue'
  163. import DirectPacketExhibition from '@/components/businessMoudle/batchGdt/configArea/directPacket/echoIndex.vue'
  164. import RuleConfig from '@/components/businessMoudle/batchGdt/configArea/ruleConfig/index.vue'
  165. import CreativeMaterial from '@/components/businessMoudle/batchGdt/configArea/creativeMaterial/index.vue'
  166. import ResuseConfig from '@/components/businessMoudle/batchGdt/configArea/resuseConfig/index.vue'
  167. import PreviewArea from '@/components/businessMoudle/batchGdt/previewArea/index.vue'
  168. import {Api} from "@/api/api";
  169. import {ElMessage} from "element-plus";
  170. import BasicInfo from "./basicInfo/index.vue";
  171. import ExpandPopulation from './basicInfo/expandPopulation.vue'
  172. import AttributionOuter from './basicInfo/attributionOuter.vue'
  173. import WeChatVideoAccount from './basicInfo/weChatVideoAccount.vue'
  174. import UnionPosition from './basicInfo/unionPosition.vue'
  175. import OriginalityBasic from './originalityBasic/index.vue'
  176. import Copywriter from './copywriter/index.vue'
  177. import LandPage from "./landPage/index.vue";
  178. import { getPromotedObjectType } from './basicInfo/ts/basicApi'
  179. import _ from "lodash";
  180. import { previewCompute } from './ts/preview'
  181. import { submitPreview } from './ts/submitPreview'
  182. import { materialDeclare, handleMultiple } from './ts/material'
  183. import { IOuterConfigRule, basicInfoDeclare, handleAdBasic} from './ts/adBasic'
  184. import { resuseConfigEvent} from './ts/resuseConfigTs'
  185. import handleJudge from './ts/judgeEvent'
  186. import { mockEvent } from './ts/mock'
  187. import { AddDays } from "@/common/common";
  188. import StrategyGroupsList from './strategyGroups/list.vue'
  189. import StrategyGroupsDialog from './strategyGroups/saveDialog.vue'
  190. import { strategyGroupsEvent } from './ts/strategyGroups'
  191. const { proxy } = getCurrentInstance() as any;
  192. // 全局方法定义
  193. const NumberHandle = proxy.$NumberHandle
  194. // S 参数声明
  195. const {
  196. basicInfoData
  197. } = basicInfoDeclare()
  198. const {
  199. CreativeMaterialRef,
  200. cMaterial
  201. } = materialDeclare()
  202. // E 参数声明
  203. const targetRef = ref<{value:any}>()
  204. const originalityBasicRef = ref()
  205. const pageInfo = reactive<reactiveTableAndAny>({
  206. last_ad_show_list:[],//最终需要的数组
  207. num_total: {
  208. accNum:0,//账号数
  209. planNum:0,//计划数
  210. adNum:0,//预览广告数
  211. },
  212. targetValue: '',
  213. targetList:[],
  214. adTitleList:[
  215. {id:1,name:'广告',subList:[
  216. { id:2,name:'广告基本信息',haveContent:false },
  217. { id:3,name:'定向包',chooseNum:0,haveChooseNum:true,haveContent:false },
  218. ]},
  219. {id:4,name:'广告创意',subList:[
  220. { id:5,name:'创意基本信息',haveContent:false },
  221. { id:6,name:'创意素材',chooseNum:0,haveChooseNum:true,haveContent:false },
  222. { id:7,name:'创意文案',chooseNum:0,haveChooseNum:true,haveContent:false },
  223. { id:8,name:'落地页',chooseNum:0,haveChooseNum:true,haveContent:false },
  224. ]},
  225. ],
  226. accountList:[],
  227. accIdsList:[],//选中的格式化后的账户列表
  228. accIdsList_copy_last:[],//选中的格式化后的账户列表
  229. directObj:{},//定向包展示的数据
  230. RuleConfigObj:{},//规则配置的值
  231. copywriterInfoData: {//创意文案
  232. multiCopyTesting: 0,
  233. data: [],
  234. allocation_type: '',//分配形式 1自动分配 2程序化相乘分配
  235. },
  236. copyLandPageInfoData: {//落地页
  237. data: [],
  238. allocation_type: '',//分配形式 1自动分配 2程序化相乘分配
  239. loadPageRule: 0, //0 全部相同 //1 按账户分配 //2 分配到计划 // 3分配到广告
  240. multiCopyTesting: 0,//分账户选择 0不开启 1开启
  241. },
  242. acc_plan_ad_count: {}, //各账户对应的计划数、广告数;用于微信视频号的配置
  243. groupsConfig: {},//已选择的策略组
  244. })
  245. //创意基本信息
  246. const originalityBasicInfoData = reactive<any>({
  247. positionKey: 0,//广告基本信息版位变化+1
  248. receiveForm: {},//自己操作的form
  249. apiResult: {},//接口返回的数据
  250. params: [],//接口需要的数据
  251. })
  252. //创意文案
  253. const CopywriterRef = ref()
  254. const LandPageRef = ref()
  255. //获取账号列表
  256. const get_account_list = async () => {
  257. const paramsModel = reactive<adqParam>({
  258. page:1,
  259. page_size:10000,
  260. })
  261. let res:any = await proxy.$http.get(Api.adq_list,paramsModel)
  262. if(res&&res.errNo=='0'){
  263. pageInfo.accountList = res.rst.data
  264. }else{
  265. ElMessage.error(res.errMsg)
  266. }
  267. }
  268. //创意基本信息是否上传完成
  269. const resuse_complate_flag_creaBasicInfo=ref<boolean>(false)
  270. const switch_complate_flag_creaBasicInfo = (val:any)=>{
  271. resuse_complate_flag_creaBasicInfo.value = val
  272. }
  273. watch(()=>resuse_complate_flag_creaBasicInfo.value,async (val)=>{
  274. if(val){
  275. // 创意素材 - 修改或者新增
  276. await CreativeMaterialRef.value?.deleAcEvent(pageInfo.accIdsList,false)
  277. CreativeMaterialRef.value?.creatice_reuseEvent(_.cloneDeep(cMaterial))
  278. }
  279. })
  280. //创意素材清空
  281. const CreativeMaterial_clear = () => {
  282. nextTick(()=> {
  283. CreativeMaterialRef.value?.clearAllEvent()
  284. updateHaveContent(6, 0, false, true)
  285. })
  286. }
  287. //推广目标
  288. const targetChange = () => {
  289. pageInfo.targetValue = targetRef.value?.value
  290. }
  291. //打开规则配置
  292. const RuleConfigRef = ref<{switchShow:(val:boolean)=>void}>()
  293. const openRuleConfig = () => {
  294. nextTick(()=>{
  295. RuleConfigRef.value?.switchShow(true)
  296. })
  297. }
  298. // 得到规则配置的值
  299. const get_ruleConfig_info = async () => {
  300. let res:any = await proxy.$http.get(Api.ruleConfig_get)
  301. if(res&&res.errNo=='0'){
  302. let resNew:any = res.rst
  303. pageInfo.RuleConfigObj = resNew
  304. }else{
  305. ElMessage.error(res.errMsg)
  306. }
  307. }
  308. //监听创意素材点击了确定
  309. watch(()=>cMaterial.key,()=>{
  310. cMaterial.list = _.cloneDeep(cMaterial.list_copy)
  311. let num = cMaterial.list&&cMaterial.list.length
  312. updateHaveContent(6,num)
  313. })
  314. // 定向包
  315. const DirectPacketExhibitionRef = ref<{get_echoAcId:()=>void,
  316. showDirectPacket:()=>void,
  317. clearDirectContent:()=>void,
  318. AcChangeEvent:(arr:any)=>void,
  319. feedbackEvent:(obj)=>void
  320. // addAcEvent:(arr:any)=>void,deleAcEvent:(arr:any)=>void
  321. }>()
  322. // 打开添加 / 编辑
  323. const openDialogEvent = async (sub:any) => {
  324. if( !judgeEvent( sub.id ) ) return; // 判断是否完成前一模块
  325. if(sub.name == '定向包'){
  326. nextTick(()=>{
  327. if(DirectPacketExhibitionRef.value) { DirectPacketExhibitionRef.value[0]?.showDirectPacket() }
  328. if(sub.haveContent){
  329. console.log('get_echoAcIdget_echoAcIdget_echoAcIdget_echoAcIdget_echoAcIdget_echoAcId')
  330. if(DirectPacketExhibitionRef.value) { DirectPacketExhibitionRef.value[0]?.get_echoAcId() }
  331. }
  332. })
  333. }
  334. if(sub.name == '广告基本信息'){
  335. basicInfoData.visible = true;
  336. }
  337. if(sub.name == '创意基本信息'){
  338. if (basicInfoData.fillBack?.automatic_site && basicInfoData.fillBack?.automatic_site != ''){
  339. originalityBasicRef.value?.switchShow(true, {
  340. 'fillback': originalityBasicInfoData.receiveForm,
  341. 'apiResult': originalityBasicInfoData.apiResult,
  342. })
  343. } else {
  344. ElMessage.error('请完善广告基本信息!')
  345. }
  346. }
  347. if(sub.name == '创意素材'){
  348. await get_cover_info()
  349. console.log('cMaterial', cMaterial)
  350. console.log('打开之前CreativeMaterialRef',cMaterial.list);
  351. CreativeMaterialRef.value?.switchShow(true,sub.haveContent,cMaterial.list,cMaterial.testNew_text)
  352. console.log(cMaterial.array_property);
  353. }
  354. if(sub.name == '创意文案' && CopywriterRef.value){
  355. CopywriterRef.value[0]?.initFun(true, pageInfo?.copywriterInfoData)
  356. }
  357. if(sub.name == '落地页' && LandPageRef.value){
  358. LandPageRef.value[0]?.initFun(true, pageInfo.num_total, pageInfo.last_ad_show_list, pageInfo?.copyLandPageInfoData)
  359. }
  360. }
  361. //更新数值,判断是否有内容
  362. const updateHaveContent = (id:number,chooseNum?:number,minusFlag?:boolean,clearFlag?:boolean, type?:string) => {
  363. nextTick(()=>{
  364. // id : adTitleList的id chooseNum: 选中的个数 minusFlag:是否需要减少
  365. if(clearFlag){ //清空
  366. pageInfo.adTitleList.forEach(i=>{
  367. i.subList.forEach(s=>{
  368. if(s.id == id){
  369. s.haveContent = false
  370. s.chooseNum = 0
  371. }
  372. })
  373. })
  374. }else{
  375. if(id == 3){
  376. if(DirectPacketExhibitionRef.value){
  377. pageInfo.directObj = DirectPacketExhibitionRef.value[0]?.getObjValue()
  378. }
  379. if(type != 'feedback'){
  380. //清空落地页
  381. if(LandPageRef.value){
  382. LandPageRef.value[0]?.clearEvent()
  383. }
  384. }
  385. updateHaveContent(8,0,false,true)
  386. computeCount()
  387. }
  388. pageInfo.adTitleList.forEach(i=>{
  389. i.subList.forEach(s=>{
  390. if(s.id == id){
  391. s.haveContent = true
  392. if(Number(chooseNum)>0){
  393. s.chooseNum = chooseNum
  394. }
  395. if(minusFlag){//减法开关
  396. s.chooseNum -= 1
  397. }
  398. if(s.chooseNum==0){
  399. s.haveContent = false
  400. if(id == 3 && DirectPacketExhibitionRef.value) {
  401. DirectPacketExhibitionRef.value[0]?.clearDirectContent()
  402. }
  403. }
  404. }
  405. })
  406. })
  407. }
  408. })
  409. }
  410. /**计算广告数、计划数、账号数 并获取计划列表信息 */
  411. const computeCount = (cb?) => {
  412. if(isMock.value){
  413. let { pageInfo_mock, cMaterial_mock, basicInfoData_mock } = mockEvent()
  414. for(let key in pageInfo_mock) {
  415. pageInfo[key] = pageInfo_mock[key]
  416. }
  417. for(let key in cMaterial_mock) {
  418. cMaterial[key] = cMaterial_mock[key]
  419. }
  420. for(let key in basicInfoData_mock) {
  421. basicInfoData[key] = basicInfoData_mock[key]
  422. }
  423. }else{
  424. if( !judgeEvent(7, true) ) return; // 创意文案之前未填写,则不进行下面逻辑
  425. }
  426. previewCompute(pageInfo, cMaterial, basicInfoData).then((res:any)=>{
  427. pageInfo.num_total.accNum = res.num_total.accNum;
  428. pageInfo.num_total.planNum = res.num_total.planNum;
  429. pageInfo.num_total.adNum = res.num_total.adNum;
  430. pageInfo.last_ad_show_list = res.last_ad_show_list;
  431. pageInfo.acc_plan_ad_count = res.acc_plan_ad_count;
  432. cb ? cb() : ''
  433. })
  434. }
  435. /**创意文案回调 */
  436. const writerCallBack = (obj) => {
  437. pageInfo.copywriterInfoData.multiCopyTesting = obj.multiCopyTesting;
  438. pageInfo.copywriterInfoData.data = obj.writer;
  439. pageInfo.copywriterInfoData.allocation_type = obj.allocation_type;
  440. if(obj.writer && Array.isArray(obj.writer)){
  441. updateHaveContent(7,pageInfo.copywriterInfoData.data?.length)
  442. }else{
  443. updateHaveContent(7,0)
  444. }
  445. computeCount()
  446. }
  447. /**落地页回调 */
  448. const landPageEvent = (obj) => {
  449. let length = 0;
  450. for(let i in obj.landPage){
  451. length += obj.landPage[i].length
  452. }
  453. pageInfo.copyLandPageInfoData.data = obj.landPage;
  454. pageInfo.copyLandPageInfoData.allocation_type = obj.allocation_type;
  455. pageInfo.copyLandPageInfoData.loadPageRule = obj.loadPageRule;
  456. pageInfo.copyLandPageInfoData.multiCopyTesting = obj.multiCopyTesting;
  457. if(obj.landPage && JSON.stringify(obj.landPage) != '{}') {
  458. updateHaveContent(8,length)
  459. }else{
  460. updateHaveContent(8,0)
  461. }
  462. computeCount()
  463. }
  464. /**创意基本信息回调 */
  465. const originalityBasicClose = (obj) => {
  466. originalityBasicRef.value?.switchShow(false)
  467. if(obj){
  468. if(originalityBasicInfoData.apiResult?.templateCurr?.adcreative_template_id != obj.apiResult?.templateCurr?.adcreative_template_id){
  469. //清空创意素材、文案、落地页
  470. CreativeMaterial_clear()
  471. if(LandPageRef.value){
  472. LandPageRef.value[0]?.clearEvent()
  473. }
  474. updateHaveContent(7,0,false,true)
  475. if(CopywriterRef.value) {
  476. CopywriterRef.value[0]?.clearEvent()
  477. }
  478. updateHaveContent(8,0,false,true)
  479. }
  480. originalityBasicInfoData.params = _.cloneDeep(obj.apiFormList)
  481. originalityBasicInfoData.receiveForm = _.cloneDeep(obj.form)
  482. originalityBasicInfoData.apiResult = _.cloneDeep(obj.apiResult)
  483. updateHaveContent(5,1)
  484. }
  485. }
  486. /**清空创意基本信息 */
  487. const clearOriginalityInfo = () => {
  488. originalityBasicInfoData.positionKey += 1;
  489. originalityBasicInfoData.receiveForm = {}
  490. originalityBasicInfoData.params = []
  491. originalityBasicInfoData.apiResult = {}
  492. }
  493. onMounted(()=>{
  494. nextTick(async ()=>{
  495. await get_ruleConfig_info() //规则配置获取
  496. //获取推广目标类型
  497. await getPromotedObjectType().then((res)=>{
  498. pageInfo.targetList = res
  499. if(targetRef.value){
  500. targetRef.value.value = pageInfo.targetList[0].name
  501. }
  502. pageInfo.targetValue = targetRef.value?.value
  503. })
  504. get_account_list()
  505. getAdPresetsInfo(); // 广告预存信息获取
  506. })
  507. })
  508. // S 每个模块判断是否可添加编辑
  509. const {
  510. judgeEvent
  511. } = handleJudge({
  512. pageInfo,
  513. basicInfoData,
  514. originalityBasicInfoData,
  515. cMaterial,
  516. })
  517. // E 每个模块判断是否可添加编辑
  518. // S 广告基本信息 及 外部配置
  519. const {
  520. basicInfoClose,
  521. getAdPresetsInfo,
  522. basicOuterClick,
  523. basicOuterClose,
  524. getCommonValue,
  525. isCompleteEvent
  526. } = handleAdBasic({
  527. CreativeMaterialRef,
  528. CopywriterRef,
  529. LandPageRef,
  530. targetRef,
  531. pageInfo,
  532. basicInfoData,
  533. clearOriginalityInfo,
  534. updateHaveContent,
  535. judgeEvent,
  536. CreativeMaterial_clear
  537. })
  538. // E 广告基本信息 及 外部配置
  539. /**S 复用 */
  540. const {
  541. accRef,
  542. ResuseConfigRef,
  543. accVisibleEvent,
  544. accEvent,
  545. aNewConfigEvent,
  546. reuseEvent,
  547. close_reuse_loading,
  548. accClearEvent,
  549. } = resuseConfigEvent({
  550. originalityBasicRef,
  551. CopywriterRef,
  552. LandPageRef,
  553. CreativeMaterialRef,
  554. DirectPacketExhibitionRef,
  555. pageInfo,
  556. basicInfoData,
  557. originalityBasicInfoData,
  558. updateHaveContent,
  559. isCompleteEvent,
  560. getCommonValue,
  561. clearOriginalityInfo,
  562. CreativeMaterial_clear
  563. })
  564. /**E 复用 */
  565. // S 创意素材
  566. const {
  567. assignEvent_CreativeMaterial,
  568. get_cover_info,
  569. } = handleMultiple({
  570. originalityBasicInfoData,
  571. ResuseConfigRef,
  572. computeCount,
  573. cMaterial,
  574. close_reuse_loading,
  575. // updateHaveContent
  576. })
  577. // E 创意素材
  578. /**S 提交预览 */
  579. const {
  580. isMock,
  581. openPreAreaLoading,
  582. PreviewAreaRef,
  583. openPreAreaEvent,
  584. continueCreate,
  585. } = submitPreview({
  586. pageInfo,
  587. basicInfoData,
  588. judgeEvent,
  589. computeCount,
  590. aNewConfigEvent
  591. })
  592. /**E 提交预览 */
  593. /**S 策略组 */
  594. const {
  595. StrategyGroupsDialogRef,
  596. StrategyGroupsListRef,
  597. openStrategyGroups,
  598. openSaveStrategyGroups,
  599. closeSeletedGroup,
  600. strategyGroupsUse
  601. } = strategyGroupsEvent({
  602. DirectPacketExhibitionRef,
  603. LandPageRef,
  604. CopywriterRef,
  605. targetRef,
  606. accRef,
  607. cMaterial,
  608. basicInfoData,
  609. pageInfo,
  610. isMock,
  611. originalityBasicInfoData,
  612. judgeEvent,
  613. aNewConfigEvent,
  614. getAdPresetsInfo,
  615. updateHaveContent,
  616. clearOriginalityInfo,
  617. computeCount
  618. })
  619. /**E 策略组 */
  620. //传值
  621. provide('accountIds',toRef(pageInfo,'accIdsList'))
  622. </script>
  623. <style lang="scss" scoped>
  624. @import "src/assets/style/batchGdt.scss";
  625. .titleBox{
  626. font-size: 14px;
  627. font-weight: 700;
  628. line-height: 48px;
  629. color: #515a6e;
  630. background-color: #fff;
  631. box-shadow: 0 2px 4px 0 rgba(0,0,0,.08);
  632. padding: 0 30px 0 32px;
  633. }
  634. .areaCon{
  635. .screenArea{
  636. display: flex;
  637. align-items: center;
  638. }
  639. .configArea{
  640. margin-top: 20px;
  641. display: flex;
  642. .bigTitle{
  643. font-size: 14px;
  644. border: 1px solid #F2F2F2;
  645. padding: 20px 12px;
  646. font-weight: 600;
  647. }
  648. .blockBox{
  649. width: calc((100vw - 40px - 32px) / 6);
  650. border: 1px solid #F2F2F2;
  651. border-top: none;
  652. border-bottom: none;
  653. }
  654. .no_left_boder{
  655. border-left: none!important;
  656. }
  657. .smallTitle{
  658. font-size: 13px;
  659. padding: 17px 12px;
  660. font-weight: 600;
  661. display: flex;
  662. align-items: center;
  663. .chooseCss{
  664. font-size: 12px;
  665. margin-left: auto;
  666. color: #999999;
  667. font-weight: 400;
  668. }
  669. }
  670. .showInfoArea{
  671. height: 250px;
  672. font-size: 12px;
  673. overflow-y: auto;
  674. padding: 8px 12px;
  675. scrollbar-color: transparent transparent;
  676. &::-webkit-scrollbar{
  677. width: 2px;
  678. }
  679. &:hover{
  680. box-shadow: 0 2px 4px 0 rgba(0,0,0,.08);
  681. }
  682. .noData{
  683. margin: 20px auto;
  684. font-size: 13px;
  685. color: #999999;
  686. text-align: center;
  687. }
  688. }
  689. .btn{
  690. border: 1px solid #F2F2F2;
  691. height: 44px;
  692. display: flex;
  693. align-items: center;
  694. justify-content: center;
  695. cursor: pointer;
  696. border-left: none;
  697. border-right: none;
  698. &:hover{
  699. box-shadow: 0 2px 4px 0 rgba(0,0,0,.08);
  700. }
  701. }
  702. }
  703. .btnArea{
  704. margin-top: 20px;
  705. display: flex;
  706. align-items: center;
  707. }
  708. }
  709. .lH16{
  710. line-height: 16px;
  711. }
  712. .c-515a6e{
  713. color: #515a6e;
  714. }
  715. .outerButton{
  716. &:hover{
  717. .outerIcon{
  718. color: #3173FF
  719. }
  720. .outerIconActive{
  721. color: #00b697;
  722. }
  723. }
  724. }
  725. .outerIcon{
  726. color: #888;
  727. margin: 0 10px;
  728. font-size: 16px;
  729. }
  730. .outerIconActive{
  731. color: #00b697;
  732. }
  733. .oss_url_img{
  734. width:60px;
  735. height: 60px;
  736. border-radius: 6px;
  737. }
  738. .strategy-title{
  739. margin-left: 16px;
  740. font-weight: 400;
  741. color: #666;
  742. display: flex;
  743. align-items: center;
  744. font-size: 14px;
  745. }
  746. </style>