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. accountCreateLogs.forEach(item => {
  273. let productList: any[] = []
  274. if (['MARKETING_TARGET_TYPE_FICTION'].includes(marketingAssetOuterSpec?.marketingTargetType)) { // 小说
  275. productList = item?.productList || []
  276. } else if (['MARKETING_TARGET_TYPE_WECHAT_OFFICIAL_ACCOUNT'].includes(marketingAssetOuterSpec?.marketingTargetType)) { // 公众号
  277. productList = item?.wechatChannelList || []
  278. }
  279. adLength += productList.length * targeting.length
  280. if (adLength > dynamicGroupLength) {
  281. message.error(`创意组分配规则选择创意组平均分配到广告时,创意组总数必须大于等于广告总数。当前创意组数量:${dynamicGroupLength},广告数量:${adLength}`)
  282. return
  283. }
  284. averageAdDynamicList = distributeArray(newDynamicGroup, adLength)
  285. })
  286. }
  287. let accountIndex = 0
  288. accountCreateLogs.forEach(item => {
  289. let productList: any[] = []
  290. if (['MARKETING_TARGET_TYPE_FICTION'].includes(marketingAssetOuterSpec?.marketingTargetType)) { // 小说
  291. productList = item?.productList || []
  292. } else if (['MARKETING_TARGET_TYPE_WECHAT_OFFICIAL_ACCOUNT'].includes(marketingAssetOuterSpec?.marketingTargetType)) { // 公众号
  293. productList = item?.wechatChannelList || []
  294. }
  295. let data = cartesianProduct(productList, targeting).map(newD => {
  296. let [productDto, targetDto, index] = newD
  297. let suffix = '_' + item.accountId + '_' + index
  298. let averageAdDynamic = averageAdDynamicList?.[accountIndex]
  299. let dat: any = {
  300. id: item.accountId + '_' + index,
  301. accountId: item.accountId, // 账户
  302. userActionSetsList: item.userActionSetsList, // 数据源
  303. pageListDto: item.pageList, // 落地页
  304. productDto, // 商品
  305. targetDto: { // 定向
  306. ...targetDto,
  307. targetingName: targetDto.targetingName + suffix
  308. },
  309. adgroupsDto: { // 广告信息
  310. ...adgroups,
  311. adgroupName: adgroups.adgroupName + suffix
  312. },
  313. dynamicDto: dynamic, // 创意信息
  314. averageAdDynamic,
  315. rowSpan: mediaType === 1 ? averageAdDynamic.length : ([910].includes(dynamic.creativeTemplateId) ? item.pageList?.length : (textType === 3 ? textDtoLenth * dynamicGroupLength : dynamicGroupLength)) || 1
  316. }
  317. if (marketingCarrierType === 'MARKETING_CARRIER_TYPE_WECHAT_OFFICIAL_ACCOUNT') { // 营销载体
  318. dat.marketingCarrierDto = item?.wechatChannelList
  319. }
  320. accountIndex += 1
  321. return dat
  322. })
  323. newAdCount += data.length
  324. let newData: any[] = []
  325. if ([910].includes(dynamic.creativeTemplateId)) {
  326. newData = cartesianProduct(data, item.pageList).map((item, index) => {
  327. let [d1, pageList, num] = item
  328. return {
  329. ...d1,
  330. id: d1.id + '_' + index,
  331. pageListDto: [pageList],
  332. dynamicDto: {
  333. ...d1.dynamicDto,
  334. dynamicCreativeName: d1.dynamicDto.dynamicCreativeName + num
  335. }
  336. }
  337. })
  338. } else {
  339. if (mediaType === 1) {
  340. data.forEach(item => {
  341. const { averageAdDynamic, ...ad } = item
  342. if (textType === 3) {
  343. let rowSpan = textDtoLenth * averageAdDynamic.length
  344. cartesianProduct(textDto, averageAdDynamic).forEach((taad: any, index) => {
  345. let [textValue, aad] = taad
  346. newData.push({
  347. ...ad,
  348. id: ad.id + '_' + index,
  349. dynamicGroup: aad,
  350. textDto: textValue,
  351. rowSpan
  352. })
  353. })
  354. } else {
  355. averageAdDynamic.forEach((aad: any, index: number) => {
  356. newData.push({
  357. ...ad,
  358. id: ad.id + '_' + index,
  359. dynamicGroup: aad,
  360. textDto: aad?.textDto
  361. })
  362. })
  363. }
  364. })
  365. } else {
  366. newData = cartesianProduct(data, newDynamicGroup.length > 0 ? newDynamicGroup : [{}]).map((item, index) => {
  367. let [d1, group] = item
  368. return {
  369. ...d1,
  370. id: d1.id + '_' + index,
  371. dynamicGroup: group,
  372. textDto: (group as any)?.textDto
  373. }
  374. })
  375. }
  376. }
  377. newdynamicCount = newdynamicCount + newData.length
  378. newTableData[item.accountId] = newData
  379. })
  380. setAdCount(newAdCount)
  381. setDynamicCount(newdynamicCount)
  382. setActiveKey(accountCreateLogs?.[0].accountId?.toString())
  383. console.log('newTableData-->', newTableData)
  384. setTableData(newTableData)
  385. }
  386. const onSubmit = (values: any) => {
  387. const { adgroups, targeting, dynamic, dynamicMaterialDTos, dynamicCreativesTextDTOS, mediaType } = addelivery
  388. let dynamicMaterialDTOS = []
  389. if ((materialData && Object.keys(materialData).length && dynamicMaterialDTos && Object.keys(dynamicMaterialDTos).length)) {
  390. let mType = Object.keys(materialData)[0];
  391. dynamicMaterialDTOS = dynamicMaterialDTos.dynamicGroup?.map((item: any) => {
  392. if (mType === 'image') {
  393. return [{
  394. type: mType,
  395. valueJson: JSON.stringify({
  396. value: {
  397. imageUrl: item?.image_id?.url,
  398. imageId: item?.image_id?.id,
  399. materialType: item?.image_id?.materialType
  400. }
  401. })
  402. }]
  403. } else if (mType === 'image_list' || mType === 'element_story') {
  404. let key = 'image_list'
  405. if (mType === 'element_story') {
  406. key = 'element_story'
  407. }
  408. let list = item?.[key]?.map((l: any) => {
  409. return {
  410. imageUrl: l?.url,
  411. imageId: l?.id,
  412. materialType: l?.materialType
  413. }
  414. })
  415. return [{
  416. type: mType,
  417. valueJson: JSON.stringify({
  418. value: {
  419. list
  420. }
  421. })
  422. }]
  423. } else if (['short_video', 'video'].includes(mType)) {
  424. let value: any = {
  425. materialType: item?.video_id?.materialType || item?.short_video1?.materialType || 0,
  426. videoUrl: item?.video_id?.url || item?.short_video1?.url,
  427. videoId: item?.video_id?.id || item?.short_video1?.id
  428. }
  429. if (item?.cover_id?.url) {
  430. value.imageUrl = item?.cover_id?.url
  431. value.imageId = item?.cover_id?.id
  432. value.materialCoverType = item?.cover_id?.materialType
  433. }
  434. return [{
  435. type: mType,
  436. valueJson: JSON.stringify({
  437. value
  438. })
  439. }]
  440. }
  441. return [{
  442. type: mType,
  443. valueJson: ''
  444. }]
  445. })
  446. }
  447. let accountIdParamDTOMap: any = {}
  448. accountCreateLogs.forEach(item => {
  449. let { pageList, productList, userActionSetsList, accountId, wechatChannelList } = item
  450. let userActionSetsListDto = userActionSetsList?.map((item: any) => ({ id: item?.userActionSetId, type: item?.type })) // dataSourceId
  451. let map: any = {
  452. userActionSetsList: userActionSetsListDto,
  453. pageList: pageList?.map((item: { pageId: any }) => item.pageId)
  454. }
  455. if (productList) {
  456. map.productDTOS = productList?.map(item => {
  457. return { productId: item.marketingAssetId }
  458. })
  459. }
  460. if (wechatChannelList) {
  461. map.wechatChannelId = wechatChannelList?.[0]?.wechatOfficialAccountId
  462. }
  463. accountIdParamDTOMap[accountId] = map
  464. })
  465. let params = {
  466. ...values,
  467. adgroupDTO: adgroups,
  468. targetings: targeting.map(item => ({ targetingName: item.targetingName, ...item?.targeting || {} })),
  469. dynamicCreativesDTO: { ...dynamic, mediaType },
  470. dynamicCreativesTextDTOS,
  471. dynamicMaterialDTOS,
  472. accountIdParamDTOMap
  473. }
  474. // setSubVisible(false)
  475. createAdgroupTask.run(params).then(res => {
  476. if (res) {
  477. Modal.success({
  478. content: '任务提交成功',
  479. bodyStyle: { fontWeight: 700 },
  480. okText: '跳转任务列表',
  481. closable: true,
  482. onOk: () => {
  483. sessionStorage.setItem('CAMPV3', values?.taskName)
  484. window.location.href = '/#/launchSystemV3/tencentAdPutIn/taskList'
  485. },
  486. onCancel: () => {
  487. setSubVisible(false)
  488. }
  489. })
  490. }
  491. })
  492. }
  493. const clearData = () => {
  494. setTableData({})
  495. }
  496. return <Space direction="vertical" style={{ width: '100%' }}>
  497. <Spin spinning={createAdgroupTask.loading || getSelectTaskDetail.loading}>
  498. <Card
  499. size="small"
  500. title={
  501. <div>
  502. <Space>
  503. <div className={style.cardTitle}>配置区</div>
  504. </Space>
  505. </div>
  506. }
  507. className={style.createAd}
  508. >
  509. <Space wrap>
  510. <Selector label="媒体账户组">
  511. <Select
  512. mode="multiple"
  513. style={{ minWidth: 200 }}
  514. placeholder="快捷选择媒体账户组"
  515. maxTagCount={1}
  516. allowClear
  517. bordered={false}
  518. filterOption={(input: any, option: any) => {
  519. return option!.children?.toString().toLowerCase().includes(input.toLowerCase())
  520. }}
  521. onChange={(e, option) => { getGroupAccountList(e) }}
  522. >
  523. {getGroupList?.data && getGroupList?.data?.map((item: any) => <Select.Option value={item.groupId} key={item.groupId}>{item.groupName}</Select.Option>)}
  524. </Select>
  525. </Selector>
  526. <Selector label="媒体账户">
  527. <Select
  528. mode="multiple"
  529. style={{ minWidth: 200, maxWidth: 500 }}
  530. placeholder="媒体账户(多个,,空格换行)"
  531. maxTagCount={1}
  532. allowClear
  533. bordered={false}
  534. maxTagPlaceholder={
  535. <Tooltip
  536. color="#FFF"
  537. title={<span style={{ color: '#000' }}>
  538. {accountCreateLogs?.filter((item, index) => index !== 0)
  539. ?.map((item, index) => <Tag
  540. key={index}
  541. closable
  542. onClose={() => {
  543. setAccountCreateLogs(accountCreateLogs?.filter(item1 => item1.accountId !== item.accountId))
  544. // setQueryForm({ ...queryForm, adqPageList: [], pageList: [], taskMediaMaps: queryForm?.taskMediaMaps?.map((item: { sysPageId: number }) => ({ ...item, sysPageId: '', accountPageIdMap: {}, cropUserGroupMap: [] })) })
  545. // clearData()
  546. }}
  547. >{item.accountId}</Tag>)}</span>
  548. }
  549. >
  550. <span>+{accountCreateLogs?.length > 1 ? accountCreateLogs.length - 1 : 0}</span>
  551. </Tooltip>
  552. }
  553. autoClearSearchValue={false}
  554. filterOption={(input: any, option: any) => {
  555. let newInput: string[] = input ? input?.split(/[,,\n\s]+/ig).filter((item: any) => item) : []
  556. return newInput?.some(val => option!.children?.toString().toLowerCase()?.includes(val))
  557. }}
  558. value={accountCreateLogs?.map(item => item?.accountId)}
  559. onChange={(e) => {
  560. setAccountCreateLogs(e?.map((item: any) => ({ accountId: item })))
  561. }}
  562. searchValue={accSearch}
  563. onSearch={(val) => {
  564. setAccSearch(val)
  565. }}
  566. dropdownRender={menu => (
  567. <>
  568. {menu}
  569. <Divider style={{ margin: '8px 0' }} />
  570. <Space style={{ padding: '0 8px 4px' }}>
  571. <Checkbox onChange={(e) => {
  572. let data = []
  573. if (e.target.checked) {
  574. data = JSON.parse(JSON.stringify(getAllUserAccount?.data?.data))
  575. if (accSearch) {
  576. let newAccSearch = accSearch?.split(/[,,\n\s]+/ig).filter((item: any) => item)
  577. data = data?.filter((item: any) => newAccSearch?.some(val => item!.accountId?.toString().toLowerCase()?.includes(val)))
  578. }
  579. }
  580. // setQueryForm({ ...queryForm, adqPageList: [], pageList: [], taskMediaMaps: queryForm?.taskMediaMaps?.map((item: { sysPageId: number }) => ({ ...item, sysPageId: '', accountPageIdMap: {}, cropUserGroupMap: [] })) })
  581. setAccountCreateLogs(data?.map((item: any) => ({ accountId: item?.accountId })))
  582. // clearData()
  583. }}>全选</Checkbox>
  584. </Space>
  585. </>
  586. )}
  587. >
  588. {getAllUserAccount?.data?.data?.map((item: any) => <Select.Option value={item.accountId} key={item.id}>{item.remark ? item.accountId + '_' + item.remark : item.accountId}</Select.Option>)}
  589. </Select>
  590. </Selector>
  591. {accountCreateLogs?.length > 0 && <>
  592. {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>}
  593. {(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>}
  594. <Button onClick={() => { setSourceVisible(true) }}>精准匹配归因(选填){accountCreateLogs?.some(item => item?.userActionSetsList?.length) && <CheckOutlined style={{ color: '#1890ff' }} />}</Button>
  595. </>}
  596. </Space>
  597. <div className={style.settingsBody}>
  598. <div className={style.settingsBody_content}>
  599. <DispatchAddelivery.Provider
  600. value={{
  601. addelivery,
  602. setAddelivery,
  603. accountCreateLogs,
  604. setAccountCreateLogs,
  605. materialData,
  606. setMaterialData,
  607. textData,
  608. setTextData,
  609. clearData
  610. }}>
  611. <div className={style.settingsBody_content_right}>
  612. {/* 广告信息 */}
  613. <Ad />
  614. {/* 定向 */}
  615. <Target />
  616. {/* 创意 */}
  617. <Dynamic />
  618. {/* 创意素材 */}
  619. <Material />
  620. </div>
  621. <div className={style.settingsBody_content_left}>
  622. {/* 创意文案 */}
  623. <MaterialText />
  624. {/* 落地页 */}
  625. <PageList />
  626. </div>
  627. </DispatchAddelivery.Provider>
  628. </div>
  629. </div>
  630. <Space className={style.bts} wrap>
  631. <Button type='primary' onClick={severBd}>存为预设</Button>
  632. <Popconfirm
  633. title="确定清空?"
  634. onConfirm={delBdPlan}
  635. >
  636. <Button>清空配置/预设</Button>
  637. </Popconfirm>
  638. <Button type='primary' onClick={preview}><SearchOutlined />预览广告</Button>
  639. </Space>
  640. {/* 选择小说 */}
  641. {goodsVisible && <GoodsModal
  642. visible={goodsVisible}
  643. data={accountCreateLogs}
  644. onClose={() => setGoodsVisible(false)}
  645. onChange={(e) => {
  646. setAccountCreateLogs(e);
  647. setGoodsVisible(false);
  648. clearData()
  649. }}
  650. />}
  651. {/* 选择数据源 */}
  652. {sourceVisible && <DataSourceModal
  653. visible={sourceVisible}
  654. data={accountCreateLogs}
  655. onClose={() => setSourceVisible(false)}
  656. onChange={(e) => {
  657. setAccountCreateLogs(e);
  658. setSourceVisible(false);
  659. clearData()
  660. }}
  661. />}
  662. {/* 选择公众号 */}
  663. {wechatVisible && <WechatAccount
  664. visible={wechatVisible}
  665. data={accountCreateLogs}
  666. onClose={() => setWechatVisible(false)}
  667. onChange={(e) => {
  668. setAccountCreateLogs(e);
  669. setWechatVisible(false);
  670. clearData()
  671. }}
  672. />}
  673. </Card>
  674. </Spin>
  675. <Card
  676. className={style.createAd}
  677. >
  678. {activeKey && tableData && Object.keys(tableData)?.length > 0 ? <div className={style.cardBody}>
  679. <Tabs
  680. onChange={(e) => { setActiveKey(e) }}
  681. type="card"
  682. activeKey={activeKey}
  683. tabBarExtraContent={<Space>
  684. <span>广告总数:{adCount}</span>
  685. <span>创意总数:{dynamicCount}</span>
  686. <Button type='primary' onClick={() => {
  687. setSubVisible(true)
  688. }}>提交创建</Button>
  689. </Space>}
  690. >
  691. {accountCreateLogs.map(item => <Tabs.TabPane tab={item.accountId} key={item.accountId} />)}
  692. </Tabs>
  693. <div className={style.content} style={{ marginTop: 20 }}>
  694. <Table
  695. columns={columns()}
  696. dataSource={tableData[activeKey]}
  697. size="small"
  698. bordered
  699. scroll={{ x: 1200 }}
  700. rowKey={'id'}
  701. pagination={{
  702. defaultPageSize: 50
  703. }}
  704. // rowSelection={{
  705. // selectedRowKeys: tableSelect?.map((item: any) => item?.myId.toString()),
  706. // onChange: (selectedRowKeys: React.Key[], selectedRows: any) => {
  707. // setTableSelect(selectedRows)
  708. // }
  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