index.tsx 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759
  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, randomString } 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. export const DispatchAddelivery = React.createContext<PULLIN.DispatchAddelivery | null>(null);
  25. /**
  26. * 创建广告
  27. * @returns
  28. */
  29. const Create: React.FC = () => {
  30. /*******************************************/
  31. const { getAllUserAccount } = useModel('useLaunchAdq.useAdAuthorize')
  32. const { initTargeting } = useModel('useLaunchV3.useTargeting')
  33. const [addelivery, setAddelivery] = useState<PULLIN.AddeliveryProps>({ adgroups: {}, targeting: [], dynamic: {}, dynamicMaterialDTos: {}, dynamicCreativesTextDTOS: {}, mediaType: 0 })
  34. const { marketingAssetOuterSpec, marketingCarrierType } = addelivery.adgroups
  35. const [accSearch, setAccSearch] = useState<string>()
  36. const [accountCreateLogs, setAccountCreateLogs] = useState<PULLIN.AccountCreateLogsProps[]>([]) // 账户
  37. const [goodsVisible, setGoodsVisible] = useState<boolean>(false) // 选择小说弹窗控制
  38. const [wechatVisible, setWechatVisible] = useState<boolean>(false) // 选择微信公众号弹窗控制
  39. const [sourceVisible, setSourceVisible] = useState<boolean>(false) // 选择数据源弹窗控制
  40. const [materialData, setMaterialData] = useState<any>({}) // 素材数据
  41. const [textData, setTextData] = useState<any>({})
  42. const [tableData, setTableData] = useState<any>({})
  43. const [activeKey, setActiveKey] = useState<string>()
  44. const [subVisible, setSubVisible] = useState<boolean>(false) // 选择设置名称弹窗控制
  45. const [adCount, setAdCount] = useState<number>(0)
  46. const [dynamicCount, setDynamicCount] = useState<number>(0)
  47. const getGroupList = useAjax(() => getGroupListApi())
  48. const createAdgroupTask = useAjax((params) => createAdgroupTaskApi(params))
  49. const getSelectTaskDetail = useAjax((params) => getSelectTaskDetailApi(params))
  50. /*******************************************/
  51. useEffect(() => {
  52. console.log('addelivery---->', addelivery)
  53. // 获取账户组
  54. getGroupList.run()
  55. // 获取账户列表
  56. getAllUserAccount.run()
  57. initTargeting()
  58. }, [])
  59. /** 获取分组里账号 */
  60. const getGroupAccountList = (ids: number[]) => {
  61. if (ids.length > 0) {
  62. let data = ids.map(id => getAccountListApi(id))
  63. Promise.all(data).then(res => {
  64. if (res?.length > 0 && res.every((item: { code: number }) => item.code === 200)) {
  65. let userArr: any[] = []
  66. res.forEach((item: { data: { adAccountList: { accountId: number, id: number }[] } }) => {
  67. item.data.adAccountList.forEach(acc => {
  68. let obj = userArr.find((item: { accountId: number }) => item.accountId === acc.accountId)
  69. if (!obj) {
  70. userArr.push(acc)
  71. }
  72. })
  73. })
  74. setAccountCreateLogs(userArr?.map((item) => ({ accountId: item?.accountId })))
  75. clearData()
  76. setAddelivery({ adgroups: {}, targeting: [], dynamic: {}, dynamicMaterialDTos: {}, dynamicCreativesTextDTOS: {}, mediaType: 0 })
  77. } else {
  78. message.error('操作异常')
  79. }
  80. })
  81. } else {
  82. setAccountCreateLogs([])
  83. }
  84. }
  85. /** 存为预设 */
  86. const severBd = () => {
  87. // queryForm accountCreateLogs
  88. localStorage.setItem('ADQADV3', JSON.stringify({
  89. addelivery,
  90. accountCreateLogs,
  91. materialData,
  92. textData
  93. }))
  94. message.success('存储成功')
  95. }
  96. /** 清除 */
  97. const delBdPlan = () => {
  98. localStorage.removeItem('ADQADV3')
  99. setAccountCreateLogs([])
  100. setMaterialData({})
  101. setTextData({})
  102. setAddelivery({
  103. adgroups: {},
  104. targeting: [],
  105. dynamic: {},
  106. dynamicMaterialDTos: {},
  107. dynamicCreativesTextDTOS: {},
  108. mediaType: 0
  109. })
  110. setTableData({})
  111. }
  112. /**数据回填 */
  113. useEffect(() => {
  114. let taskId = sessionStorage.getItem('TASKID3.0')
  115. let adqAdData = localStorage.getItem('ADQADV3')
  116. if (taskId) {
  117. getSelectTaskDetail.run(taskId).then(res => {
  118. console.log(res)
  119. if (res) {
  120. const { adgroupDTO, accountIdParamVOMap, targetings, dynamicCreativesDTO: { mediaType, ...dynamic }, dynamicCreativesTextDTO, dynamicMaterialDTOS } = res
  121. let beginDate = adgroupDTO.beginDate
  122. let endDate = adgroupDTO.endDate
  123. if (beginDate && moment(beginDate) < moment()) {
  124. beginDate = moment().format('YYYY-MM-DD')
  125. endDate = moment().add(7, 'day').format('YYYY-MM-DD')
  126. message.warning('请注意,检测投放开始日期小于今天,已自动改成今天,如需修改,请重新设置')
  127. }
  128. let dynamicGroup: any[] = []
  129. if (dynamic.deliveryMode === 'DELIVERY_MODE_CUSTOMIZE') {
  130. dynamicGroup = dynamicMaterialDTOS?.map((item: any[]) => {
  131. let { type, valueJson } = item[0]
  132. let value = JSON.parse(valueJson).value
  133. if (type === 'image') {
  134. return { image_id: { id: value.imageId, url: value.imageUrl, materialType: value.materialType } }
  135. } else if (type === 'image_list' || type === 'element_story') {
  136. return { [type]: value.list.map((l: { imageUrl: any; imageId: any; materialType: any }) => ({ url: l.imageUrl, id: l.imageId, materialType: l.materialType })) }
  137. } else if (type === 'short_video' || type === 'video') {
  138. let field = type === 'video' ? 'video_id' : 'short_video1'
  139. let videoData: any = {}
  140. videoData[field] = { materialType: value.materialType, url: value.videoUrl, id: value.videoId }
  141. if (value.imageUrl) {
  142. videoData['cover_id'] = { materialCoverType: value.materialType, url: value.imageUrl, id: value.iamgeId }
  143. }
  144. return videoData
  145. } else {
  146. return {}
  147. }
  148. })
  149. }
  150. setAddelivery({
  151. adgroups: { ...adgroupDTO, adgroupName: adgroupDTO.adgroupName + '_副本' + randomString(true, 3, 5), endDate, beginDate },
  152. targeting: targetings.map((item: any) => {
  153. const { targetingName, ...targeting } = item
  154. return { targetingName, targeting }
  155. }),
  156. dynamic,
  157. dynamicMaterialDTos: dynamicGroup.length > 0 ? { dynamicGroup } : {},
  158. dynamicCreativesTextDTOS: dynamicCreativesTextDTO,
  159. mediaType: mediaType || 0
  160. })
  161. setAccountCreateLogs(Object.keys(accountIdParamVOMap || {}).map(accountId => {
  162. const { productDTOS, wechatOfficialAccountsVO, pageList, userActionSetsList } = accountIdParamVOMap[accountId]
  163. let data: PULLIN.AccountCreateLogsProps = {
  164. accountId: Number(accountId),
  165. productList: productDTOS
  166. }
  167. if (wechatOfficialAccountsVO) {
  168. data.wechatChannelList = [wechatOfficialAccountsVO]
  169. }
  170. if (pageList) {
  171. data.pageList = pageList
  172. }
  173. if (userActionSetsList) {
  174. data.userActionSetsList = userActionSetsList
  175. }
  176. return data
  177. }))
  178. sessionStorage.removeItem('TASKID3.0')
  179. }
  180. })
  181. } else if (adqAdData) {
  182. const { addelivery, accountCreateLogs, materialData, textData } = JSON.parse(adqAdData)
  183. if (addelivery?.adgroups) {
  184. if (addelivery?.adgroups?.beginDate && moment(addelivery?.adgroups?.beginDate) < moment()) {
  185. addelivery.adgroups.beginDate = moment().format('YYYY-MM-DD')
  186. message.warning('请注意,检测投放开始日期小于今天,已自动改成今天,如需修改,请重新设置')
  187. }
  188. if (addelivery?.adgroups?.endDate && moment(addelivery?.adgroups?.endDate) < moment()) {
  189. addelivery.adgroups.endDate = moment().format('YYYY-MM-DD')
  190. message.warning('请注意,检测投放结束日期小于今天,已自动改成今天,如需修改,请重新设置')
  191. }
  192. }
  193. setAddelivery({ ...addelivery })
  194. setAccountCreateLogs(accountCreateLogs)
  195. setMaterialData(materialData)
  196. setTextData(textData)
  197. }
  198. }, [])
  199. const preview = () => {
  200. console.log('addelivery------>', addelivery)
  201. console.log('accountCreateLogs------>', accountCreateLogs)
  202. if (accountCreateLogs?.length === 0) {
  203. message.error('请先选择媒体账户')
  204. return
  205. }
  206. const { adgroups, targeting, dynamic, dynamicMaterialDTos, dynamicCreativesTextDTOS, mediaType } = addelivery
  207. if (!(adgroups && Object.keys(adgroups).length)) {
  208. message.error('请先配置广告信息')
  209. return
  210. }
  211. if (['MARKETING_TARGET_TYPE_FICTION'].includes(marketingAssetOuterSpec?.marketingTargetType) && !accountCreateLogs?.some(item => item?.productList?.length)) {
  212. message.error('请先选择小说')
  213. return
  214. }
  215. if ((['MARKETING_TARGET_TYPE_WECHAT_OFFICIAL_ACCOUNT'].includes(marketingAssetOuterSpec?.marketingTargetType) || marketingCarrierType === 'MARKETING_CARRIER_TYPE_WECHAT_OFFICIAL_ACCOUNT') && !accountCreateLogs?.some(item => item?.wechatChannelList?.length)) {
  216. message.error('请先选择公众号')
  217. return
  218. }
  219. if (!(targeting?.length)) {
  220. message.error('请先添加定向')
  221. return
  222. }
  223. if (!(dynamic && Object.keys(dynamic).length)) {
  224. message.error('请先配置创意')
  225. return
  226. }
  227. if ((materialData && Object.keys(materialData).length) && !(dynamicMaterialDTos && Object.keys(dynamicMaterialDTos).length)) {
  228. message.error('请先配置创意素材')
  229. return
  230. }
  231. if ((textData && Object.keys(textData).length) && !(dynamicCreativesTextDTOS && Object.keys(dynamicCreativesTextDTOS).length)) {
  232. message.error('请先配置创意文案')
  233. return
  234. }
  235. if (!accountCreateLogs?.some(item => item?.pageList?.length)) {
  236. message.error('请先选择落地页')
  237. return
  238. }
  239. let newTableData: any = {}
  240. let newAdCount = 0, newdynamicCount = 0
  241. let textType = dynamicCreativesTextDTOS.type
  242. let textDto = dynamicCreativesTextDTOS?.dynamicCreativesTextDetailDTOList || []
  243. let textDtoLenth = textDto.length
  244. let dynamicGroupLength = dynamicMaterialDTos?.dynamicGroup?.length || 0
  245. let newDynamicGroup: any = []
  246. if (![910].includes(dynamic.creativeTemplateId)) {
  247. newDynamicGroup = dynamicMaterialDTos?.dynamicGroup || []
  248. if (newDynamicGroup.length > 0 && [0, 1, 2, 3].includes(textType)) {
  249. if (textType === 0) {
  250. newDynamicGroup = newDynamicGroup.map((item: any) => ({ ...item, textDto: textDto?.[0] }))
  251. } else if (textType === 1) {
  252. newDynamicGroup = newDynamicGroup.map((item: any, index: number) => ({ ...item, textDto: textDto?.[index] }))
  253. } else if (textType === 2) {
  254. newDynamicGroup = newDynamicGroup.map((item: any, index: number) => ({ ...item, textDto: textDto?.[index % textDtoLenth] }))
  255. } else if (textType === 3) {
  256. if (mediaType === 0) {
  257. newDynamicGroup = cartesianProduct(newDynamicGroup, textDto || [{}]).map((item) => {
  258. let [dynamicGroup, textDtoData] = item
  259. return {
  260. ...dynamicGroup as any,
  261. textDto: textDtoData
  262. }
  263. })
  264. }
  265. }
  266. }
  267. }
  268. // 创意组平均分配到广告逻辑
  269. let averageAdDynamicList: any[] = []
  270. if (mediaType === 1 && newDynamicGroup.length) {
  271. let adLength = 0
  272. let isReturn = false
  273. accountCreateLogs.forEach(item => {
  274. let productList: any[] = []
  275. if (['MARKETING_TARGET_TYPE_FICTION'].includes(marketingAssetOuterSpec?.marketingTargetType)) { // 小说
  276. productList = item?.productList || []
  277. } else if (['MARKETING_TARGET_TYPE_WECHAT_OFFICIAL_ACCOUNT'].includes(marketingAssetOuterSpec?.marketingTargetType)) { // 公众号
  278. productList = item?.wechatChannelList || []
  279. }
  280. adLength += productList.length * targeting.length
  281. if (adLength > dynamicGroupLength) {
  282. isReturn = true
  283. }
  284. averageAdDynamicList = distributeArray(newDynamicGroup, adLength)
  285. })
  286. if (isReturn) {
  287. message.error(`创意组分配规则选择创意组平均分配到广告时,创意组总数必须大于等于广告总数。当前创意组数量:${dynamicGroupLength},广告数量:${adLength}`)
  288. return
  289. }
  290. }
  291. let accountIndex = 0
  292. accountCreateLogs.forEach(item => {
  293. let productList: any[] = []
  294. if (['MARKETING_TARGET_TYPE_FICTION'].includes(marketingAssetOuterSpec?.marketingTargetType)) { // 小说
  295. productList = item?.productList || []
  296. } else if (['MARKETING_TARGET_TYPE_WECHAT_OFFICIAL_ACCOUNT'].includes(marketingAssetOuterSpec?.marketingTargetType)) { // 公众号
  297. productList = item?.wechatChannelList || []
  298. }
  299. let data = cartesianProduct(productList, targeting).map(newD => {
  300. let [productDto, targetDto, index] = newD
  301. let suffix = '_' + item.accountId + '_' + index
  302. let averageAdDynamic = averageAdDynamicList?.[accountIndex]
  303. let dat: any = {
  304. id: item.accountId + '_' + index,
  305. accountId: item.accountId, // 账户
  306. userActionSetsList: item.userActionSetsList, // 数据源
  307. pageListDto: item.pageList, // 落地页
  308. productDto, // 商品
  309. targetDto: { // 定向
  310. ...targetDto,
  311. targetingName: targetDto.targetingName + suffix
  312. },
  313. adgroupsDto: { // 广告信息
  314. ...adgroups,
  315. adgroupName: adgroups.adgroupName + suffix
  316. },
  317. dynamicDto: dynamic, // 创意信息
  318. averageAdDynamic,
  319. rowSpan: mediaType === 1 ? averageAdDynamic.length : ([910].includes(dynamic.creativeTemplateId) ? item.pageList?.length : (textType === 3 ? textDtoLenth * dynamicGroupLength : dynamicGroupLength)) || 1
  320. }
  321. if (marketingCarrierType === 'MARKETING_CARRIER_TYPE_WECHAT_OFFICIAL_ACCOUNT') { // 营销载体
  322. dat.marketingCarrierDto = item?.wechatChannelList
  323. }
  324. accountIndex += 1
  325. return dat
  326. })
  327. newAdCount += data.length
  328. let newData: any[] = []
  329. if ([910].includes(dynamic.creativeTemplateId)) {
  330. newData = cartesianProduct(data, item.pageList).map((item, index) => {
  331. let [d1, pageList, num] = item
  332. return {
  333. ...d1,
  334. id: d1.id + '_' + index,
  335. pageListDto: [pageList],
  336. dynamicDto: {
  337. ...d1.dynamicDto,
  338. dynamicCreativeName: d1.dynamicDto.dynamicCreativeName + num
  339. }
  340. }
  341. })
  342. } else {
  343. if (mediaType === 1) {
  344. data.forEach(item => {
  345. const { averageAdDynamic, ...ad } = item
  346. if (textType === 3) {
  347. let rowSpan = textDtoLenth * averageAdDynamic.length
  348. cartesianProduct(textDto, averageAdDynamic).forEach((taad: any, index) => {
  349. let [textValue, aad] = taad
  350. newData.push({
  351. ...ad,
  352. id: ad.id + '_' + index,
  353. dynamicGroup: aad,
  354. textDto: textValue,
  355. rowSpan
  356. })
  357. })
  358. } else {
  359. averageAdDynamic.forEach((aad: any, index: number) => {
  360. newData.push({
  361. ...ad,
  362. id: ad.id + '_' + index,
  363. dynamicGroup: aad,
  364. textDto: aad?.textDto
  365. })
  366. })
  367. }
  368. })
  369. } else {
  370. newData = cartesianProduct(data, newDynamicGroup.length > 0 ? newDynamicGroup : [{}]).map((item, index) => {
  371. let [d1, group] = item
  372. return {
  373. ...d1,
  374. id: d1.id + '_' + index,
  375. dynamicGroup: group,
  376. textDto: (group as any)?.textDto
  377. }
  378. })
  379. }
  380. }
  381. newdynamicCount = newdynamicCount + newData.length
  382. newTableData[item.accountId] = newData
  383. })
  384. setAdCount(newAdCount)
  385. setDynamicCount(newdynamicCount)
  386. setActiveKey(accountCreateLogs?.[0].accountId?.toString())
  387. console.log('newTableData-->', newTableData)
  388. setTableData(newTableData)
  389. }
  390. const onSubmit = (values: any) => {
  391. const { adgroups, targeting, dynamic, dynamicMaterialDTos, dynamicCreativesTextDTOS, mediaType } = addelivery
  392. let dynamicMaterialDTOS = []
  393. if ((materialData && Object.keys(materialData).length && dynamicMaterialDTos && Object.keys(dynamicMaterialDTos).length)) {
  394. let mType = Object.keys(materialData)[0];
  395. dynamicMaterialDTOS = dynamicMaterialDTos.dynamicGroup?.map((item: any) => {
  396. if (mType === 'image') {
  397. return [{
  398. type: mType,
  399. valueJson: JSON.stringify({
  400. value: {
  401. imageUrl: item?.image_id?.url,
  402. imageId: item?.image_id?.id,
  403. materialType: item?.image_id?.materialType
  404. }
  405. })
  406. }]
  407. } else if (mType === 'image_list' || mType === 'element_story') {
  408. let key = 'image_list'
  409. if (mType === 'element_story') {
  410. key = 'element_story'
  411. }
  412. let list = item?.[key]?.map((l: any) => {
  413. return {
  414. imageUrl: l?.url,
  415. imageId: l?.id,
  416. materialType: l?.materialType
  417. }
  418. })
  419. return [{
  420. type: mType,
  421. valueJson: JSON.stringify({
  422. value: {
  423. list
  424. }
  425. })
  426. }]
  427. } else if (['short_video', 'video'].includes(mType)) {
  428. let value: any = {
  429. materialType: item?.video_id?.materialType || item?.short_video1?.materialType || 0,
  430. videoUrl: item?.video_id?.url || item?.short_video1?.url,
  431. videoId: item?.video_id?.id || item?.short_video1?.id
  432. }
  433. if (item?.cover_id?.url) {
  434. value.imageUrl = item?.cover_id?.url
  435. value.imageId = item?.cover_id?.id
  436. value.materialCoverType = item?.cover_id?.materialType
  437. }
  438. return [{
  439. type: mType,
  440. valueJson: JSON.stringify({
  441. value
  442. })
  443. }]
  444. }
  445. return [{
  446. type: mType,
  447. valueJson: ''
  448. }]
  449. })
  450. }
  451. let accountIdParamDTOMap: any = {}
  452. accountCreateLogs.forEach(item => {
  453. let { pageList, productList, userActionSetsList, accountId, wechatChannelList } = item
  454. let userActionSetsListDto = userActionSetsList?.map((item: any) => ({ id: item?.userActionSetId, type: item?.type })) // dataSourceId
  455. let map: any = {
  456. userActionSetsList: userActionSetsListDto,
  457. pageList: pageList?.map((item: { pageId: any }) => item.pageId)
  458. }
  459. if (productList) {
  460. map.productDTOS = productList?.map(item => {
  461. return { productId: item.marketingAssetId }
  462. })
  463. }
  464. if (wechatChannelList) {
  465. map.wechatChannelId = wechatChannelList?.[0]?.wechatOfficialAccountId
  466. }
  467. accountIdParamDTOMap[accountId] = map
  468. })
  469. let params = {
  470. ...values,
  471. adgroupDTO: adgroups,
  472. targetings: targeting.map(item => ({ targetingName: item.targetingName, ...item?.targeting || {} })),
  473. dynamicCreativesDTO: { ...dynamic, mediaType },
  474. dynamicCreativesTextDTOS,
  475. dynamicMaterialDTOS,
  476. accountIdParamDTOMap
  477. }
  478. // setSubVisible(false)
  479. createAdgroupTask.run(params).then(res => {
  480. if (res) {
  481. Modal.success({
  482. content: '任务提交成功',
  483. bodyStyle: { fontWeight: 700 },
  484. okText: '跳转任务列表',
  485. closable: true,
  486. onOk: () => {
  487. sessionStorage.setItem('CAMPV3', values?.taskName)
  488. window.location.href = '/#/launchSystemV3/tencentAdPutIn/taskList'
  489. },
  490. onCancel: () => {
  491. setSubVisible(false)
  492. }
  493. })
  494. }
  495. })
  496. }
  497. const clearData = () => {
  498. setTableData({})
  499. }
  500. return <Space direction="vertical" style={{ width: '100%' }}>
  501. <Spin spinning={createAdgroupTask.loading || getSelectTaskDetail.loading}>
  502. <Card
  503. size="small"
  504. title={
  505. <div>
  506. <Space>
  507. <div className={style.cardTitle}>配置区</div>
  508. </Space>
  509. </div>
  510. }
  511. className={style.createAd}
  512. >
  513. <Space wrap>
  514. <Selector label="媒体账户组">
  515. <Select
  516. mode="multiple"
  517. style={{ minWidth: 200 }}
  518. placeholder="快捷选择媒体账户组"
  519. maxTagCount={1}
  520. allowClear
  521. bordered={false}
  522. filterOption={(input: any, option: any) => {
  523. return option!.children?.toString().toLowerCase().includes(input.toLowerCase())
  524. }}
  525. onChange={(e, option) => { getGroupAccountList(e) }}
  526. >
  527. {getGroupList?.data && getGroupList?.data?.map((item: any) => <Select.Option value={item.groupId} key={item.groupId}>{item.groupName}</Select.Option>)}
  528. </Select>
  529. </Selector>
  530. <Selector label="媒体账户">
  531. <Select
  532. mode="multiple"
  533. style={{ minWidth: 200, maxWidth: 500 }}
  534. placeholder="媒体账户(多个,,空格换行)"
  535. maxTagCount={1}
  536. allowClear
  537. bordered={false}
  538. maxTagPlaceholder={
  539. <Tooltip
  540. color="#FFF"
  541. title={<span style={{ color: '#000' }}>
  542. {accountCreateLogs?.filter((item, index) => index !== 0)
  543. ?.map((item, index) => <Tag
  544. key={index}
  545. closable
  546. onClose={() => {
  547. setAccountCreateLogs(accountCreateLogs?.filter(item1 => item1.accountId !== item.accountId))
  548. // setQueryForm({ ...queryForm, adqPageList: [], pageList: [], taskMediaMaps: queryForm?.taskMediaMaps?.map((item: { sysPageId: number }) => ({ ...item, sysPageId: '', accountPageIdMap: {}, cropUserGroupMap: [] })) })
  549. // clearData()
  550. }}
  551. >{item.accountId}</Tag>)}</span>
  552. }
  553. >
  554. <span>+{accountCreateLogs?.length > 1 ? accountCreateLogs.length - 1 : 0}</span>
  555. </Tooltip>
  556. }
  557. autoClearSearchValue={false}
  558. filterOption={(input: any, option: any) => {
  559. let newInput: string[] = input ? input?.split(/[,,\n\s]+/ig).filter((item: any) => item) : []
  560. return newInput?.some(val => option!.children?.toString().toLowerCase()?.includes(val))
  561. }}
  562. value={accountCreateLogs?.map(item => item?.accountId)}
  563. onChange={(e) => {
  564. setAccountCreateLogs(e?.map((item: any) => ({ accountId: item })))
  565. }}
  566. searchValue={accSearch}
  567. onSearch={(val) => {
  568. setAccSearch(val)
  569. }}
  570. dropdownRender={menu => (
  571. <>
  572. {menu}
  573. <Divider style={{ margin: '8px 0' }} />
  574. <Space style={{ padding: '0 8px 4px' }}>
  575. <Checkbox onChange={(e) => {
  576. let data = []
  577. if (e.target.checked) {
  578. data = JSON.parse(JSON.stringify(getAllUserAccount?.data?.data))
  579. if (accSearch) {
  580. let newAccSearch = accSearch?.split(/[,,\n\s]+/ig).filter((item: any) => item)
  581. data = data?.filter((item: any) => newAccSearch?.some(val => item!.accountId?.toString().toLowerCase()?.includes(val)))
  582. }
  583. }
  584. // setQueryForm({ ...queryForm, adqPageList: [], pageList: [], taskMediaMaps: queryForm?.taskMediaMaps?.map((item: { sysPageId: number }) => ({ ...item, sysPageId: '', accountPageIdMap: {}, cropUserGroupMap: [] })) })
  585. setAccountCreateLogs(data?.map((item: any) => ({ accountId: item?.accountId })))
  586. // clearData()
  587. }}>全选</Checkbox>
  588. </Space>
  589. </>
  590. )}
  591. >
  592. {getAllUserAccount?.data?.data?.map((item: any) => <Select.Option value={item.accountId} key={item.id}>{item.remark ? item.accountId + '_' + item.remark : item.accountId}</Select.Option>)}
  593. </Select>
  594. </Selector>
  595. {accountCreateLogs?.length > 0 && <>
  596. {marketingAssetOuterSpec?.marketingTargetType === 'MARKETING_TARGET_TYPE_FICTION' && <Button type="primary" danger={!accountCreateLogs?.some(item => item?.productList?.length)} onClick={() => { setGoodsVisible(true) }}>{accountCreateLogs?.some(item => item?.productList?.length) ? <>重新选择小说 <CheckOutlined style={{ color: '#FFFFFF' }} /></> : '请选择小说'}</Button>}
  597. {(marketingAssetOuterSpec?.marketingTargetType === 'MARKETING_TARGET_TYPE_WECHAT_OFFICIAL_ACCOUNT' || marketingCarrierType === 'MARKETING_CARRIER_TYPE_WECHAT_OFFICIAL_ACCOUNT') && <Button type="primary" danger={!accountCreateLogs?.some(item => item?.wechatChannelList?.length)} onClick={() => { setWechatVisible(true) }}>{accountCreateLogs?.some(item => item?.wechatChannelList?.length) ? <>重新选择公众号 <CheckOutlined style={{ color: '#FFFFFF' }} /></> : '请选择公众号'}</Button>}
  598. <Button onClick={() => { setSourceVisible(true) }}>精准匹配归因(选填){accountCreateLogs?.some(item => item?.userActionSetsList?.length) && <CheckOutlined style={{ color: '#1890ff' }} />}</Button>
  599. </>}
  600. </Space>
  601. <div className={style.settingsBody}>
  602. <div className={style.settingsBody_content}>
  603. <DispatchAddelivery.Provider
  604. value={{
  605. addelivery,
  606. setAddelivery,
  607. accountCreateLogs,
  608. setAccountCreateLogs,
  609. materialData,
  610. setMaterialData,
  611. textData,
  612. setTextData,
  613. clearData
  614. }}>
  615. <div className={style.settingsBody_content_right}>
  616. {/* 广告信息 */}
  617. <Ad />
  618. {/* 定向 */}
  619. <Target />
  620. {/* 创意 */}
  621. <Dynamic />
  622. {/* 创意素材 */}
  623. <Material />
  624. </div>
  625. <div className={style.settingsBody_content_left}>
  626. {/* 创意文案 */}
  627. <MaterialText />
  628. {/* 落地页 */}
  629. <PageList />
  630. </div>
  631. </DispatchAddelivery.Provider>
  632. </div>
  633. </div>
  634. <Space className={style.bts} wrap>
  635. <Button type='primary' onClick={severBd}>存为预设</Button>
  636. <Popconfirm
  637. title="确定清空?"
  638. onConfirm={delBdPlan}
  639. >
  640. <Button>清空配置/预设</Button>
  641. </Popconfirm>
  642. <Button type='primary' onClick={preview}><SearchOutlined />预览广告</Button>
  643. </Space>
  644. {/* 选择小说 */}
  645. {goodsVisible && <GoodsModal
  646. visible={goodsVisible}
  647. data={accountCreateLogs}
  648. onClose={() => setGoodsVisible(false)}
  649. onChange={(e) => {
  650. setAccountCreateLogs(e);
  651. setGoodsVisible(false);
  652. clearData()
  653. }}
  654. />}
  655. {/* 选择数据源 */}
  656. {sourceVisible && <DataSourceModal
  657. visible={sourceVisible}
  658. data={accountCreateLogs}
  659. onClose={() => setSourceVisible(false)}
  660. onChange={(e) => {
  661. setAccountCreateLogs(e);
  662. setSourceVisible(false);
  663. clearData()
  664. }}
  665. />}
  666. {/* 选择公众号 */}
  667. {wechatVisible && <WechatAccount
  668. visible={wechatVisible}
  669. data={accountCreateLogs}
  670. onClose={() => setWechatVisible(false)}
  671. onChange={(e) => {
  672. setAccountCreateLogs(e);
  673. setWechatVisible(false);
  674. clearData()
  675. }}
  676. />}
  677. </Card>
  678. </Spin>
  679. <Card
  680. className={style.createAd}
  681. >
  682. {activeKey && tableData && Object.keys(tableData)?.length > 0 ? <div className={style.cardBody}>
  683. <Tabs
  684. onChange={(e) => { setActiveKey(e) }}
  685. type="card"
  686. activeKey={activeKey}
  687. tabBarExtraContent={<Space>
  688. <span>广告总数:{adCount}</span>
  689. <span>创意总数:{dynamicCount}</span>
  690. <Button type='primary' onClick={() => {
  691. setSubVisible(true)
  692. }}>提交创建</Button>
  693. </Space>}
  694. >
  695. {accountCreateLogs.map(item => <Tabs.TabPane tab={item.accountId} key={item.accountId} />)}
  696. </Tabs>
  697. <div className={style.content} style={{ marginTop: 20 }}>
  698. <Table
  699. columns={columns()}
  700. dataSource={tableData[activeKey]}
  701. size="small"
  702. bordered
  703. scroll={{ x: 1200, y: 600 }}
  704. rowKey={'id'}
  705. pagination={{
  706. defaultPageSize: 50,
  707. total: tableData[activeKey]?.length || 0,
  708. showTotal: (total) => <Tag color="cyan">当前共{total}个创意,{tableData[activeKey]?.length / (tableData[activeKey]?.[0]?.rowSpan)}个广告</Tag>,
  709. }}
  710. />
  711. </div>
  712. </div> : <div style={{ minHeight: 400, display: 'flex', justifyContent: 'center', alignItems: 'center' }}>
  713. <Empty description="请先完成模块配置后,再预览广告计划" />
  714. </div>}
  715. </Card>
  716. {/* 提交任务 */}
  717. {subVisible && <SubmitModal
  718. ajax={createAdgroupTask}
  719. visible={subVisible}
  720. onChange={(e) => {
  721. onSubmit(e)
  722. }}
  723. onClose={() => {
  724. setSubVisible(false)
  725. }}
  726. />}
  727. </Space>
  728. }
  729. export default Create