addDynamic.tsx 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638
  1. import { Button, Card, Drawer, Empty, Modal, Popconfirm, Space, Spin, Table, Tabs, Typography, message } from "antd"
  2. import React, { useEffect, useState } from "react"
  3. import '../index.less'
  4. import style from './index.less'
  5. import Dynamic from "./Dynamic";
  6. import Material from "./Material";
  7. import MaterialText from "./MaterialText";
  8. import PageList from "./PageList";
  9. import { DispatchAddelivery } from ".";
  10. import { CheckOutlined, SearchOutlined } from "@ant-design/icons";
  11. import WechatAccount from "../../components/WechatAccount";
  12. import { cartesianProduct, distributeArray, splitArrayIntoRandomChunks } from "@/utils/utils";
  13. import { columnsAddDynamic } from "./tableConfig";
  14. import { useAjax } from "@/Hook/useAjax";
  15. import { createDynamicTaskApi } from "@/services/adqV3";
  16. import TacticsS from "./TacticsS";
  17. const { Text, Title } = Typography;
  18. /**
  19. * 新增创意
  20. * @returns
  21. */
  22. const AddDynamic: React.FC<PULLIN.NewAddDynamic> = ({ visible, onChange, onClose, adData: selectData, tactics }) => {
  23. /****************************************/
  24. const [addelivery, setAddelivery] = useState<PULLIN.AddeliveryProps>({ adgroups: {}, targeting: [], dynamic: {}, dynamicMaterialDTos: {}, dynamicCreativesTextDTOS: {}, mediaType: 0 })
  25. const { adgroups } = addelivery
  26. const [wechatVisible, setWechatVisible] = useState<boolean>(false) // 选择微信公众号弹窗控制
  27. const [materialData, setMaterialData] = useState<any>({}) // 素材数据
  28. const [textData, setTextData] = useState<any>({})
  29. const [accountCreateLogs, setAccountCreateLogs] = useState<PULLIN.AccountCreateLogsProps[]>([]) // 账户
  30. const [tableData, setTableData] = useState<any>({})
  31. const [activeKey, setActiveKey] = useState<string>()
  32. const [dynamicCount, setDynamicCount] = useState<number>(0)
  33. const [adData, setAdData] = useState<any[]>(selectData)
  34. const [adDataGroup, setAdDataGroup] = useState<{ [x: number]: any[] }>({})
  35. const createDynamicTask = useAjax((params) => createDynamicTaskApi(params))
  36. /****************************************/
  37. useEffect(() => {
  38. if (adData && adData.length) {
  39. let adDataGroup: { [x: number]: any[] } = {}
  40. adData.forEach(item => {
  41. let accountId = item.accountId
  42. if (adDataGroup?.[accountId]?.length) {
  43. adDataGroup[accountId].push(item)
  44. } else {
  45. adDataGroup[accountId] = [item]
  46. }
  47. })
  48. setAdDataGroup(adDataGroup)
  49. }
  50. }, [adData])
  51. useEffect(() => {
  52. if (tactics) {
  53. const {
  54. adData,
  55. addelivery,
  56. accountCreateLogs,
  57. materialData,
  58. textData
  59. } = JSON.parse(tactics.strategyValue)
  60. setAccountCreateLogs(accountCreateLogs)
  61. setAddelivery(addelivery)
  62. setAdData(adData)
  63. setMaterialData(materialData)
  64. setTextData(textData)
  65. } else if (selectData?.length > 0) {
  66. const { siteSet, marketingCarrierType, marketingGoal, marketingTargetType, sceneSpec, automaticSiteEnabled } = selectData[0]
  67. setAddelivery({ ...addelivery, adgroups: { marketingGoal, marketingCarrierType, siteSet, automaticSiteEnabled, sceneSpec, marketingAssetOuterSpec: { marketingTargetType } } })
  68. let AccountSet = new Set(selectData.map(item => item.accountId))
  69. setAccountCreateLogs([...AccountSet].map(accountId => ({ accountId })))
  70. }
  71. }, [selectData, tactics])
  72. const clearData = () => {
  73. setTableData([])
  74. }
  75. // 预览
  76. const preview = () => {
  77. if (accountCreateLogs?.length === 0) {
  78. message.error('请先选择媒体账户')
  79. return
  80. }
  81. const { adgroups, dynamic, dynamicMaterialDTos, dynamicCreativesTextDTOS, mediaType } = addelivery
  82. if (!(adgroups && Object.keys(adgroups).length)) {
  83. message.error('请先配置广告信息')
  84. return
  85. }
  86. if ((['MARKETING_TARGET_TYPE_WECHAT_OFFICIAL_ACCOUNT'].includes(adgroups?.marketingAssetOuterSpec?.marketingTargetType) || adgroups?.marketingCarrierType === 'MARKETING_CARRIER_TYPE_WECHAT_OFFICIAL_ACCOUNT') && !accountCreateLogs?.some(item => item?.wechatChannelList?.length)) {
  87. message.error('请先选择公众号')
  88. return
  89. }
  90. if (!(dynamic && Object.keys(dynamic).length)) {
  91. message.error('请先配置创意')
  92. return
  93. }
  94. if ((materialData && Object.keys(materialData).length) && !(dynamicMaterialDTos && Object.keys(dynamicMaterialDTos).length)) {
  95. message.error('请先配置创意素材')
  96. return
  97. }
  98. if ((textData && Object.keys(textData).length) && !(dynamicCreativesTextDTOS && Object.keys(dynamicCreativesTextDTOS).length)) {
  99. message.error('请先配置创意文案')
  100. return
  101. }
  102. if (!accountCreateLogs?.some(item => item?.pageList?.length)) {
  103. message.error('请先选择落地页')
  104. return
  105. }
  106. let newTableData: any = {}, newDynamicCount = 0
  107. let textType = dynamicCreativesTextDTOS.type
  108. let textDto = dynamicCreativesTextDTOS?.dynamicCreativesTextDetailDTOList || []
  109. let textDtoLenth = textDto.length
  110. let dynamicGroupLength = dynamicMaterialDTos?.dynamicGroup?.length || 0
  111. let newDynamicGroup: any = []
  112. if (![910].includes(dynamic.creativeTemplateId)) {
  113. newDynamicGroup = dynamicMaterialDTos?.dynamicGroup || []
  114. if (newDynamicGroup.length > 0 && [0, 1, 2, 3, 4].includes(textType)) {
  115. if (textType === 0) {
  116. newDynamicGroup = newDynamicGroup.map((item: any) => ({ ...item, textDto: textDto?.[0] }))
  117. } else if (textType === 1) {
  118. newDynamicGroup = newDynamicGroup.map((item: any, index: number) => ({ ...item, textDto: textDto?.[index] }))
  119. } else if (textType === 2) {
  120. newDynamicGroup = newDynamicGroup.map((item: any, index: number) => ({ ...item, textDto: textDto?.[index % textDtoLenth] }))
  121. } else if ((textType === 3 && mediaType === 0) || (textType === 4 && mediaType === 1)) {
  122. newDynamicGroup = cartesianProduct(newDynamicGroup, textDto || [{}]).map((item) => {
  123. let [dynamicGroup, textDtoData] = item
  124. return {
  125. ...dynamicGroup as any,
  126. textDto: textDtoData
  127. }
  128. })
  129. }
  130. }
  131. }
  132. // 创意组平均分配到广告逻辑
  133. let averageAdDynamicList: any[] = []
  134. if ((mediaType === 1 || mediaType === 2) && newDynamicGroup.length) {
  135. let adLength = adData.length
  136. if (mediaType === 1) {
  137. if (textType === 4) {
  138. if (adLength > newDynamicGroup.length) {
  139. message.error(`创意组分配规则选择“平均分配到广告”时,创意组总数必须大于等于广告总数。当前创意组数量:${dynamicGroupLength},广告数量:${adLength}`)
  140. return
  141. }
  142. averageAdDynamicList = splitArrayIntoRandomChunks(newDynamicGroup, adLength)
  143. } else {
  144. if (adLength > dynamicGroupLength) {
  145. message.error(`创意组分配规则选择“平均分配到广告”时,创意组总数必须大于等于广告总数。当前创意组数量:${dynamicGroupLength},广告数量:${adLength}`)
  146. return
  147. }
  148. averageAdDynamicList = distributeArray(newDynamicGroup, adLength)
  149. }
  150. } else if (mediaType === 2) {
  151. if (adLength < dynamicGroupLength) {
  152. message.error(`创意组分配规则选择“顺序分配到广告”时,创意组总数必须小于等于广告总数。当前创意组数量:${dynamicGroupLength},广告数量:${adLength}`)
  153. return
  154. }
  155. }
  156. }
  157. // 落地页平均分配判断数量
  158. if ([910].includes(dynamic.creativeTemplateId) && dynamic?.landingPageType === 1) {
  159. if (accountCreateLogs.some(item => {
  160. let total = adDataGroup[item.accountId].length
  161. let pageLength = item.pageList.length
  162. if (total > pageLength) {
  163. message.error(`当前${item.accountId}下的广告总数(${total})大于落地页总数(${pageLength}),平均分配需要落地页总数大于广告总数`)
  164. return true
  165. }
  166. return false
  167. })) {
  168. return
  169. }
  170. }
  171. if (textType === 1) {
  172. if (dynamicGroupLength !== textDtoLenth) {
  173. message.error(`当前创意文案是“创意组一一对应”模式,创意组总数(${dynamicGroupLength})要等于创意文案总数(${textDtoLenth})`)
  174. return
  175. }
  176. if (!dynamicCreativesTextDTOS.dynamicCreativesTextDetailDTOList.every((item: {}) => item && Object.keys(item).length)) {
  177. message.error('创意文案配置错误,内容空')
  178. return
  179. }
  180. }
  181. let accountIndex1 = 0
  182. if (dynamic?.landingPageType === 1 && [910].includes(dynamic.creativeTemplateId)) {
  183. accountCreateLogs.forEach(item => {
  184. let adData = adDataGroup[item.accountId]
  185. let averageAdPageList: any[] = distributeArray(item.pageList, adData.length)
  186. let newData: any[] = []
  187. adData.forEach((ad, index) => {
  188. let data = [{
  189. id: ad.adgroupId + '_' + index,
  190. adgroupsDto: ad,
  191. dynamicDto: dynamic, // 创意信息
  192. }]
  193. newData = cartesianProduct(data, averageAdPageList[index]).map((item, index) => {
  194. let [d1, pageList, num] = item
  195. return {
  196. ...d1,
  197. id: d1.id + '_' + index,
  198. pageListDto: [pageList],
  199. dynamicDto: {
  200. ...d1.dynamicDto,
  201. dynamicCreativeName: d1.dynamicDto.dynamicCreativeName + num
  202. },
  203. rowSpan: index === 0 ? averageAdPageList[index].length : 0,
  204. isRowSpan: true
  205. }
  206. })
  207. newTableData[ad.adgroupId] = newData
  208. })
  209. newDynamicCount += item.pageList.length
  210. })
  211. } else {
  212. adData.forEach((ad, index) => {
  213. let item = accountCreateLogs.find(a => a.accountId === ad.accountId) as PULLIN.AccountCreateLogsProps
  214. let averageAdDynamic = averageAdDynamicList?.[index]
  215. let data = [{
  216. id: ad.adgroupId + '_' + index,
  217. pageListDto: item.pageList, // 落地页
  218. adgroupsDto: ad,
  219. dynamicDto: dynamic, // 创意信息
  220. averageAdDynamic,
  221. rowSpan: (mediaType === 1 && textType !== 4) ? averageAdDynamic.length : ([910].includes(dynamic.creativeTemplateId) ? item.pageList?.length : (textType === 3 ? textDtoLenth * dynamicGroupLength : dynamicGroupLength)) || 1
  222. }]
  223. let newData: any[] = []
  224. if ([910].includes(dynamic.creativeTemplateId)) {
  225. newData = cartesianProduct(data, item.pageList).map((item, index) => {
  226. let [d1, pageList, num] = item
  227. return {
  228. ...d1,
  229. id: d1.id + '_' + index,
  230. pageListDto: [pageList],
  231. dynamicDto: {
  232. ...d1.dynamicDto,
  233. dynamicCreativeName: d1.dynamicDto.dynamicCreativeName + num
  234. }
  235. }
  236. })
  237. } else {
  238. if (mediaType === 1) {
  239. data.forEach(item => {
  240. const { averageAdDynamic, ...ad } = item
  241. if (textType === 3) {
  242. let rowSpan = textDtoLenth * averageAdDynamic.length
  243. cartesianProduct(textDto, averageAdDynamic).forEach((taad: any, index) => {
  244. let [textValue, aad] = taad
  245. newData.push({
  246. ...ad,
  247. id: ad.id + '_' + index,
  248. dynamicGroup: aad,
  249. textDto: textValue,
  250. rowSpan
  251. })
  252. })
  253. } else if (textType === 4) {
  254. averageAdDynamic.forEach((aad: any, index: number) => {
  255. newData.push({
  256. ...ad,
  257. id: ad.id + '_' + index,
  258. dynamicGroup: aad,
  259. textDto: aad?.textDto,
  260. rowSpan: index === 0 ? averageAdDynamic.length : 0,
  261. isRowSpan: true
  262. })
  263. })
  264. } else {
  265. averageAdDynamic.forEach((aad: any, index: number) => {
  266. newData.push({
  267. ...ad,
  268. id: ad.id + '_' + index,
  269. dynamicGroup: aad,
  270. textDto: aad?.textDto
  271. })
  272. })
  273. }
  274. })
  275. } else if (mediaType === 2) {
  276. data.forEach((item) => {
  277. const { averageAdDynamic, ...ad } = item
  278. if (textType === 3) {
  279. cartesianProduct(textDto, [newDynamicGroup[accountIndex1 % newDynamicGroup.length]]).forEach((taad: any) => {
  280. let [textValue, aad, index] = taad
  281. newData.push({
  282. ...ad,
  283. id: ad.id + '_' + index,
  284. dynamicGroup: aad,
  285. textDto: textValue,
  286. rowSpan: textDto.length
  287. })
  288. })
  289. } else {
  290. let { textDto, ...dynamicGroup } = newDynamicGroup[accountIndex1 % newDynamicGroup.length]
  291. newData.push({
  292. ...ad,
  293. dynamicGroup,
  294. textDto,
  295. rowSpan: 1
  296. })
  297. }
  298. accountIndex1 += 1
  299. })
  300. } else {
  301. newData = cartesianProduct(data, newDynamicGroup.length > 0 ? newDynamicGroup : [{}]).map((item, index) => {
  302. let [d1, group] = item
  303. return {
  304. ...d1,
  305. id: d1.id + '_' + index,
  306. dynamicGroup: group,
  307. textDto: (group as any)?.textDto
  308. }
  309. })
  310. }
  311. }
  312. newDynamicCount += newData.length
  313. newTableData[ad.adgroupId] = newData
  314. })
  315. }
  316. setDynamicCount(newDynamicCount)
  317. setActiveKey(adData?.[0].adgroupId?.toString())
  318. console.log('newTableData-->', newTableData)
  319. setTableData(newTableData)
  320. }
  321. // 提交
  322. const onSubmit = () => {
  323. const { dynamic, dynamicMaterialDTos, dynamicCreativesTextDTOS, mediaType } = addelivery
  324. let dynamicMaterialDTOS = []
  325. if (dynamic.deliveryMode === 'DELIVERY_MODE_CUSTOMIZE') {
  326. if ((materialData && Object.keys(materialData).length && dynamicMaterialDTos && Object.keys(dynamicMaterialDTos).length)) {
  327. let mType = Object.keys(materialData)[0];
  328. dynamicMaterialDTOS = dynamicMaterialDTos.dynamicGroup?.map((item: any) => {
  329. if (mType === 'image') {
  330. return [{
  331. type: mType,
  332. valueJson: JSON.stringify({
  333. value: {
  334. imageUrl: item?.image_id?.url,
  335. imageId: item?.image_id?.id,
  336. materialType: item?.image_id?.materialType
  337. }
  338. })
  339. }]
  340. } else if (mType === 'image_list' || mType === 'element_story') {
  341. let key = 'image_list'
  342. if (mType === 'element_story') {
  343. key = 'element_story'
  344. }
  345. let list = item?.[key]?.map((l: any) => {
  346. return {
  347. imageUrl: l?.url,
  348. imageId: l?.id,
  349. materialType: l?.materialType
  350. }
  351. })
  352. return [{
  353. type: mType,
  354. valueJson: JSON.stringify({
  355. value: {
  356. list
  357. }
  358. })
  359. }]
  360. } else if (['short_video', 'video'].includes(mType)) {
  361. let value: any = {
  362. materialType: item?.video_id?.materialType || item?.short_video1?.materialType || 0,
  363. videoUrl: item?.video_id?.url || item?.short_video1?.url,
  364. videoId: item?.video_id?.id || item?.short_video1?.id
  365. }
  366. if (item?.cover_id?.url) {
  367. value.imageUrl = item?.cover_id?.url
  368. value.imageId = item?.cover_id?.id
  369. value.materialCoverType = item?.cover_id?.materialType
  370. }
  371. return [{
  372. type: mType,
  373. valueJson: JSON.stringify({
  374. value
  375. })
  376. }]
  377. }
  378. return [{
  379. type: mType,
  380. valueJson: ''
  381. }]
  382. })
  383. }
  384. } else {
  385. if (dynamicMaterialDTos && Object.keys(dynamicMaterialDTos).length) {
  386. dynamicMaterialDTOS = dynamicMaterialDTos.dynamicGroup?.map((item: { list: any[] }) => {
  387. return item.list.map(l => {
  388. if (Array.isArray(l)) {
  389. return {
  390. type: 'image_list',
  391. valueJson: JSON.stringify({
  392. value: {
  393. list: l?.map((i: any) => {
  394. return {
  395. imageUrl: i?.url,
  396. imageId: i?.id,
  397. materialType: i?.materialType
  398. }
  399. })
  400. }
  401. })
  402. }
  403. } else if (l?.url?.includes('mp4')) {
  404. return {
  405. type: 'video',
  406. valueJson: JSON.stringify({
  407. value: {
  408. materialType: l?.materialType,
  409. videoUrl: l?.url,
  410. videoId: l?.id
  411. }
  412. })
  413. }
  414. } else {
  415. return {
  416. type: 'image',
  417. valueJson: JSON.stringify({
  418. value: {
  419. imageUrl: l?.url,
  420. imageId: l?.id,
  421. materialType: l?.materialType
  422. }
  423. })
  424. }
  425. }
  426. })
  427. })
  428. }
  429. }
  430. let accountIdParamDTOMap: any = {}
  431. accountCreateLogs.forEach(item => {
  432. let { pageList, productList, userActionSetsList, accountId, wechatChannelList } = item
  433. let userActionSetsListDto = userActionSetsList?.map((item: any) => ({ id: item?.userActionSetId, type: item?.type })) // dataSourceId
  434. let map: any = {
  435. userActionSetsList: userActionSetsListDto,
  436. pageList: pageList?.map((item: { pageId: any }) => item.pageId)
  437. }
  438. if (productList) {
  439. map.productDTOS = productList?.map(item => {
  440. return { productId: item.marketingAssetId }
  441. })
  442. }
  443. if (wechatChannelList) {
  444. map.wechatChannelId = wechatChannelList?.[0]?.wechatOfficialAccountId
  445. }
  446. accountIdParamDTOMap[accountId] = map
  447. })
  448. let dynamicCreativesDTO = { ...dynamic, mediaType }
  449. if (dynamic.deliveryMode === 'DELIVERY_MODE_COMPONENT') {
  450. dynamicCreativesDTO.creativeTemplateId = 711
  451. }
  452. let params = {
  453. accountAdgroupMaps: adData.map(item => `${item.accountId},${item.adgroupId}`),
  454. dynamicCreativesDTO,
  455. dynamicCreativesTextDTOS,
  456. dynamicMaterialDTOS,
  457. accountIdParamDTOMap
  458. }
  459. createDynamicTask.run(params).then(res => {
  460. if (res) {
  461. Modal.success({
  462. content: '创建任务提交成功',
  463. bodyStyle: { fontWeight: 700 },
  464. okText: '返回上一页',
  465. closable: true,
  466. onOk: () => {
  467. onChange?.()
  468. },
  469. onCancel: () => {}
  470. })
  471. }
  472. })
  473. }
  474. return <Drawer
  475. title={<strong>添加创意</strong>}
  476. visible={visible}
  477. width={1500}
  478. onClose={onClose}
  479. bodyStyle={{ backgroundColor: '#f1f4fc', padding: '0 10px 10px' }}
  480. >
  481. <Space direction="vertical" style={{ width: '100%' }}>
  482. <Spin spinning={false}>
  483. <Card
  484. size="small"
  485. title={<div className={style.cardTitle}>配置区</div>}
  486. className={style.createAd}
  487. >
  488. <Space wrap>
  489. {(adgroups?.marketingAssetOuterSpec?.marketingTargetType === 'MARKETING_TARGET_TYPE_WECHAT_OFFICIAL_ACCOUNT' || adgroups?.marketingCarrierType === 'MARKETING_CARRIER_TYPE_WECHAT_OFFICIAL_ACCOUNT' || addelivery?.dynamic?.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>}
  490. </Space>
  491. <div className={style.settingsBody}>
  492. <div className={style.settingsBody_content}>
  493. <DispatchAddelivery.Provider
  494. value={{
  495. addelivery,
  496. setAddelivery,
  497. accountCreateLogs,
  498. setAccountCreateLogs,
  499. materialData,
  500. setMaterialData,
  501. textData,
  502. setTextData,
  503. clearData
  504. }}>
  505. <div className={style.settingsBody_content_right}>
  506. <div className={`${style.settingsBody_content_row} ${style.row1}`}>
  507. <div className={style.title}>
  508. <span>广告信息</span>
  509. </div>
  510. <div className={style.detail}>
  511. <div className={style.detail_body}>
  512. <Title level={5} style={{ fontSize: 12 }}>已选广告</Title>
  513. {Object.keys(adDataGroup).map((key: any) => {
  514. return <div key={key}>
  515. <Title level={5} style={{ fontSize: 12 }}>{key}</Title>
  516. {adDataGroup[key]?.map((item: any) => {
  517. return <div key={item.adgroupId}>
  518. <div className={style.text}><Text ellipsis={{ tooltip: true }}>{item.adgroupName}</Text></div>
  519. </div>
  520. })}
  521. </div>
  522. })}
  523. </div>
  524. </div>
  525. </div>
  526. {/* 创意 */}
  527. <Dynamic />
  528. {/* 创意素材 */}
  529. <Material adData={adData} />
  530. </div>
  531. <div className={style.settingsBody_content_left}>
  532. {/* 创意文案 */}
  533. <MaterialText />
  534. {/* 落地页 */}
  535. <PageList adDataGroup={adDataGroup} />
  536. </div>
  537. </DispatchAddelivery.Provider>
  538. </div>
  539. </div>
  540. <Space className={style.bts} wrap>
  541. <TacticsS strategyValue={{
  542. adData: adData.map(item => {
  543. const { accountId, adgroupName, adgroupId, siteSet, marketingCarrierType, marketingGoal, marketingTargetType, sceneSpec, automaticSiteEnabled } = item
  544. return {
  545. siteSet, marketingCarrierType, marketingGoal, marketingTargetType, sceneSpec, automaticSiteEnabled,
  546. accountId,
  547. adgroupId,
  548. adgroupName
  549. }
  550. }),
  551. addelivery,
  552. accountCreateLogs,
  553. materialData,
  554. textData
  555. }} />
  556. <Button type='primary' onClick={preview}><SearchOutlined />预览广告</Button>
  557. </Space>
  558. {/* 选择公众号 */}
  559. {wechatVisible && <WechatAccount
  560. visible={wechatVisible}
  561. data={accountCreateLogs}
  562. onClose={() => setWechatVisible(false)}
  563. onChange={(e) => {
  564. setAccountCreateLogs(e);
  565. setWechatVisible(false);
  566. clearData()
  567. }}
  568. />}
  569. </Card>
  570. </Spin>
  571. <Card
  572. className={style.createAd}
  573. >
  574. {activeKey && tableData && Object.keys(tableData)?.length > 0 ? <div className={style.cardBody}>
  575. <Tabs
  576. onChange={(e) => { setActiveKey(e) }}
  577. type="card"
  578. activeKey={activeKey}
  579. tabBarExtraContent={<Space>
  580. <span>创意总数:{dynamicCount}</span>
  581. <Popconfirm
  582. title="确定提交?"
  583. onConfirm={onSubmit}
  584. >
  585. <Button type='primary' loading={createDynamicTask.loading}>提交创建</Button>
  586. </Popconfirm>
  587. </Space>}
  588. >
  589. {adData.map(item => <Tabs.TabPane tab={item.adgroupId} key={item.adgroupId} />)}
  590. </Tabs>
  591. {addelivery?.dynamicCreativesTextDTOS?.type === 4 && <Title level={5} style={{ color: 'red', fontSize: 12 }}>因为选择的是“创意组和文案叉乘打乱后分配”模式,会随机打乱,当前预览广告下创意内容会与实际建出来的创意有偏差,请以建出来的为准</Title>}
  592. <div className={style.content} style={{ marginTop: 20 }}>
  593. <Table
  594. columns={columnsAddDynamic()}
  595. dataSource={tableData[activeKey]}
  596. size="small"
  597. bordered
  598. scroll={{ x: 1200 }}
  599. rowKey={'id'}
  600. pagination={{
  601. defaultPageSize: 50
  602. }}
  603. />
  604. </div>
  605. </div> : <div style={{ minHeight: 400, display: 'flex', justifyContent: 'center', alignItems: 'center' }}>
  606. <Empty description="请先完成模块配置后,再预览广告计划" />
  607. </div>}
  608. </Card>
  609. </Space>
  610. </Drawer>
  611. }
  612. export default React.memo(AddDynamic)