index.tsx 55 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041
  1. import { Button, Card, Checkbox, Divider, Empty, Modal, Popconfirm, Select, Space, Spin, Table, Tabs, Tag, Tooltip, message } from "antd"
  2. import React, { useEffect, useState } from "react"
  3. import style from './index.less'
  4. import '../index.less'
  5. import Selector from "@/pages/launchSystemNew/launchManage/createAd/selector"
  6. import { CheckOutlined, SearchOutlined } from "@ant-design/icons"
  7. import Ad from "./Ad"
  8. import Target from "./Target"
  9. import { getAccountListApi, getGroupListApi } from "@/services/launchAdq/subgroup"
  10. import { useAjax } from "@/Hook/useAjax"
  11. import { useModel } from "umi"
  12. import GoodsModal from "../../components/GoodsModal"
  13. import DataSourceModal from "../../components/DataSourceModal"
  14. import moment from "moment"
  15. import Dynamic from "./Dynamic"
  16. import Material from "./Material"
  17. import MaterialText from "./MaterialText"
  18. import PageList from "./PageList"
  19. import { cartesianProduct, distributeArray, processData, randomString, splitArrayIntoRandomChunks } from "@/utils/utils"
  20. import columns from "./tableConfig"
  21. import SubmitModal from "./submitModal"
  22. import { createAdgroupTaskApi, getSelectTaskDetailApi } from "@/services/adqV3"
  23. import WechatAccount from "../../components/WechatAccount"
  24. import Title from "antd/lib/typography/Title"
  25. import { getCreativeDetailsApi } from "@/services/adqV3/global"
  26. import ConversionSelect from "../../components/ConversionSelect"
  27. import VideoChannel from "../../components/VideoChannel"
  28. import Save from "./Save"
  29. export const DispatchAddelivery = React.createContext<PULLIN.DispatchAddelivery | null>(null);
  30. /**
  31. * 创建广告
  32. * @returns
  33. */
  34. const Create: React.FC = () => {
  35. /*******************************************/
  36. const { getAllUserAccount } = useModel('useLaunchAdq.useAdAuthorize')
  37. const { initTargeting } = useModel('useLaunchV3.useTargeting')
  38. const [addelivery, setAddelivery] = useState<PULLIN.AddeliveryProps>({ adgroups: {}, targeting: [], dynamic: {}, dynamicMaterialDTos: {}, dynamicCreativesTextDTOS: {}, mediaType: 0 })
  39. const { marketingAssetOuterSpec, marketingCarrierType, marketingGoal, siteSet, automaticSiteEnabled, sceneSpec, isConversion } = addelivery.adgroups
  40. const { deliveryMode, creativeTemplateId, creativeComponents } = addelivery.dynamic
  41. const [accSearch, setAccSearch] = useState<string>()
  42. const [accountCreateLogs, setAccountCreateLogs] = useState<PULLIN.AccountCreateLogsProps[]>([]) // 账户
  43. const [goodsVisible, setGoodsVisible] = useState<boolean>(false) // 选择小说弹窗控制
  44. const [wechatVisible, setWechatVisible] = useState<boolean>(false) // 选择微信公众号弹窗控制
  45. const [channelsProfileVisible, setChannelsProfileVisible] = useState<boolean>(false) // 选择微信公众号弹窗控制
  46. const [sourceVisible, setSourceVisible] = useState<boolean>(false) // 选择数据源弹窗控制
  47. const [conversionVisible, setConversionVisible] = useState<boolean>(false) // 选择转化归因控制
  48. const [materialData, setMaterialData] = useState<any>({}) // 素材数据
  49. const [textData, setTextData] = useState<any>({})
  50. const [tableData, setTableData] = useState<any>({})
  51. const [activeKey, setActiveKey] = useState<string>()
  52. const [subVisible, setSubVisible] = useState<boolean>(false) // 选择设置名称弹窗控制
  53. const [adCount, setAdCount] = useState<number>(0)
  54. const [dynamicCount, setDynamicCount] = useState<number>(0)
  55. const [creativeTemplateAppellation, setCreativeTemplateAppellation] = useState<string>()
  56. const [creativeTemplateStyle, setCreativeTemplateStyle] = useState<string>()
  57. const getGroupList = useAjax(() => getGroupListApi())
  58. const createAdgroupTask = useAjax((params) => createAdgroupTaskApi(params))
  59. const getSelectTaskDetail = useAjax((params) => getSelectTaskDetailApi(params))
  60. const getCreativeDetails = useAjax((params) => getCreativeDetailsApi(params))
  61. /*******************************************/
  62. useEffect(() => {
  63. // 获取账户组
  64. getGroupList.run()
  65. // 获取账户列表
  66. getAllUserAccount.run()
  67. initTargeting()
  68. }, [])
  69. useEffect(() => {
  70. if (creativeTemplateId) {
  71. let params: any = {
  72. marketingGoal,
  73. marketingTargetType: marketingAssetOuterSpec.marketingTargetType,
  74. marketingCarrierType,
  75. deliveryMode,
  76. creativeTemplateId,
  77. wechatSceneSpecPosition: sceneSpec?.wechatPosition,
  78. dynamicCreativeType: deliveryMode === 'DELIVERY_MODE_COMPONENT' ? 'DYNAMIC_CREATIVE_TYPE_PROGRAM' : 'DYNAMIC_CREATIVE_TYPE_COMMON'
  79. }
  80. if (automaticSiteEnabled) {
  81. params.automaticSiteEnabled = automaticSiteEnabled
  82. } else {
  83. params.siteSet = siteSet
  84. }
  85. getCreativeDetails.run(params).then(res => {
  86. if (res?.adcreativeTemplateStructAdpermits?.length > 0) {
  87. let adcreativeTemplateStructAdpermits = res?.adcreativeTemplateStructAdpermits[0]
  88. setCreativeTemplateAppellation(adcreativeTemplateStructAdpermits.creativeTemplateAppellation)
  89. setCreativeTemplateStyle(adcreativeTemplateStructAdpermits.creativeTemplateStyle)
  90. let creativeComponents = adcreativeTemplateStructAdpermits?.creativeComponents || []
  91. let result = processData(creativeComponents);
  92. let newMaterialData: any = {};
  93. let newTextData: any = {};
  94. Object.keys(result).forEach(key => {
  95. let data = result[key]
  96. if ((key === 'image_list' || key === 'short_video' || key === 'video' || key === 'image' || key === 'element_story') && data.required) {
  97. newMaterialData[key] = data
  98. } else if (key === 'title' || (data.required && key === 'description')) {
  99. newTextData[key] = data
  100. }
  101. })
  102. setMaterialData(newMaterialData)
  103. setTextData(newTextData)
  104. }
  105. })
  106. }
  107. }, [creativeTemplateId, deliveryMode, marketingGoal, marketingAssetOuterSpec, marketingCarrierType, siteSet, sceneSpec?.wechatPosition, automaticSiteEnabled])
  108. /** 获取分组里账号 */
  109. const getGroupAccountList = (ids: number[]) => {
  110. if (ids.length > 0) {
  111. let data = ids.map(id => getAccountListApi(id))
  112. Promise.all(data).then(res => {
  113. if (res?.length > 0 && res.every((item: { code: number }) => item.code === 200)) {
  114. let userArr: any[] = []
  115. res.forEach((item: { data: { adAccountList: { accountId: number, id: number }[] } }) => {
  116. item.data.adAccountList.forEach(acc => {
  117. let obj = userArr.find((item: { accountId: number }) => item.accountId === acc.accountId)
  118. if (!obj) {
  119. userArr.push(acc)
  120. }
  121. })
  122. })
  123. setAccountCreateLogs(userArr?.map((item) => ({ accountId: item?.accountId })))
  124. clearData()
  125. setAddelivery({ adgroups: {}, targeting: [], dynamic: {}, dynamicMaterialDTos: {}, dynamicCreativesTextDTOS: {}, mediaType: 0 })
  126. } else {
  127. message.error('操作异常')
  128. }
  129. })
  130. } else {
  131. setAccountCreateLogs([])
  132. }
  133. }
  134. /** 存为预设 */
  135. const severBd = () => {
  136. // queryForm accountCreateLogs
  137. localStorage.setItem('ADQADV3', JSON.stringify({
  138. addelivery,
  139. accountCreateLogs,
  140. materialData,
  141. textData
  142. }))
  143. message.success('存储成功')
  144. }
  145. /** 清除 */
  146. const delBdPlan = () => {
  147. localStorage.removeItem('ADQADV3')
  148. setAccountCreateLogs([])
  149. setMaterialData({})
  150. setTextData({})
  151. setAddelivery({
  152. adgroups: {},
  153. targeting: [],
  154. dynamic: {},
  155. dynamicMaterialDTos: {},
  156. dynamicCreativesTextDTOS: {},
  157. mediaType: 0
  158. })
  159. setTableData({})
  160. }
  161. /**数据回填 */
  162. useEffect(() => {
  163. let taskId = sessionStorage.getItem('TASKID3.0')
  164. let adqAdData = localStorage.getItem('ADQADV3')
  165. if (taskId) {
  166. getSelectTaskDetail.run(taskId).then(res => {
  167. if (res) {
  168. const { adgroupDTO, accountIdParamVOMap, targetings, dynamicCreativesDTO: { mediaType, ...dynamic }, dynamicCreativesTextDTO, dynamicMaterialDTOS } = res
  169. let beginDate = adgroupDTO.beginDate
  170. let endDate = adgroupDTO.endDate
  171. if (beginDate && moment(beginDate) < moment()) {
  172. beginDate = moment().format('YYYY-MM-DD')
  173. endDate = moment().add(7, 'day').format('YYYY-MM-DD')
  174. message.warning('请注意,检测投放开始日期小于今天,已自动改成今天,如需修改,请重新设置')
  175. }
  176. let dynamicGroup: any[] = []
  177. if (dynamic.deliveryMode === 'DELIVERY_MODE_CUSTOMIZE') {
  178. dynamicGroup = dynamicMaterialDTOS?.map((item: any[]) => {
  179. let { type, valueJson } = item[0]
  180. let value = JSON.parse(valueJson).value
  181. if (type === 'image') {
  182. return { image_id: { id: value.imageId, url: value.imageUrl, materialType: value.materialType } }
  183. } else if (type === 'image_list' || type === 'element_story') {
  184. return { [type]: value.list.map((l: { imageUrl: any; imageId: any; materialType: any }) => ({ url: l.imageUrl, id: l.imageId, materialType: l.materialType })) }
  185. } else if (type === 'short_video' || type === 'video') {
  186. let field = type === 'video' ? 'video_id' : 'short_video1'
  187. let videoData: any = {}
  188. videoData[field] = { materialType: value.materialType, url: value.videoUrl, id: value.videoId }
  189. if (value.imageUrl) {
  190. videoData['cover_id'] = { materialType: value.materialCoverType, url: value.imageUrl, id: value.iamgeId }
  191. }
  192. return videoData
  193. } else {
  194. return {}
  195. }
  196. })
  197. } else { // 组件化创意
  198. dynamicGroup = dynamicMaterialDTOS?.map((item: any[]) => {
  199. return {
  200. list: item?.map((i: any) => {
  201. let { type, valueJson } = i
  202. let value = JSON.parse(valueJson).value
  203. if (type === 'image') {
  204. return { id: value.imageId, url: value.imageUrl, materialType: value.materialType }
  205. } else if (type === 'image_list') {
  206. return value.list.map((l: { imageUrl: any; imageId: any; materialType: any }) => ({ url: l.imageUrl, id: l.imageId, materialType: l.materialType }))
  207. } else if (type === 'video') {
  208. return { materialType: value.materialType, url: value.videoUrl, id: value.videoId }
  209. } else {
  210. return {}
  211. }
  212. })
  213. }
  214. })
  215. }
  216. let isConversion = false
  217. setAccountCreateLogs(Object.keys(accountIdParamVOMap || {}).map(accountId => {
  218. const { productDTOS, wechatOfficialAccountsVO, pageList, landingPageVOS, userActionSetsList, conversionInfo, wechatChannelVO, wechatAppletList } = accountIdParamVOMap[accountId]
  219. let data: PULLIN.AccountCreateLogsProps = {
  220. accountId: Number(accountId),
  221. productList: productDTOS
  222. }
  223. if (wechatOfficialAccountsVO) {
  224. data.wechatChannelList = [wechatOfficialAccountsVO]
  225. }
  226. if (pageList || landingPageVOS || wechatAppletList) {
  227. data.pageList = pageList || landingPageVOS || wechatAppletList?.map((item: { appletName: any; id: any }) => ({ ...item, pageName: item.appletName, pageId: item.id }))
  228. }
  229. if (userActionSetsList) {
  230. data.userActionSetsList = userActionSetsList
  231. }
  232. if (conversionInfo) {
  233. isConversion = true
  234. data.newConversionList = [conversionInfo]
  235. }
  236. if (wechatChannelVO) {
  237. data.videoChannelList = [wechatChannelVO]
  238. }
  239. return data
  240. }))
  241. setAddelivery({
  242. adgroups: { ...adgroupDTO, isConversion, adgroupName: adgroupDTO.adgroupName + '_副本' + randomString(true, 3, 5), endDate, beginDate },
  243. targeting: targetings.map((item: any) => {
  244. const { targetingName, ...targeting } = item
  245. return { targetingName, targeting }
  246. }),
  247. dynamic,
  248. dynamicMaterialDTos: dynamicGroup.length > 0 ? { dynamicGroup } : {},
  249. dynamicCreativesTextDTOS: dynamicCreativesTextDTO,
  250. mediaType: mediaType || 0
  251. })
  252. sessionStorage.removeItem('TASKID3.0')
  253. }
  254. })
  255. } else if (adqAdData) {
  256. const { addelivery, accountCreateLogs, materialData, textData } = JSON.parse(adqAdData)
  257. if (addelivery?.adgroups) {
  258. if (addelivery?.adgroups?.beginDate && moment(addelivery?.adgroups?.beginDate) < moment()) {
  259. addelivery.adgroups.beginDate = moment().format('YYYY-MM-DD')
  260. message.warning('请注意,检测投放开始日期小于今天,已自动改成今天,如需修改,请重新设置')
  261. }
  262. if (addelivery?.adgroups?.endDate && moment(addelivery?.adgroups?.endDate) < moment()) {
  263. addelivery.adgroups.endDate = moment().format('YYYY-MM-DD')
  264. message.warning('请注意,检测投放结束日期小于今天,已自动改成今天,如需修改,请重新设置')
  265. }
  266. }
  267. setAddelivery({ ...addelivery })
  268. setAccountCreateLogs(accountCreateLogs)
  269. setMaterialData(materialData)
  270. setTextData(textData)
  271. }
  272. }, [])
  273. // 预览
  274. const preview = () => {
  275. if (accountCreateLogs?.length === 0) {
  276. message.error('请先选择媒体账户')
  277. return
  278. }
  279. const { adgroups, targeting, dynamic, dynamicMaterialDTos, dynamicCreativesTextDTOS, mediaType } = addelivery
  280. if (!(adgroups && Object.keys(adgroups).length)) {
  281. message.error('请先配置广告信息')
  282. return
  283. }
  284. if (!(targeting?.length)) {
  285. message.error('请先添加定向')
  286. return
  287. }
  288. if (!(dynamic && Object.keys(dynamic).length)) {
  289. message.error('请先配置创意')
  290. return
  291. }
  292. if ((materialData && Object.keys(materialData).length) && !(dynamicMaterialDTos && Object.keys(dynamicMaterialDTos).length)) {
  293. message.error('请先配置创意素材')
  294. return
  295. }
  296. if ((textData && Object.keys(textData).length) && !(dynamicCreativesTextDTOS && Object.keys(dynamicCreativesTextDTOS).length)) {
  297. message.error('请先配置创意文案')
  298. return
  299. }
  300. if (['MARKETING_TARGET_TYPE_FICTION', 'MARKETING_TARGET_TYPE_SHORT_DRAMA'].includes(marketingAssetOuterSpec?.marketingTargetType) && !accountCreateLogs?.some(item => item?.productList?.length)) {
  301. message.error(marketingAssetOuterSpec?.marketingTargetType === 'MARKETING_TARGET_TYPE_FICTION' ? '请先选择小说' : '请先选择短剧')
  302. return
  303. }
  304. if ((['MARKETING_TARGET_TYPE_WECHAT_OFFICIAL_ACCOUNT'].includes(marketingAssetOuterSpec?.marketingTargetType) || marketingCarrierType === 'MARKETING_CARRIER_TYPE_WECHAT_OFFICIAL_ACCOUNT' || dynamic?.creativeComponents?.brand?.[0]?.value?.jumpInfo?.pageType === 'PAGE_TYPE_WECHAT_OFFICIAL_ACCOUNT_DETAIL') && !accountCreateLogs?.some(item => item?.wechatChannelList?.length)) {
  305. message.error('请先选择公众号')
  306. return
  307. }
  308. if (creativeComponents?.brand?.[0]?.value?.jumpInfo?.pageType === 'PAGE_TYPE_WECHAT_CHANNELS_PROFILE' && !accountCreateLogs?.some(item => item?.videoChannelList?.length)) {
  309. message.error('请先选择视频号')
  310. return
  311. }
  312. if (isConversion && !accountCreateLogs?.some(item => item?.newConversionList?.length)) {
  313. message.error('请先选择转化归因')
  314. return
  315. }
  316. if (!accountCreateLogs?.some(item => item?.pageList?.length)) {
  317. message.error('请先选择落地页')
  318. return
  319. }
  320. let newTableData: any = {}
  321. let newAdCount = 0, newdynamicCount = 0
  322. let textType = dynamicCreativesTextDTOS.type
  323. let textDto = dynamicCreativesTextDTOS?.dynamicCreativesTextDetailDTOList || []
  324. let textDtoLenth = textDto.length
  325. let dynamicGroupLength = dynamicMaterialDTos?.dynamicGroup?.length || 0
  326. let newDynamicGroup: any = []
  327. if (![910].includes(dynamic.creativeTemplateId)) {
  328. newDynamicGroup = dynamicMaterialDTos?.dynamicGroup || []
  329. if (newDynamicGroup.length > 0 && [0, 1, 2, 3, 4].includes(textType)) {
  330. if (textType === 0) {
  331. newDynamicGroup = newDynamicGroup.map((item: any) => ({ ...item, textDto: textDto?.[0] }))
  332. } else if (textType === 1) {
  333. newDynamicGroup = newDynamicGroup.map((item: any, index: number) => ({ ...item, textDto: textDto?.[index] }))
  334. } else if (textType === 2) {
  335. newDynamicGroup = newDynamicGroup.map((item: any, index: number) => ({ ...item, textDto: textDto?.[index % textDtoLenth] }))
  336. } else if ((textType === 3 && mediaType === 0) || (textType === 4 && mediaType === 1)) {
  337. newDynamicGroup = cartesianProduct(newDynamicGroup, textDto || [{}]).map((item) => {
  338. let [dynamicGroup, textDtoData] = item
  339. return {
  340. ...dynamicGroup as any,
  341. textDto: textDtoData
  342. }
  343. })
  344. }
  345. }
  346. }
  347. // 创意组平均分配到广告逻辑
  348. let averageAdDynamicList: any[] = []
  349. if ((mediaType === 1 || mediaType === 2) && newDynamicGroup.length) {
  350. let adLength = 0
  351. accountCreateLogs.forEach(item => {
  352. let productList: any[] = []
  353. if (['MARKETING_TARGET_TYPE_FICTION', 'MARKETING_TARGET_TYPE_SHORT_DRAMA'].includes(marketingAssetOuterSpec?.marketingTargetType)) { // 小说 短剧
  354. productList = item?.productList || []
  355. } else if (['MARKETING_TARGET_TYPE_WECHAT_OFFICIAL_ACCOUNT'].includes(marketingAssetOuterSpec?.marketingTargetType)) { // 公众号
  356. productList = item?.wechatChannelList || []
  357. } else {
  358. productList = [{}]
  359. }
  360. adLength += productList.length * targeting.length
  361. })
  362. if (mediaType === 1) {
  363. if (textType === 4) {
  364. if (adLength > newDynamicGroup.length) {
  365. message.error(`创意组分配规则选择“平均分配到广告”时,创意组总数必须大于等于广告总数。当前创意组数量:${dynamicGroupLength},广告数量:${adLength}`)
  366. return
  367. }
  368. averageAdDynamicList = splitArrayIntoRandomChunks(newDynamicGroup, adLength)
  369. } else {
  370. if (adLength > dynamicGroupLength) {
  371. message.error(`创意组分配规则选择“平均分配到广告”时,创意组总数必须大于等于广告总数。当前创意组数量:${dynamicGroupLength},广告数量:${adLength}`)
  372. return
  373. }
  374. averageAdDynamicList = distributeArray(newDynamicGroup, adLength)
  375. }
  376. } else if (mediaType === 2) {
  377. if (adLength < dynamicGroupLength) {
  378. message.error(`创意组分配规则选择“顺序分配到广告”时,创意组总数必须小于等于广告总数。当前创意组数量:${dynamicGroupLength},广告数量:${adLength}`)
  379. return
  380. }
  381. }
  382. }
  383. if (textType === 1) {
  384. if (dynamicGroupLength !== textDtoLenth) {
  385. message.error(`当前创意文案是“创意组一一对应”模式,创意组总数(${dynamicGroupLength})要等于创意文案总数(${textDtoLenth})`)
  386. return
  387. }
  388. if (!dynamicCreativesTextDTOS.dynamicCreativesTextDetailDTOList.every((item: {}) => item && Object.keys(item).length)) {
  389. message.error('创意文案配置错误,内容空')
  390. return
  391. }
  392. }
  393. // 落地页平均分配判断数量
  394. if ([910].includes(dynamic.creativeTemplateId) && dynamic?.landingPageType === 1) {
  395. let targetingLength = targeting.length
  396. if (accountCreateLogs.some(item => {
  397. let productListLength = item?.productList?.length || 1
  398. let total = targetingLength * productListLength
  399. let pageLength = item.pageList.length
  400. if (total > pageLength) {
  401. message.error(`当前${item.accountId}下的广告总数(${total})大于落地页总数(${pageLength}),平均分配需要落地页总数大于广告总数`)
  402. return true
  403. }
  404. return false
  405. })) {
  406. return
  407. }
  408. }
  409. let accountIndex = 0, accountIndex1 = 0
  410. accountCreateLogs.forEach(item => {
  411. let productList: any[] = [{}]
  412. if (['MARKETING_TARGET_TYPE_FICTION', 'MARKETING_TARGET_TYPE_SHORT_DRAMA'].includes(marketingAssetOuterSpec?.marketingTargetType)) { // 小说
  413. productList = item?.productList || []
  414. } else if (['MARKETING_TARGET_TYPE_WECHAT_OFFICIAL_ACCOUNT'].includes(marketingAssetOuterSpec?.marketingTargetType)) { // 公众号
  415. productList = item?.wechatChannelList || []
  416. }
  417. let data = cartesianProduct(productList, targeting).map(newD => {
  418. let [productDto, targetDto, index] = newD
  419. let suffix = '_' + item.accountId + '_' + index
  420. let averageAdDynamic = averageAdDynamicList?.[accountIndex]
  421. let dat: any = {
  422. id: item.accountId + '_' + index,
  423. accountId: item.accountId, // 账户
  424. userActionSetsList: item.userActionSetsList, // 数据源
  425. conversionList: item.newConversionList, // 转化归因
  426. pageListDto: item.pageList, // 落地页
  427. productDto, // 商品
  428. targetDto: { // 定向
  429. ...targetDto,
  430. targetingName: targetDto.targetingName + suffix
  431. },
  432. adgroupsDto: { // 广告信息
  433. ...adgroups,
  434. adgroupName: adgroups.adgroupName + suffix
  435. },
  436. dynamicDto: dynamic, // 创意信息
  437. averageAdDynamic,
  438. rowSpan: (mediaType === 1 && textType !== 4) ? averageAdDynamic.length : ([910].includes(dynamic.creativeTemplateId) ? item.pageList?.length : (textType === 3 ? textDtoLenth * dynamicGroupLength : dynamicGroupLength)) || 1
  439. }
  440. if (marketingCarrierType === 'MARKETING_CARRIER_TYPE_WECHAT_OFFICIAL_ACCOUNT') { // 营销载体
  441. dat.marketingCarrierDto = item?.wechatChannelList
  442. }
  443. accountIndex += 1
  444. return dat
  445. })
  446. newAdCount += data.length
  447. let newData: any[] = []
  448. if ([910].includes(dynamic.creativeTemplateId)) {
  449. if (dynamic?.landingPageType === 1) {
  450. let averageAdPageList: any[] = distributeArray(item.pageList, productList.length * targeting.length)
  451. data.forEach((item, aIndex) => {
  452. let aPageList: any[] = averageAdPageList[aIndex]
  453. aPageList.forEach((page, index) => {
  454. newData.push({
  455. ...item,
  456. id: item.id + '_' + index,
  457. pageListDto: [page],
  458. dynamicDto: {
  459. ...item.dynamicDto,
  460. dynamicCreativeName: item.dynamicDto.dynamicCreativeName + index
  461. },
  462. rowSpan: index === 0 ? aPageList.length : 0,
  463. adLength: data.length,
  464. isRowSpan: true
  465. })
  466. })
  467. })
  468. } else {
  469. newData = cartesianProduct(data, item.pageList).map((item, index) => {
  470. let [d1, pageList, num] = item
  471. return {
  472. ...d1,
  473. id: d1.id + '_' + index,
  474. pageListDto: [pageList],
  475. dynamicDto: {
  476. ...d1.dynamicDto,
  477. dynamicCreativeName: d1.dynamicDto.dynamicCreativeName + num
  478. }
  479. }
  480. })
  481. }
  482. } else {
  483. if (mediaType === 1) {
  484. data.forEach(item => {
  485. const { averageAdDynamic, ...ad } = item
  486. if (textType === 3) {
  487. let rowSpan = textDtoLenth * averageAdDynamic.length
  488. cartesianProduct(textDto, averageAdDynamic).forEach((taad: any, index) => {
  489. let [textValue, aad] = taad
  490. newData.push({
  491. ...ad,
  492. id: ad.id + '_' + index,
  493. dynamicGroup: aad,
  494. textDto: textValue,
  495. rowSpan: index === 0 ? rowSpan : 0,
  496. adLength: data.length,
  497. isRowSpan: true
  498. })
  499. })
  500. } else if (textType === 4) {
  501. averageAdDynamic.forEach((aad: any, index: number) => {
  502. newData.push({
  503. ...ad,
  504. id: ad.id + '_' + index,
  505. dynamicGroup: aad,
  506. textDto: aad?.textDto,
  507. adLength: data.length,
  508. rowSpan: index === 0 ? averageAdDynamic.length : 0,
  509. isRowSpan: true
  510. })
  511. })
  512. } else {
  513. averageAdDynamic.forEach((aad: any, index: number) => {
  514. newData.push({
  515. ...ad,
  516. id: ad.id + '_' + index,
  517. dynamicGroup: aad,
  518. textDto: aad?.textDto,
  519. adLength: data.length
  520. })
  521. })
  522. }
  523. })
  524. } else if (mediaType === 2) {
  525. data.forEach((item) => {
  526. const { averageAdDynamic, ...ad } = item
  527. if (textType === 3) {
  528. cartesianProduct(textDto, [newDynamicGroup[accountIndex1 % newDynamicGroup.length]]).forEach((taad: any, i) => {
  529. let [textValue, aad, index] = taad
  530. newData.push({
  531. ...ad,
  532. id: ad.id + '_' + index,
  533. dynamicGroup: aad,
  534. textDto: textValue,
  535. rowSpan: i === 0 ? textDto.length : 0,
  536. adLength: data.length,
  537. isRowSpan: true
  538. })
  539. })
  540. } else {
  541. let { textDto, ...dynamicGroup } = newDynamicGroup[accountIndex1 % newDynamicGroup.length]
  542. newData.push({
  543. ...ad,
  544. dynamicGroup,
  545. textDto,
  546. rowSpan: 1,
  547. adLength: data.length
  548. })
  549. }
  550. accountIndex1 += 1
  551. })
  552. } else { // 全账号复用创意组 所有广告一样的创意组
  553. newData = cartesianProduct(data, newDynamicGroup.length > 0 ? newDynamicGroup : [{}]).map((item, index) => {
  554. let [d1, group] = item
  555. return {
  556. ...d1,
  557. id: d1.id + '_' + index,
  558. dynamicGroup: group,
  559. textDto: (group as any)?.textDto,
  560. adLength: data.length
  561. }
  562. })
  563. }
  564. }
  565. newdynamicCount = newdynamicCount + newData.length
  566. newTableData[item.accountId] = newData
  567. })
  568. setAdCount(newAdCount)
  569. setDynamicCount(newdynamicCount)
  570. setActiveKey(accountCreateLogs?.[0].accountId?.toString())
  571. console.log('newTableData-->', newTableData)
  572. setTableData(newTableData)
  573. }
  574. // 提交
  575. const onSubmit = (values: any) => {
  576. const { adgroups, targeting, dynamic, dynamicMaterialDTos, dynamicCreativesTextDTOS, mediaType } = JSON.parse(JSON.stringify(addelivery)) as PULLIN.AddeliveryProps
  577. let dynamicMaterialDTOS = []
  578. if (dynamic.deliveryMode === 'DELIVERY_MODE_CUSTOMIZE') {
  579. if ((materialData && Object.keys(materialData).length && dynamicMaterialDTos && Object.keys(dynamicMaterialDTos).length)) {
  580. let mType = Object.keys(materialData)[0];
  581. dynamicMaterialDTOS = dynamicMaterialDTos.dynamicGroup?.map((item: any) => {
  582. if (mType === 'image') {
  583. return [{
  584. type: mType,
  585. valueJson: JSON.stringify({
  586. value: {
  587. imageUrl: item?.image_id?.url,
  588. imageId: item?.image_id?.id,
  589. materialType: item?.image_id?.materialType
  590. }
  591. })
  592. }]
  593. } else if (mType === 'image_list' || mType === 'element_story') {
  594. let key = 'image_list'
  595. if (mType === 'element_story') {
  596. key = 'element_story'
  597. }
  598. let list = item?.[key]?.map((l: any) => {
  599. return {
  600. imageUrl: l?.url,
  601. imageId: l?.id,
  602. materialType: l?.materialType
  603. }
  604. })
  605. return [{
  606. type: mType,
  607. valueJson: JSON.stringify({
  608. value: {
  609. list
  610. }
  611. })
  612. }]
  613. } else if (['short_video', 'video'].includes(mType)) {
  614. let value: any = {
  615. materialType: item?.video_id?.materialType || item?.short_video1?.materialType || 0,
  616. videoUrl: item?.video_id?.url || item?.short_video1?.url,
  617. videoId: item?.video_id?.id || item?.short_video1?.id
  618. }
  619. if (item?.cover_id?.url) {
  620. value.imageUrl = item?.cover_id?.url
  621. value.imageId = item?.cover_id?.id
  622. value.materialCoverType = item?.cover_id?.materialType
  623. }
  624. return [{
  625. type: mType,
  626. valueJson: JSON.stringify({
  627. value
  628. })
  629. }]
  630. }
  631. return [{
  632. type: mType,
  633. valueJson: ''
  634. }]
  635. })
  636. }
  637. } else {
  638. if (dynamicMaterialDTos && Object.keys(dynamicMaterialDTos).length) {
  639. dynamicMaterialDTOS = dynamicMaterialDTos.dynamicGroup?.map((item: { list: any[] }) => {
  640. return item.list.map(l => {
  641. if (Array.isArray(l)) {
  642. return {
  643. type: 'image_list',
  644. valueJson: JSON.stringify({
  645. value: {
  646. list: l?.map((i: any) => {
  647. return {
  648. imageUrl: i?.url,
  649. imageId: i?.id,
  650. materialType: i?.materialType
  651. }
  652. })
  653. }
  654. })
  655. }
  656. } else if (l?.url?.includes('mp4')) {
  657. return {
  658. type: 'video',
  659. valueJson: JSON.stringify({
  660. value: {
  661. materialType: l?.materialType,
  662. videoUrl: l?.url,
  663. videoId: l?.id
  664. }
  665. })
  666. }
  667. } else {
  668. return {
  669. type: 'image',
  670. valueJson: JSON.stringify({
  671. value: {
  672. imageUrl: l?.url,
  673. imageId: l?.id,
  674. materialType: l?.materialType
  675. }
  676. })
  677. }
  678. }
  679. })
  680. })
  681. }
  682. }
  683. let accountIdParamDTOMap: any = {}
  684. accountCreateLogs.forEach(item => {
  685. let { pageList, productList, userActionSetsList, accountId, wechatChannelList, newConversionList, videoChannelList } = item
  686. let userActionSetsListDto = userActionSetsList?.map((item: any) => ({ id: item?.userActionSetId, type: item?.type })) // dataSourceId
  687. let map: any = {
  688. userActionSetsList: userActionSetsListDto,
  689. pageList: pageList?.map((item: { pageId: any }) => item.pageId)
  690. }
  691. if (productList && ['MARKETING_TARGET_TYPE_FICTION', 'MARKETING_TARGET_TYPE_SHORT_DRAMA'].includes(marketingAssetOuterSpec?.marketingTargetType)) {
  692. map.productDTOS = productList?.map(item => {
  693. return { productId: item.marketingAssetId }
  694. })
  695. }
  696. if (wechatChannelList && (['MARKETING_TARGET_TYPE_WECHAT_OFFICIAL_ACCOUNT'].includes(marketingAssetOuterSpec?.marketingTargetType) || marketingCarrierType === 'MARKETING_CARRIER_TYPE_WECHAT_OFFICIAL_ACCOUNT' || dynamic?.creativeComponents?.brand?.[0]?.value?.jumpInfo?.pageType === 'PAGE_TYPE_WECHAT_OFFICIAL_ACCOUNT_DETAIL')) {
  697. map.wechatChannelId = wechatChannelList?.[0]?.wechatOfficialAccountId
  698. }
  699. if (newConversionList && isConversion) {
  700. map.conversionId = newConversionList?.[0]?.conversionId
  701. }
  702. if (videoChannelList && creativeComponents?.brand?.[0]?.value?.jumpInfo?.pageType === 'PAGE_TYPE_WECHAT_CHANNELS_PROFILE') {
  703. map.videoChannelId = videoChannelList?.[0]?.wechatChannelsAccountId
  704. }
  705. accountIdParamDTOMap[accountId] = map
  706. })
  707. let dynamicCreativesDTO = { ...dynamic, mediaType }
  708. if (dynamic.deliveryMode === 'DELIVERY_MODE_COMPONENT') {
  709. dynamicCreativesDTO.creativeTemplateId = 711
  710. }
  711. delete adgroups?.isConversion // 前端控制新链路字段
  712. let params = {
  713. ...values,
  714. adgroupDTO: adgroups,
  715. targetings: targeting.map(item => ({ targetingName: item.targetingName, ...item?.targeting || {} })),
  716. dynamicCreativesDTO,
  717. dynamicCreativesTextDTOS,
  718. dynamicMaterialDTOS,
  719. accountIdParamDTOMap
  720. }
  721. // setSubVisible(false)
  722. createAdgroupTask.run(params).then(res => {
  723. if (res) {
  724. Modal.success({
  725. content: '任务提交成功',
  726. bodyStyle: { fontWeight: 700 },
  727. okText: '跳转任务列表',
  728. closable: true,
  729. onOk: () => {
  730. sessionStorage.setItem('CAMPV3', values?.taskName)
  731. window.location.href = '/#/launchSystemV3/tencentAdPutIn/taskList'
  732. },
  733. onCancel: () => {
  734. setSubVisible(false)
  735. }
  736. })
  737. }
  738. })
  739. }
  740. const clearData = () => {
  741. setTableData({})
  742. }
  743. return <Space direction="vertical" style={{ width: '100%' }}>
  744. <Spin spinning={createAdgroupTask.loading || getSelectTaskDetail.loading || getCreativeDetails.loading}>
  745. <Card
  746. size="small"
  747. title={
  748. <div>
  749. <Space>
  750. <div className={style.cardTitle}>配置区</div>
  751. </Space>
  752. </div>
  753. }
  754. className={style.createAd}
  755. >
  756. <Space wrap>
  757. <Selector label="媒体账户组">
  758. <Select
  759. mode="multiple"
  760. style={{ minWidth: 200 }}
  761. placeholder="快捷选择媒体账户组"
  762. maxTagCount={1}
  763. allowClear
  764. bordered={false}
  765. filterOption={(input: any, option: any) => {
  766. return option!.children?.toString().toLowerCase().includes(input.toLowerCase())
  767. }}
  768. onChange={(e, option) => { getGroupAccountList(e) }}
  769. >
  770. {getGroupList?.data && getGroupList?.data?.map((item: any) => <Select.Option value={item.groupId} key={item.groupId}>{item.groupName}</Select.Option>)}
  771. </Select>
  772. </Selector>
  773. <Selector label="媒体账户">
  774. <Select
  775. mode="multiple"
  776. style={{ minWidth: 200, maxWidth: 500 }}
  777. placeholder="媒体账户(多个,,空格换行)"
  778. maxTagCount={1}
  779. allowClear
  780. bordered={false}
  781. maxTagPlaceholder={
  782. <Tooltip
  783. color="#FFF"
  784. title={<span style={{ color: '#000' }}>
  785. {accountCreateLogs?.filter((item, index) => index !== 0)
  786. ?.map((item, index) => <Tag
  787. key={index}
  788. closable
  789. onClose={() => {
  790. setAccountCreateLogs(accountCreateLogs?.filter(item1 => item1.accountId !== item.accountId))
  791. // setQueryForm({ ...queryForm, adqPageList: [], pageList: [], taskMediaMaps: queryForm?.taskMediaMaps?.map((item: { sysPageId: number }) => ({ ...item, sysPageId: '', accountPageIdMap: {}, cropUserGroupMap: [] })) })
  792. // clearData()
  793. }}
  794. >{item.accountId}</Tag>)}</span>
  795. }
  796. >
  797. <span>+{accountCreateLogs?.length > 1 ? accountCreateLogs.length - 1 : 0}</span>
  798. </Tooltip>
  799. }
  800. autoClearSearchValue={false}
  801. filterOption={(input: any, option: any) => {
  802. let newInput: string[] = input ? input?.split(/[,,\n\s]+/ig).filter((item: any) => item) : []
  803. return newInput?.some(val => option!.children?.toString().toLowerCase()?.includes(val))
  804. }}
  805. value={accountCreateLogs?.map(item => item?.accountId)}
  806. onChange={(e) => {
  807. setAccountCreateLogs(e?.map((item: any) => ({ accountId: item })))
  808. }}
  809. searchValue={accSearch}
  810. onSearch={(val) => {
  811. setAccSearch(val)
  812. }}
  813. dropdownRender={menu => (
  814. <>
  815. {menu}
  816. <Divider style={{ margin: '8px 0' }} />
  817. <Space style={{ padding: '0 8px 4px' }}>
  818. <Checkbox onChange={(e) => {
  819. let data = []
  820. if (e.target.checked) {
  821. data = JSON.parse(JSON.stringify(getAllUserAccount?.data?.data))
  822. if (accSearch) {
  823. let newAccSearch = accSearch?.split(/[,,\n\s]+/ig).filter((item: any) => item)
  824. data = data?.filter((item: any) => newAccSearch?.some(val => item!.accountId?.toString().toLowerCase()?.includes(val)))
  825. }
  826. }
  827. // setQueryForm({ ...queryForm, adqPageList: [], pageList: [], taskMediaMaps: queryForm?.taskMediaMaps?.map((item: { sysPageId: number }) => ({ ...item, sysPageId: '', accountPageIdMap: {}, cropUserGroupMap: [] })) })
  828. setAccountCreateLogs(data?.map((item: any) => ({ accountId: item?.accountId })))
  829. // clearData()
  830. }}>全选</Checkbox>
  831. </Space>
  832. </>
  833. )}
  834. >
  835. {getAllUserAccount?.data?.data?.map((item: any) => <Select.Option value={item.accountId} key={item.id}>{item.remark ? item.accountId + '_' + item.remark : item.accountId}</Select.Option>)}
  836. </Select>
  837. </Selector>
  838. {accountCreateLogs?.length > 0 && <>
  839. {['MARKETING_TARGET_TYPE_FICTION', 'MARKETING_TARGET_TYPE_SHORT_DRAMA'].includes(marketingAssetOuterSpec?.marketingTargetType) && <Button type="primary" danger={!accountCreateLogs?.some(item => item?.productList?.length)} onClick={() => { setGoodsVisible(true) }}>{accountCreateLogs?.some(item => item?.productList?.length) ? <>重新选择{marketingAssetOuterSpec?.marketingTargetType === 'MARKETING_TARGET_TYPE_FICTION' ? '小说' : '短剧'} <CheckOutlined style={{ color: '#FFFFFF' }} /></> : `请选择${marketingAssetOuterSpec?.marketingTargetType === 'MARKETING_TARGET_TYPE_FICTION' ? '小说' : '短剧'}`}</Button>}
  840. {(marketingAssetOuterSpec?.marketingTargetType === 'MARKETING_TARGET_TYPE_WECHAT_OFFICIAL_ACCOUNT' || marketingCarrierType === 'MARKETING_CARRIER_TYPE_WECHAT_OFFICIAL_ACCOUNT' || creativeComponents?.brand?.[0]?.value?.jumpInfo?.pageType === 'PAGE_TYPE_WECHAT_OFFICIAL_ACCOUNT_DETAIL') && <Button type="primary" danger={!accountCreateLogs?.some(item => item?.wechatChannelList?.length)} onClick={() => { setWechatVisible(true) }}>{accountCreateLogs?.some(item => item?.wechatChannelList?.length) ? <>重新选择公众号 <CheckOutlined style={{ color: '#FFFFFF' }} /></> : '请选择公众号'}</Button>}
  841. {creativeComponents?.brand?.[0]?.value?.jumpInfo?.pageType === 'PAGE_TYPE_WECHAT_CHANNELS_PROFILE' && <Button type="primary" danger={!accountCreateLogs?.some(item => item?.videoChannelList?.length)} onClick={() => { setChannelsProfileVisible(true) }}>{accountCreateLogs?.some(item => item?.videoChannelList?.length) ? <>重新选择视频号 <CheckOutlined style={{ color: '#FFFFFF' }} /></> : '请选择视频号'}</Button>}
  842. {!isConversion ?
  843. <Button onClick={() => { setSourceVisible(true) }}>精准匹配归因(选填){accountCreateLogs?.some(item => item?.userActionSetsList?.length) && <CheckOutlined style={{ color: '#1890ff' }} />}</Button>
  844. :
  845. <Button type="primary" danger={!accountCreateLogs?.some(item => item?.newConversionList?.length)} onClick={() => { setConversionVisible(true) }}>{accountCreateLogs?.some(item => item?.newConversionList?.length) ? <>重新选择转化归因<CheckOutlined style={{ color: '#FFF' }} /></> : '请选择转化归因'}</Button>
  846. }
  847. </>}
  848. </Space>
  849. <div className={style.settingsBody}>
  850. <div className={style.settingsBody_content}>
  851. <DispatchAddelivery.Provider
  852. value={{
  853. addelivery,
  854. setAddelivery,
  855. accountCreateLogs,
  856. setAccountCreateLogs,
  857. materialData,
  858. setMaterialData,
  859. textData,
  860. setTextData,
  861. clearData
  862. }}>
  863. <div className={style.settingsBody_content_right}>
  864. {/* 广告信息 */}
  865. <Ad />
  866. {/* 定向 */}
  867. <Target />
  868. {/* 创意 */}
  869. <Dynamic
  870. creativeTemplateAppellation={creativeTemplateAppellation}
  871. creativeTemplateStyle={creativeTemplateStyle}
  872. />
  873. {/* 创意素材 */}
  874. <Material />
  875. </div>
  876. <div className={style.settingsBody_content_left}>
  877. {/* 创意文案 */}
  878. <MaterialText />
  879. {/* 落地页 */}
  880. <PageList />
  881. </div>
  882. </DispatchAddelivery.Provider>
  883. </div>
  884. </div>
  885. <Space className={style.bts} wrap>
  886. <Save addelivery={addelivery} />
  887. <Button type='primary' onClick={severBd}>存为预设</Button>
  888. <Popconfirm
  889. title="确定清空?"
  890. onConfirm={delBdPlan}
  891. >
  892. <Button>清空配置/预设</Button>
  893. </Popconfirm>
  894. <Button type='primary' onClick={preview}><SearchOutlined />预览广告</Button>
  895. </Space>
  896. {/* 选择小说 */}
  897. {goodsVisible && <GoodsModal
  898. marketingTargetType={marketingAssetOuterSpec?.marketingTargetType}
  899. visible={goodsVisible}
  900. data={accountCreateLogs}
  901. onClose={() => setGoodsVisible(false)}
  902. onChange={(e) => {
  903. setAccountCreateLogs(e);
  904. setGoodsVisible(false);
  905. clearData()
  906. }}
  907. />}
  908. {/* 选择数据源 */}
  909. {sourceVisible && <DataSourceModal
  910. visible={sourceVisible}
  911. data={accountCreateLogs}
  912. onClose={() => setSourceVisible(false)}
  913. onChange={(e) => {
  914. setAccountCreateLogs(e);
  915. setSourceVisible(false);
  916. clearData()
  917. }}
  918. />}
  919. {/* 选择公众号 */}
  920. {wechatVisible && <WechatAccount
  921. visible={wechatVisible}
  922. data={accountCreateLogs}
  923. onClose={() => setWechatVisible(false)}
  924. onChange={(e) => {
  925. setAccountCreateLogs(e);
  926. setWechatVisible(false);
  927. clearData()
  928. }}
  929. />}
  930. {/* 选择视频号 */}
  931. {channelsProfileVisible && <VideoChannel
  932. visible={channelsProfileVisible}
  933. data={accountCreateLogs}
  934. onClose={() => setChannelsProfileVisible(false)}
  935. onChange={(e) => {
  936. setAccountCreateLogs(e);
  937. setChannelsProfileVisible(false);
  938. clearData()
  939. }}
  940. />}
  941. {/* 转化归因 */}
  942. {conversionVisible && <ConversionSelect
  943. adgroups={addelivery.adgroups}
  944. visible={conversionVisible}
  945. data={accountCreateLogs}
  946. onClose={() => setConversionVisible(false)}
  947. onChange={(e) => {
  948. setAccountCreateLogs(e);
  949. setConversionVisible(false);
  950. clearData()
  951. }}
  952. />}
  953. </Card>
  954. </Spin>
  955. <Card
  956. className={style.createAd}
  957. >
  958. {activeKey && tableData && Object.keys(tableData)?.length > 0 ? <div className={style.cardBody}>
  959. <Tabs
  960. onChange={(e) => { setActiveKey(e) }}
  961. type="card"
  962. activeKey={activeKey}
  963. tabBarExtraContent={<Space>
  964. <span>广告总数:{adCount}</span>
  965. <span>创意总数:{dynamicCount}</span>
  966. <Button type='primary' onClick={() => {
  967. setSubVisible(true)
  968. }}>提交创建</Button>
  969. </Space>}
  970. >
  971. {accountCreateLogs.map(item => <Tabs.TabPane tab={item.accountId} key={item.accountId} />)}
  972. </Tabs>
  973. {addelivery?.dynamicCreativesTextDTOS?.type === 4 && <Title level={5} style={{ color: 'red', fontSize: 12 }}>因为选择的是“创意组和文案叉乘打乱后分配”模式,会随机打乱,当前预览广告下创意内容会与实际建出来的创意有偏差,请以建出来的为准</Title>}
  974. <div className={style.content} style={{ marginTop: 20 }}>
  975. <Table
  976. columns={columns()}
  977. dataSource={tableData[activeKey]}
  978. size="small"
  979. bordered
  980. scroll={{ x: 1200, y: 600 }}
  981. rowKey={'id'}
  982. pagination={{
  983. defaultPageSize: 50,
  984. total: tableData[activeKey]?.length || 0,
  985. showTotal: (total) => <Tag color="cyan">当前共{total}个创意,{tableData[activeKey]?.[0]?.adLength}个广告</Tag>,
  986. }}
  987. />
  988. </div>
  989. </div> : <div style={{ minHeight: 400, display: 'flex', justifyContent: 'center', alignItems: 'center' }}>
  990. <Empty description="请先完成模块配置后,再预览广告计划" />
  991. </div>}
  992. </Card>
  993. {/* 提交任务 */}
  994. {subVisible && <SubmitModal
  995. ajax={createAdgroupTask}
  996. visible={subVisible}
  997. onChange={(e) => {
  998. onSubmit(e)
  999. }}
  1000. onClose={() => {
  1001. setSubVisible(false)
  1002. }}
  1003. />}
  1004. </Space>
  1005. }
  1006. export default Create