index.tsx 65 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066
  1. import Tables from "@/components/Tables"
  2. import { useAjax } from "@/Hook/useAjax"
  3. import { createAdBatchApi, CreateAdProps } from "@/services/launchAdq/createAd"
  4. import { getSysAdcreativeInfo } from "@/services/launchAdq/creative"
  5. import { PromotedObjectType } from "@/services/launchAdq/enum"
  6. import { getTagsList } from "@/services/launchAdq/global"
  7. import { getSysAdgroupsInfo } from "@/services/launchAdq/localAd"
  8. import { getsysTargetingInfo } from "@/services/launchAdq/targeting"
  9. import { CheckOutlined, CloseOutlined, SearchOutlined } from "@ant-design/icons"
  10. import { Button, Card, Col, Empty, Row, Select, Space, Spin, Tooltip, Image, message, Tabs, Popconfirm, notification } from "antd"
  11. import React, { useCallback, useEffect, useState } from "react"
  12. import { useModel } from "umi"
  13. import Ad from "./ad"
  14. import DataSourceModal from "../../components/dataSourceModal"
  15. import GoodsModal from "../../components/goodsModal"
  16. import IdModal from "../../components/idModal"
  17. import LookLanding from "../../components/lookLanding"
  18. import PageModal from "../../components/pageModal"
  19. import SelectCloud from "../../components/selectCloud"
  20. import style from './index.less'
  21. import Selector from "./selector"
  22. import SubmitModal from "./submitModal"
  23. import columns from "./tableConfig"
  24. import TargetIng from './targeting'
  25. import Creative from './creative'
  26. import AddGroup from '../../components/addGroup'
  27. import CustomerServiceModal from "../../components/customerServiceModal"
  28. import { getTaskDetailsApi } from "@/services/launchAdq/taskList"
  29. import CreativeCL from "./creativeCL"
  30. import { groupBy } from "@/utils/utils"
  31. import { getAccountListApi, getGroupListApi } from "@/services/launchAdq/subgroup"
  32. const CreateAd: React.FC = () => {
  33. /*************************/
  34. const { getAdAccount } = useModel('useLaunchAdq.useAdAuthorize')
  35. const [queryForm, setQueryForm] = useState<Partial<CreateAdProps>>({
  36. campaignName: '', // 计划名称
  37. campaignType: 'CAMPAIGN_TYPE_NORMAL', // 计划类型 CAMPAIGN_TYPE_NORMAL CAMPAIGN_TYPE_SEARCH
  38. promotedObjectType: 'PROMOTED_OBJECT_TYPE_WECHAT_OFFICIAL_ACCOUNT', // 推广目标类型
  39. speedMode: 'SPEED_MODE_STANDARD', // 投放速度模式
  40. sysAdgroupId: undefined, // 广告组ID
  41. sysAdgroup: undefined,//广告组内容
  42. sysTargetingId: undefined, // 定向包 id
  43. sysTargeting: undefined, // 定向包 内容
  44. adgroupName: undefined, // 广告名称
  45. configuredStatus: 'AD_STATUS_SUSPEND', // 广告状态
  46. sysAdcreativeId: undefined, // 创意ID
  47. taskMediaMaps: [], // 创意内容
  48. pageList: [],//本地落地页详情入口
  49. adqPageList: [],//云落地页
  50. expandEnabled: false,
  51. expandTargeting: []
  52. })
  53. const [launchMode, setLaunchMode] = useState<number>(Number(localStorage.getItem('LAUNCHMODE')) || 1) // 投放模式 1 现在投放模式 2 创量模式
  54. const [accountCreateLogs, setAccountCreateLogs] = useState<{ adAccountId: number, id: number, userActionSetsList?: any[], productList?: any, conversionList?: any, customAudienceList?: any, excludedCustomAudienceList?: any, pageList?: any, coldStartAudienceList?: any[] }[]>([]) // 账户
  55. const { currentUser: { userId } }: any = useModel('@@initialState', model => ({ currentUser: model.initialState?.currentUser }))
  56. const [goodsVisible, setGoodsVisible] = useState<boolean>(false) // 选择商品弹窗控制
  57. const [sourceVisible, setSourceVisible] = useState<boolean>(false) // 选择数据源弹窗控制
  58. const [idVisible, setIdVisible] = useState<boolean>(false) // 选择转化ID弹窗控制
  59. const [selectImgVisible, setSelectImgVisible] = useState<boolean>(false) // 选择转化ID弹窗控制
  60. const [lookVisible, setLookVisible] = useState<boolean>(false) // 选择转化ID弹窗控制
  61. const [subVisible, setSubVisible] = useState<boolean>(false) // 选择设置名称弹窗控制
  62. const [pageVisible, setPageVisible] = useState<boolean>(false) // 选择云端落地页控制
  63. const [tableData, setTableData] = useState<any[]>([]) // 预览表格
  64. const [tableSelect, setTableSelect] = useState<any[]>([])
  65. const [geoLocationList, setGeoLocationList] = useState<any>({}) // 所有地域列表
  66. const [modelList, setModelList] = useState<any>({}) // 所有品牌手机
  67. const [targetKey, set_targetKey] = useState('0')//创意key
  68. const [page_checked, set_page_checked] = useState(false)//创意key
  69. const [usesArr, setUsersArr] = useState<any>(localStorage.getItem('ADQUSERS' + userId) ? JSON.parse(localStorage.getItem('ADQUSERS' + userId) as any) : [])
  70. const { init, get } = useModel('useLaunchAdq.useBdMediaPup')
  71. const [cloudParams, setCloudParams] = useState<{ adcreativeTemplateId?: number }>({})
  72. const tagsList_REGION = useAjax((params) => getTagsList(params))
  73. const tagsList_MODEL = useAjax((params) => getTagsList(params))
  74. const getSysAdgroups = useAjax((params) => getSysAdgroupsInfo(params))
  75. const getsysTargeting = useAjax((params) => getsysTargetingInfo(params))
  76. const getSysAdcreative = useAjax((params) => getSysAdcreativeInfo(params))
  77. const createAdBatch = useAjax((params) => createAdBatchApi(params))
  78. const getTaskDetails = useAjax((params) => getTaskDetailsApi(params))
  79. const getGroupList = useAjax(() => getGroupListApi())
  80. const getAccountList = useAjax((params) => getAccountListApi(params))
  81. /*************************/
  82. useEffect(() => {
  83. getGroupList.run()
  84. }, [])
  85. /**数据回填 */
  86. useEffect(() => {
  87. let taskId = sessionStorage.getItem('TASKID')
  88. if (taskId) {
  89. getTaskDetails.run(taskId).then(res => {
  90. console.log('res----->', res)
  91. setLaunchMode(1)
  92. const { adCreateLogs, campaignType, promotedObjectType, speedMode, sysAdgroup, sysAdgroupId, sysTargeting, sysTargetingId } = res
  93. let adCreateLogsData = adCreateLogs?.map((item: any) => {
  94. return {
  95. adAccountId: item?.accountId,
  96. id: item?.adAccountId,
  97. userActionSetsList: item?.userActionSetList?.map((item: any) => ({ ...item, id: item?.userActionSetId })),
  98. productList: item?.product ? [{ ...item?.product, productCatalog: item?.productCatalog, id: Number(item?.product?.productOuterId?.replace(/\D/ig, '')) }] : undefined,
  99. coldStartAudienceList: item?.coldStartAudienceList?.map((item: any) => ({ ...item, id: item.audienceId }))
  100. // pageList: [item.page]
  101. }
  102. }).filter((item: any, index: number, self: any) => self.findIndex((i: any) => i.id == item.id) === index)
  103. setAccountCreateLogs(adCreateLogsData)
  104. const sorted = groupBy(adCreateLogs, (item) => [item.sysAdcreativeId])
  105. let taskMediaMaps = sorted[0]?.map((item: any) => {
  106. let pageElementsSpecList = item?.sysPage?.pageSpecsList[0]?.pageElementsSpecList // 内容区
  107. let globalSpec = item?.sysPage?.globalSpec // 悬浮组件
  108. /** 处理客服 */
  109. let cropUserGroupMap: any[] = []
  110. if ((pageElementsSpecList as any[])?.some((item: { elementType: string }) => item?.elementType === 'ENTERPRISE_WX') || (globalSpec?.globalElementsSpecList?.length > 0 && globalSpec?.globalElementsSpecList?.some((item: { floatButtonSpec: { elementType: string } }) => item?.floatButtonSpec?.elementType === 'ENTERPRISE_WX'))) {
  111. let groupList: { type: number, name: string, cropList: any[], cropId?: number, groupId?: number }[] = [];
  112. (pageElementsSpecList as any[])?.forEach((item: { elementType: string, enterpriseWxSpec: { btnTitle: string } }) => {
  113. if (item?.elementType === 'ENTERPRISE_WX') {
  114. groupList.push({ type: 1, name: '联系商家', cropList: [] }) // item.enterpriseWxSpec.btnTitle
  115. }
  116. })
  117. if ((globalSpec?.globalElementsSpecList?.length > 0 && globalSpec?.globalElementsSpecList)) {
  118. groupList.push({ type: 2, name: '悬浮组件', cropList: [] })
  119. }
  120. cropUserGroupMap = sorted[0]?.map((item: any) => {
  121. let corpUserGroup1s = item?.corpUserGroup1s
  122. let corpUserGroup2s = item?.corpUserGroup2s
  123. return {
  124. adAccountId: item.accountId, id: item.adAccountId, data: groupList.map((crop: any, index: number) => {
  125. return { ...crop, cropList: crop.type === 1 ? corpUserGroup1s[index] ? [{ ...corpUserGroup1s[index], id: corpUserGroup1s[index].groupId }] : [] : corpUserGroup2s[0] ? [{ ...corpUserGroup2s[0], id: corpUserGroup2s[0].groupId }] : [] }
  126. })
  127. }
  128. })
  129. }
  130. let accountPageIdMap: any = {}
  131. adCreateLogs?.forEach((item: any) => {
  132. if (item?.pageId) {
  133. accountPageIdMap[item.accountId] = item?.pageId
  134. }
  135. })
  136. return { sysAdcreative: item?.sysAdcreative, sysPageId: item?.sysPageId, cropUserGroupMap, accountPageIdMap }
  137. })
  138. /** 云端落地页处理 */
  139. let pageList = sorted?.map((item: any[]) => {
  140. if (item.some((item1: { sysPageId: number }) => item1.sysPageId)) {
  141. return item[0].sysPage
  142. } else {
  143. return null
  144. }
  145. })
  146. let adqPageList = sorted?.map((item: any[]) => {
  147. if (item.some((item1: { pageId: number }) => item1.pageId)) {
  148. return item.map((item1: any) => ({
  149. pageList: [{ ...item1.page, id: item1.page.pageId }],
  150. adAccountId: item1?.accountId,
  151. id: item1?.adAccountId,
  152. }))
  153. } else {
  154. return null
  155. }
  156. })
  157. setQueryForm({
  158. ...queryForm,
  159. campaignType,
  160. promotedObjectType,
  161. speedMode,
  162. sysAdgroup,
  163. sysAdgroupId,
  164. sysTargeting,
  165. sysTargetingId,
  166. adgroupName: sysAdgroup?.adgroupName,
  167. configuredStatus: sysAdgroup?.configuredStatus,
  168. expandEnabled: sysAdgroup?.expandEnabled || false,
  169. expandTargeting: sysAdgroup?.expandTargeting || [],
  170. taskMediaMaps: taskMediaMaps || [],
  171. pageList,
  172. adqPageList
  173. })
  174. })
  175. sessionStorage.removeItem('TASKID')
  176. } else {
  177. let adqAdData = localStorage.getItem('ADQAD')
  178. if (adqAdData) {
  179. const { queryForm, accountCreateLogs } = JSON.parse(adqAdData)
  180. setQueryForm({ ...queryForm })
  181. setAccountCreateLogs(accountCreateLogs)
  182. }
  183. }
  184. }, [])
  185. // 设置地域
  186. useEffect(() => {
  187. tagsList_REGION.run({ type: 'REGION' }).then(res => {
  188. if (res && Array.isArray(res)) {
  189. setGeoLocationList(() => (res as any[])?.reduce((prev: any, cur: { id: number }) => {
  190. prev[cur.id] = cur
  191. return prev
  192. }, {}))
  193. }
  194. })
  195. tagsList_MODEL.run({ type: 'DEVICE_BRAND_MODEL' }).then(res => {
  196. if (res && Array.isArray(res)) {
  197. setModelList(() => (res as any[])?.reduce((prev: any, cur: { id: number }) => {
  198. prev[cur.id] = cur
  199. return prev
  200. }, {}))
  201. }
  202. })
  203. }, [])
  204. // 获取账户列表
  205. useEffect(() => {
  206. getAdAccount.run()
  207. }, [])
  208. // 账号对比
  209. useEffect(() => {
  210. if (getAdAccount?.data?.data && accountCreateLogs) {
  211. if (accountCreateLogs.some(item => !getAdAccount?.data?.data?.find((item1: { accountId: number }) => item.adAccountId == item1.accountId))) {
  212. let errorData: any[] = []
  213. let newAccountCreateLogs = accountCreateLogs.filter(item => {
  214. let data = getAdAccount?.data?.data?.find((item1: { accountId: number }) => item.adAccountId == item1.accountId)
  215. if (data) {
  216. return true
  217. } else {
  218. errorData.push(item.adAccountId)
  219. return false
  220. }
  221. })
  222. notification.error({
  223. duration: 60 * 5,
  224. message: '重要提示',
  225. description: `本地媒体账户与你所拥有账户对不上,当前创建账号不符合账号及部分相关配置已清空。请把保存在本地的媒体账户或者媒体账户组清空,重新选择保存。问题账户:(${errorData.toString()})`
  226. })
  227. setAccountCreateLogs(newAccountCreateLogs)
  228. setQueryForm({ ...queryForm, adqPageList: [], taskMediaMaps: queryForm?.taskMediaMaps?.map(item => ({ ...item, accountPageIdMap: {} })) })
  229. }
  230. }
  231. }, [getAdAccount?.data, accountCreateLogs, queryForm])
  232. /** 获取广告详情 */
  233. useEffect(() => {
  234. if (getSysAdgroups?.data?.bidMode !== 'BID_MODE_CPM' && accountCreateLogs?.length > 0) {
  235. let newAccountCreateLogs = accountCreateLogs?.map((item: any) => {
  236. if (item?.customAudienceList) {
  237. delete item?.customAudienceList
  238. }
  239. return { ...item }
  240. })
  241. setAccountCreateLogs([...newAccountCreateLogs])
  242. }
  243. }, [getSysAdgroups?.data?.bidMode])
  244. /** 删除商品内容 */
  245. const goodsDel = (index: number) => {
  246. let newArr = JSON.parse(JSON.stringify(accountCreateLogs))
  247. delete newArr[index].productList
  248. setAccountCreateLogs(newArr)
  249. }
  250. /** 删除数据源 */
  251. const sourceDel = (index: number, num: number) => {
  252. let newArr = JSON.parse(JSON.stringify(accountCreateLogs))
  253. newArr[index].userActionSetsList?.splice(num, 1)
  254. setAccountCreateLogs(newArr)
  255. }
  256. /** 删除人群包 */
  257. const cpDel = (index: number, num: number, key: string) => {
  258. let newArr = JSON.parse(JSON.stringify(accountCreateLogs))
  259. newArr[index][key]?.splice(num, 1)
  260. setAccountCreateLogs(newArr)
  261. }
  262. // 创意素材与文案叉乘处理
  263. const whatever = (...arrs: any[]) => {
  264. console.log('arrs---->', arrs);
  265. if (arrs[0]?.length && arrs[1]?.length) {
  266. return arrs.reduce((total, curr) => total.flatMap((e: any) => curr.map((e2: any) => ({ ...e2, ...e }))))
  267. } else if (arrs[0]?.length) {
  268. return arrs[0]
  269. } else if (arrs[1]?.length) {
  270. return arrs[1]
  271. } else {
  272. return ['']
  273. }
  274. }
  275. /** 预览 */
  276. const preview = () => {
  277. let newQueryForm: Partial<CreateAdProps> = JSON.parse(JSON.stringify(queryForm))
  278. if (accountCreateLogs?.length === 0) {
  279. message.error('请选择媒体账户')
  280. return
  281. }
  282. if (!newQueryForm.promotedObjectType) {
  283. message.error('请选择推广目标')
  284. return
  285. }
  286. if (!newQueryForm.sysAdgroup) {
  287. message.error('请先设置广告基本信息')
  288. return
  289. }
  290. if (!newQueryForm.sysTargeting) {
  291. message.error('请选择定向')
  292. return
  293. }
  294. if (!newQueryForm.taskMediaMaps?.every(item => item.sysAdcreative)) {
  295. message.error('请设置创意的基本信息')
  296. return
  297. }
  298. if (!newQueryForm.taskMediaMaps?.every(item => item.sysPageId || item.accountPageIdMap)) {
  299. message.error('请选择落地页')
  300. return
  301. }
  302. if (launchMode === 2) {
  303. if ((queryForm?.materialData && queryForm?.materialData?.length > 0) && !(newQueryForm?.materials && newQueryForm?.materials?.length > 0)) {
  304. message.error('请选择创意素材')
  305. return
  306. }
  307. if ((queryForm?.textData && queryForm.textData?.length > 0) && !(newQueryForm?.texts && newQueryForm?.texts?.length > 0)) {
  308. message.error('请选择创意文案')
  309. return
  310. }
  311. }
  312. if (newQueryForm?.taskMediaMaps && newQueryForm?.taskMediaMaps?.some((item: { cropUserGroupMap: any[] }) => item?.cropUserGroupMap?.length > 0)) {
  313. let cropData = newQueryForm?.taskMediaMaps?.filter((item: { cropUserGroupMap: any[] }) => item?.cropUserGroupMap?.length > 0)
  314. if (cropData?.some((item: { cropUserGroupMap: { data: { cropList: any[] }[] }[] }) => {
  315. return item?.cropUserGroupMap?.some((item1: { data: { cropList: any[] }[] }) => item1?.data?.some((item2: { cropList: any[] }) => item2?.cropList?.length === 0))
  316. })) {
  317. message.error('请完善落地页企微客服组')
  318. return
  319. }
  320. }
  321. let data: any[] = []
  322. if (launchMode === 2) {
  323. if (Array.isArray(newQueryForm.materials) && Array.isArray(newQueryForm?.texts)) {
  324. let taskMediaMap = JSON.parse(JSON.stringify(newQueryForm.taskMediaMaps[0]))
  325. let adcreativeElements = taskMediaMap.sysAdcreative?.adcreativeElements || {}
  326. let newTaskMediaMaps = whatever(newQueryForm.materials, newQueryForm.texts).map((item: any) => {
  327. taskMediaMap.sysAdcreative.adcreativeElements = { ...adcreativeElements, ...item }
  328. return JSON.parse(JSON.stringify(taskMediaMap))
  329. })
  330. newQueryForm.taskMediaMaps = newTaskMediaMaps
  331. }
  332. }
  333. accountCreateLogs.forEach((item: any) => {
  334. newQueryForm.taskMediaMaps?.forEach((task, index) => {
  335. let obj = {
  336. ...item,
  337. ...newQueryForm,
  338. sysAdGroupData: newQueryForm.sysAdgroup,
  339. targetingData: newQueryForm.sysTargeting,
  340. sysAdcreativeData: task.sysAdcreative,
  341. pageData: launchMode === 2 ? (newQueryForm.pageList as any)[0] || (newQueryForm.adqPageList as any)[0]?.find((adq: { adAccountId: any }) => adq.adAccountId === item.adAccountId)?.pageList[0] : (newQueryForm.pageList as any)[index] || (newQueryForm.adqPageList as any)[index]?.find((adq: { adAccountId: any }) => adq.adAccountId === item.adAccountId)?.pageList[0],
  342. myId: Number(item.id + '' + index)
  343. }
  344. data.push(obj)
  345. })
  346. })
  347. setTableData(data)
  348. }
  349. const submit = (props: { campaignName: string, count?: number }) => {
  350. let newQueryForm = JSON.parse(JSON.stringify(queryForm))
  351. if (launchMode === 2) {
  352. if (Array.isArray(newQueryForm.materials) && Array.isArray(newQueryForm?.texts)) {
  353. let taskMediaMap = JSON.parse(JSON.stringify(newQueryForm.taskMediaMaps[0]))
  354. let adcreativeElements = taskMediaMap.sysAdcreative?.adcreativeElements || {}
  355. let newTaskMediaMaps = whatever(newQueryForm.materials, newQueryForm.texts).map((item: any) => {
  356. if (item) {
  357. taskMediaMap.sysAdcreative.adcreativeElements = { ...adcreativeElements, ...item }
  358. } else {
  359. taskMediaMap.sysAdcreative.adcreativeElements = { ...adcreativeElements }
  360. }
  361. return JSON.parse(JSON.stringify(taskMediaMap))
  362. })
  363. newQueryForm.taskMediaMaps = newTaskMediaMaps
  364. }
  365. }
  366. let newtaskMediaMaps = newQueryForm.taskMediaMaps.map((item1: { cropUserGroupMap?: any[] }) => {
  367. let { cropUserGroupMap, ...data } = item1
  368. if (cropUserGroupMap && cropUserGroupMap?.length > 0) {
  369. let corpUserGroup1Map: any = {}
  370. let corpUserGroup2Map: any = {}
  371. cropUserGroupMap.forEach((cropData: { id: number, data: any[] }) => {
  372. let cropData1: { corpId: string, groupId: number }[] = []
  373. let cropData2: { corpId: string, groupId: number }[] = []
  374. cropData?.data.forEach((crop: { type: 1 | 2, cropList: { corpId: string, groupId: number }[] }) => {
  375. let cropList = crop.cropList
  376. if (crop.type === 1) {
  377. cropData1.push({ corpId: cropList[0].corpId, groupId: cropList[0].groupId })
  378. } else {
  379. cropData2.push({ corpId: cropList[0].corpId, groupId: cropList[0].groupId })
  380. }
  381. })
  382. if (cropData1.length > 0) {
  383. corpUserGroup1Map[cropData.id.toString()] = cropData1
  384. }
  385. if (cropData2.length > 0) {
  386. corpUserGroup2Map[cropData.id.toString()] = cropData2
  387. }
  388. })
  389. return { ...data, corpUserGroup1Map: Object.keys(corpUserGroup1Map)?.length > 0 ? corpUserGroup1Map : null, corpUserGroup2Map: Object.keys(corpUserGroup2Map)?.length > 0 ? corpUserGroup2Map : null }
  390. }
  391. return data
  392. })
  393. newQueryForm.taskMediaMaps = newtaskMediaMaps
  394. let params = { ...newQueryForm, ...props }
  395. console.log(accountCreateLogs)
  396. let accountLogs = accountCreateLogs.map((item: any, index) => {
  397. // userActionSetsList 数据源 productList 商品
  398. let data: any = { adAccountId: item.id, count: props.count || 1 }
  399. if (item?.userActionSetsList?.length > 0) { // 数据源
  400. data.userActionSets = item?.userActionSetsList?.map((item: any) => ({ id: item?.id, type: item?.type }))
  401. }
  402. if (item?.productList?.length > 0) { // 商品
  403. data.productId = item?.productList[0].productOuterId
  404. data.productCatalogId = item?.productList[0].productCatalogId
  405. }
  406. if (item?.customAudienceList?.length > 0) {
  407. data.customAudience = item?.customAudienceList?.map((item: any) => item.id)
  408. }
  409. if (item?.excludedCustomAudienceList?.length > 0) {
  410. data.excludedCustomAudience = item?.excludedCustomAudienceList?.map((item: any) => item.id)
  411. }
  412. if (item?.pageList) {
  413. data.pageId = item?.pageData?.id
  414. }
  415. if (item?.coldStartAudienceList?.length > 0) {
  416. data.coldStartAudience = item?.coldStartAudienceList?.map((item: any) => item.id)
  417. }
  418. return data
  419. })
  420. if (params?.expandEnabled) {
  421. params.sysAdgroup.expandEnabled = params?.expandEnabled
  422. params.sysAdgroup.expandTargeting = []
  423. }
  424. if (params?.expandTargeting?.length > 0) {
  425. params.sysAdgroup.expandTargeting = params?.expandTargeting
  426. }
  427. params.accountCreateLogs = accountLogs
  428. delete params.sysAdgroupId
  429. delete params.sysAdcreativeId
  430. delete params.sysTargetingId
  431. delete params.pageList
  432. delete params.adqPageList
  433. delete params.count
  434. delete params?.expandEnabled
  435. delete params?.expandTargeting
  436. delete params?.texts
  437. delete params?.textData
  438. delete params?.materialData
  439. delete params?.materials
  440. console.log('paramsSubmit====>', params)
  441. createAdBatch.run(params).then(res => {
  442. if (res) {
  443. sessionStorage.setItem('CAMP', props?.campaignName)
  444. message.success('创建成功')
  445. window.location.href = '/#/launchSystemNew/launchManage/taskList'
  446. }
  447. })
  448. }
  449. /** 清除数据 */
  450. const clearData = () => {
  451. setTableData([])
  452. setTableSelect([])
  453. }
  454. /** 存为预设 */
  455. const severBd = () => {
  456. // queryForm accountCreateLogs
  457. localStorage.setItem('ADQAD', JSON.stringify({
  458. queryForm,
  459. accountCreateLogs
  460. }))
  461. message.success('存储成功')
  462. }
  463. /** 清除 */
  464. const delBdPlan = () => {
  465. localStorage.removeItem('ADQAD')
  466. setAccountCreateLogs([])
  467. setQueryForm({
  468. campaignName: '', // 计划名称
  469. campaignType: 'CAMPAIGN_TYPE_NORMAL', // 计划类型 CAMPAIGN_TYPE_NORMAL CAMPAIGN_TYPE_SEARCH
  470. promotedObjectType: 'PROMOTED_OBJECT_TYPE_WECHAT_OFFICIAL_ACCOUNT', // 推广目标类型
  471. speedMode: 'SPEED_MODE_STANDARD', // 投放速度模式
  472. sysAdgroupId: undefined, // 广告组内容
  473. sysTargetingId: undefined, // 定向包 id
  474. adgroupName: undefined, // 广告名称
  475. configuredStatus: 'AD_STATUS_SUSPEND', // 广告状态
  476. sysAdcreativeId: undefined, // 创意ID
  477. expandEnabled: false,
  478. expandTargeting: []
  479. })
  480. }
  481. /** 设置落地页 */
  482. const setPage = (e: any) => {
  483. let arr: any = queryForm.taskMediaMaps || []
  484. function setUrl(item: { sysAdcreative: { overrideCanvasHeadOption: string, adcreativeElements: any } }) {
  485. if (item?.sysAdcreative?.overrideCanvasHeadOption && item?.sysAdcreative?.overrideCanvasHeadOption === "OPTION_CANVAS_OVERRIDE_CREATIVE") {
  486. let adcreativeElementsNew = { ...item.sysAdcreative.adcreativeElements }
  487. let obj = e[0].pageSpecsList[0].pageElementsSpecList[0]
  488. let { topImageSpec, topVideoSpec, topSliderSpec } = obj
  489. Object.keys(adcreativeElementsNew).forEach(key => {
  490. switch (key) {
  491. case 'imageUrl'://图素材
  492. adcreativeElementsNew[key] = topImageSpec?.imageUrl
  493. break;
  494. case 'videoUrl'://视频素材
  495. adcreativeElementsNew[key] = topVideoSpec?.videoUrl
  496. break;
  497. case 'imageUrlList'://图素材
  498. adcreativeElementsNew[key] = topSliderSpec?.imageUrlList || [topImageSpec?.imageUrl]
  499. break;
  500. case 'shortVideoStruct'://视频素材
  501. adcreativeElementsNew[key] = { shortVideo1Url: topVideoSpec?.videoUrl }
  502. break;
  503. }
  504. })
  505. return { ...item, sysPageId: e[0]?.id, accountPageIdMap: null, sysAdcreative: { ...item.sysAdcreative, adcreativeElements: adcreativeElementsNew } }
  506. }
  507. return { ...item, sysPageId: e[0]?.id, accountPageIdMap: null, }
  508. }
  509. if (page_checked) {
  510. arr = queryForm.taskMediaMaps?.map(item => {
  511. return setUrl(item)
  512. })
  513. } else {
  514. arr[targetKey as string] = setUrl(arr[targetKey as string])
  515. }
  516. getPageInfo(arr)
  517. setSelectImgVisible(false)
  518. }
  519. /** 获取落地页详情 */
  520. const getPageInfo = useCallback((arrList) => {
  521. console.log('arrList====>', arrList)
  522. if (arrList && arrList[targetKey]?.sysPageId) {
  523. get.run({ mediaType: 'PAGE', sysMediaId: arrList[targetKey]?.sysPageId }).then(res => {
  524. if (!Object.keys(res)?.includes('fail')) {
  525. let data = res
  526. let pageElementsSpecList = data?.pageSpecsList[0]?.pageElementsSpecList // 内容区
  527. let globalSpec = data?.globalSpec // 悬浮组件
  528. let arr: any = queryForm.pageList || []
  529. let adqPageArr: any = queryForm.adqPageList || []
  530. adqPageArr[targetKey] = null
  531. arr[targetKey] = data
  532. /** 处理客服 */
  533. let cropUserGroupMap: any[] = []
  534. if ((pageElementsSpecList as any[])?.some((item: { elementType: string }) => item?.elementType === 'ENTERPRISE_WX') || (globalSpec?.globalElementsSpecList?.length > 0 && globalSpec?.globalElementsSpecList?.some((item: { floatButtonSpec: { elementType: string } }) => item?.floatButtonSpec?.elementType === 'ENTERPRISE_WX'))) {
  535. let groupList: { type: number, name: string, cropList: any[], cropId?: number, groupId?: number }[] = [];
  536. (pageElementsSpecList as any[])?.forEach((item: { elementType: string, enterpriseWxSpec: { btnTitle: string } }) => {
  537. if (item?.elementType === 'ENTERPRISE_WX') {
  538. groupList.push({ type: 1, name: '联系商家', cropList: [] }) // item.enterpriseWxSpec.btnTitle
  539. }
  540. })
  541. if ((globalSpec?.globalElementsSpecList?.length > 0 && globalSpec?.globalElementsSpecList)) {
  542. groupList.push({ type: 2, name: '悬浮组件', cropList: [] })
  543. }
  544. cropUserGroupMap = accountCreateLogs?.map((item: any) => ({ adAccountId: item.adAccountId, id: item.id, data: groupList }))
  545. }
  546. arrList[targetKey].cropUserGroupMap = cropUserGroupMap
  547. setQueryForm({ ...queryForm, pageList: arr, taskMediaMaps: arrList, adqPageList: adqPageArr })//设置落地页详情数组
  548. } else {
  549. //清空对应创意中的落地页ID
  550. let arr = queryForm.taskMediaMaps || []
  551. arr[targetKey].sysPageId = ''
  552. setQueryForm({ ...queryForm, taskMediaMaps: arr })
  553. }
  554. })
  555. }
  556. }, [queryForm, targetKey, accountCreateLogs])
  557. // 设置云端落地页
  558. const setAdqPage = useCallback((data) => {
  559. if (Array.isArray(data) && data.length > 0) {
  560. let objMap = {}
  561. data?.forEach(item => {
  562. objMap[item.adAccountId] = item.pageList[0].pageId
  563. })
  564. let arr: any = queryForm.taskMediaMaps || []
  565. let adqPageArr: any = queryForm.adqPageList || []
  566. let pageArr: any = queryForm.pageList || []
  567. adqPageArr[targetKey as string] = data
  568. pageArr[targetKey as string] = null
  569. delete arr[targetKey as string]?.cropUserGroupMap
  570. arr[targetKey as string] = { ...arr[targetKey as string], sysPageId: '', accountPageIdMap: objMap }
  571. // 重新设置云端数据并清空本地数据
  572. setQueryForm({ ...queryForm, taskMediaMaps: arr, adqPageList: adqPageArr, pageList: pageArr })
  573. }
  574. }, [queryForm, targetKey])
  575. // tabs新增和删除
  576. const onEdit = useCallback((targetKey: string | React.MouseEvent<Element, MouseEvent> | React.KeyboardEvent<Element>, action: 'add' | 'remove') => {
  577. if (queryForm.taskMediaMaps) {
  578. if (action === 'remove') {
  579. let arr = queryForm.taskMediaMaps
  580. let adqPageArr: any = queryForm.adqPageList || []
  581. let pageArr: any = queryForm.pageList || []
  582. adqPageArr[targetKey as string] = null
  583. pageArr[targetKey as string] = null
  584. arr[targetKey as string] = { ...arr[targetKey as string], sysPageId: '', accountPageIdMap: null }
  585. setQueryForm({ ...queryForm, taskMediaMaps: arr, pageList: pageArr, adqPageList: adqPageArr })
  586. }
  587. }
  588. }, [queryForm, targetKey])
  589. // 媒体组更新通知
  590. const usersChange = useCallback(() => {
  591. let data = JSON.parse(localStorage.getItem('ADQUSERS' + userId) as any)
  592. setUsersArr(data)
  593. }, [])
  594. // 切换投放模式
  595. const switchLaunchMode = () => {
  596. if (launchMode === 1) {
  597. setLaunchMode(2)
  598. localStorage.setItem('LAUNCHMODE', '2')
  599. } else {
  600. setLaunchMode(1)
  601. localStorage.setItem('LAUNCHMODE', '1')
  602. }
  603. delBdPlan()
  604. set_targetKey('0')
  605. }
  606. /** 获取分组里账号 */
  607. const getGroupAccountList = (ids: number[]) => {
  608. if (ids.length > 0) {
  609. let data = ids.map(id => getAccountListApi(id))
  610. Promise.all(data).then(res => {
  611. if (res?.length > 0 && res.every((item: { code: number }) => item.code === 200)) {
  612. let userArr: any[] = []
  613. res.forEach((item: { data: { adAccountList: { accountId: number, id: number }[] } }) => {
  614. item.data.adAccountList.forEach(acc => {
  615. let obj = userArr.find((item: { accountId: number }) => item.accountId === acc.accountId)
  616. if (!obj) {
  617. userArr.push(acc)
  618. }
  619. })
  620. })
  621. setAccountCreateLogs(userArr?.map((item) => ({ adAccountId: item?.accountId, id: item.id })))
  622. clearData()
  623. } else {
  624. message.error('操作异常')
  625. }
  626. })
  627. } else {
  628. setAccountCreateLogs([])
  629. }
  630. }
  631. return <Space direction="vertical" style={{ width: '100%' }}>
  632. <Card
  633. title={<Space>
  634. <div className={style.cardTitle}>配置区</div>
  635. <Popconfirm
  636. title="数据部分不会保存,是否切换?"
  637. onConfirm={switchLaunchMode}
  638. okText="是"
  639. cancelText="否"
  640. >
  641. <Button type="link" style={{ padding: 0 }}>切换投放模式</Button>
  642. </Popconfirm>
  643. </Space>}
  644. className={style.createAd}
  645. hoverable
  646. // extra={<AddGroup onChange={usersChange} pitcherData={getAdAccount?.data?.data} />}
  647. >
  648. <Space wrap>
  649. <Selector label="媒体账户组">
  650. <Select
  651. mode="multiple"
  652. style={{ minWidth: 200 }}
  653. placeholder="快捷选择媒体账户组"
  654. maxTagCount={1}
  655. allowClear
  656. bordered={false}
  657. filterOption={(input: any, option: any) => {
  658. return option!.children?.toString().toLowerCase().includes(input.toLowerCase())
  659. }}
  660. onChange={(e, option) => { getGroupAccountList(e) }}
  661. >
  662. {getGroupList.data?.map((item: any) => <Select.Option value={item.groupId} key={item.groupId}>{item.groupName}</Select.Option>)}
  663. </Select>
  664. </Selector>
  665. <Selector label="媒体账户">
  666. <Select
  667. mode="multiple"
  668. style={{ minWidth: 200 }}
  669. placeholder="请选择媒体账户"
  670. maxTagCount={1}
  671. allowClear
  672. bordered={false}
  673. filterOption={(input: any, option: any) => {
  674. return option!.children?.toString().toLowerCase().includes(input.toLowerCase())
  675. }}
  676. value={accountCreateLogs?.map((item: { id: number }) => item?.id)}
  677. onChange={(e, option) => {
  678. console.log(option)
  679. setQueryForm({ ...queryForm, adqPageList: [], pageList: [], taskMediaMaps: queryForm?.taskMediaMaps?.map((item: { sysPageId: number }) => ({ ...item, sysPageId: '', accountPageIdMap: {}, cropUserGroupMap: [] })) })
  680. setAccountCreateLogs(option?.map((item: any) => ({ adAccountId: item?.children?.toString()?.split('——')[0], id: item?.value })))
  681. clearData()
  682. }}
  683. >
  684. {getAdAccount?.data?.data?.map((item: any) => <Select.Option value={item.id} key={item.id}>{item.remark ? item.accountId + '——' + item.remark : item.accountId}</Select.Option>)}
  685. </Select>
  686. </Selector>
  687. <Selector label="推广目标">
  688. <Select style={{ width: 200 }} value={queryForm?.promotedObjectType} placeholder="请选择推广目标" bordered={false} showSearch filterOption={(input: any, option: any) =>
  689. (option!.children as unknown as string).toLowerCase().includes(input.toLowerCase())
  690. } onChange={(e) => { setQueryForm({ ...queryForm, promotedObjectType: e, sysAdgroup: null, sysAdgroupId: undefined, taskMediaMaps: [], sysAdcreativeId: undefined, materials: [], textData: [], texts: [] }); clearData() }}>
  691. {Object.keys(PromotedObjectType).map(key => {
  692. return <Select.Option value={key} key={key}>{PromotedObjectType[key]}</Select.Option>
  693. })}
  694. </Select>
  695. </Selector>
  696. {launchMode === 2 && accountCreateLogs?.length > 0 && <>
  697. <Button onClick={() => { setGoodsVisible(true) }}>商品广告(选填){accountCreateLogs?.some(item => item?.productList?.length) && <CheckOutlined style={{ color: '#1890ff' }} />}</Button>
  698. <Button onClick={() => { setSourceVisible(true) }}>精准匹配归因(选填){accountCreateLogs?.some(item => item?.userActionSetsList?.length) && <CheckOutlined style={{ color: '#1890ff' }} />}</Button>
  699. </>}
  700. </Space>
  701. <div className={style.cardBody}>
  702. <Row className={style.content}>
  703. <Col span={launchMode === 1 ? 12 : 8} xl={launchMode === 1 ? 12 : 8} lg={24} md={24} sm={24} xs={24} className={style.conLeft}>
  704. <Row className={`${style.conTitle} ${style.conRightBorder}`}><Col span={24}>广告</Col></Row>
  705. <Row className={style.items}>
  706. {/* =============广告基本信息=========== */}
  707. <Ad queryForm={queryForm} setQueryForm={setQueryForm} getSysAdgroups={getSysAdgroups} clearData={clearData} />
  708. {/* =============定向包=========== */}
  709. <TargetIng
  710. queryForm={queryForm}
  711. setQueryForm={setQueryForm}
  712. getSysAdgroups={getSysAdgroups}
  713. clearData={clearData}
  714. setAccountCreateLogs={setAccountCreateLogs}
  715. getsysTargeting={getsysTargeting}
  716. geoLocationList={geoLocationList}
  717. modelList={modelList}
  718. cpDel={cpDel}
  719. accountCreateLogs={accountCreateLogs}
  720. />
  721. {launchMode === 1 && <>
  722. {/* =============商品=========== */}
  723. <Col className={style.conRightBorder} span={5}>
  724. <div className={style.top}>
  725. 商品
  726. </div>
  727. <div className={style.center}>
  728. <div className={style.centerContent}>
  729. {accountCreateLogs?.map((item: any, index: number) => {
  730. if (item?.productList) {
  731. return <div className={style.acc} key={index}>
  732. <div className={style.accName} style={{ fontWeight: 800 }}>{item.adAccountId}</div>
  733. {
  734. item?.productList?.map((pack: { productName: string, author: string, id: number }, index: number) => {
  735. return <div className={style.accCon} key={pack.id}>{pack.productName}<CloseOutlined className={style.close} onClick={() => {
  736. goodsDel(index)
  737. }} /></div>
  738. })
  739. }
  740. </div>
  741. } else {
  742. return null
  743. }
  744. })}
  745. </div>
  746. </div>
  747. <div className={style.bottom}>
  748. {accountCreateLogs?.length > 0 ? <span onClick={() => { setGoodsVisible(true) }}>编辑</span> : <Tooltip title="请先选择媒体账户">
  749. <span>编辑</span>
  750. </Tooltip>}
  751. </div>
  752. </Col>
  753. {/* 数据源 */}
  754. <Col className={style.conRightBorder} span={5}>
  755. <div className={style.top}>
  756. 数据源
  757. </div>
  758. <div className={style.center}>
  759. <div className={style.centerContent}>
  760. {accountCreateLogs?.map((item: any, index: number) => {
  761. if (item?.userActionSetsList && item?.userActionSetsList?.length > 0) {
  762. return <div className={style.acc} key={index}>
  763. <div className={style.accName} style={{ fontWeight: 800 }}>{item.adAccountId}</div>
  764. {
  765. item?.userActionSetsList?.map((pack: { name: string, type: string, id: number }, index1: number) => {
  766. return <div className={style.accCon} key={pack.id}> <span className={style.title}>{pack.name}{' > '}{pack.type?.replace('USER_ACTION_SET_TYPE_', '')}</span> <CloseOutlined className={style.close} onClick={() => {
  767. sourceDel(index, index1)
  768. }} /></div>
  769. })
  770. }
  771. </div>
  772. } else {
  773. return null
  774. }
  775. })}
  776. </div>
  777. </div>
  778. <div className={style.bottom}>
  779. {accountCreateLogs?.length > 0 ? <span onClick={() => { setSourceVisible(true) }}>编辑</span> : <Tooltip title="请先选择媒体账户">
  780. <span>编辑</span>
  781. </Tooltip>}
  782. </div>
  783. </Col>
  784. </>}
  785. </Row>
  786. </Col>
  787. {/* =============广告创意=========== */}
  788. {launchMode === 1 ? <Col span={12} xl={12} lg={24} md={24} sm={24} xs={24} className={style.conRight}>
  789. <Row className={style.conTitle}><Col span={24}>广告创意</Col></Row>
  790. <Row className={style.items}>
  791. {/* 创意 */}
  792. <Creative queryForm={queryForm} setQueryForm={setQueryForm} getSysAdgroups={getSysAdgroups} clearData={clearData} getSysAdcreative={getSysAdcreative} set_targetKey={set_targetKey} targetKey={targetKey} page_checked={page_checked} />
  793. {/* 落地页 */}
  794. <Col span={12} >
  795. <div className={style.top}>
  796. 落地页
  797. {(queryForm?.taskMediaMaps && queryForm?.taskMediaMaps[targetKey]?.cropUserGroupMap?.length > 0) && <CustomerServiceModal data={queryForm?.taskMediaMaps[targetKey]?.cropUserGroupMap} onChange={(data) => {
  798. let newQueryForm = JSON.parse(JSON.stringify(queryForm))
  799. newQueryForm.taskMediaMaps[targetKey].cropUserGroupMap = data
  800. setQueryForm(newQueryForm)
  801. }} />}
  802. </div>
  803. <div className={style.center}>
  804. <Tabs size={'small'} onEdit={onEdit} type="editable-card" activeKey={targetKey} onChange={(key) => { set_targetKey(key) }} hideAdd >
  805. {
  806. queryForm?.taskMediaMaps?.map((item, index) => {
  807. return <Tabs.TabPane tab={'创意' + (index + 1)} key={index} >
  808. <Spin spinning={get.loading}>
  809. <div className={style.centerContent}>
  810. {
  811. item?.sysPageId || item?.accountPageIdMap ? <>
  812. {
  813. (item?.sysPageId && queryForm?.pageList) && <>
  814. <div>落地页名称:{queryForm?.pageList[targetKey]?.pageName || ''}</div>
  815. <div>分享名称:{queryForm?.pageList[targetKey]?.shareContentSpec?.shareTitle || ''}</div>
  816. <div>分享描述:{queryForm?.pageList[targetKey]?.shareContentSpec?.shareDescription || ''}</div>
  817. <div style={{ marginBottom: 10 }}>原生推广页顶部素材预览:
  818. <div>{queryForm?.pageList[targetKey]?.pageSpecsList && queryForm?.pageList[targetKey]?.pageSpecsList[0]?.pageElementsSpecList?.filter((item: any, index: number) => index === 0)?.map((item: { elementType: 'TOP_IMAGE' | 'TOP_VIDEO' | 'TOP_SLIDER', topImageSpec: any, topSliderSpec: any, topVideoSpec: any }, index: number) => {
  819. switch (item?.elementType) {
  820. case 'TOP_IMAGE':
  821. return <Image width={80} src={item?.topImageSpec?.imageUrl} style={{ borderRadius: 8, overflow: 'hidden' }} key={index} />
  822. case 'TOP_SLIDER':
  823. return <Space wrap key={index}>
  824. {item?.topSliderSpec?.imageUrlList?.map((url: string, index: number) => <Image width={70} src={url} style={{ borderRadius: 8 }} key={'TOP_SLIDER' + index} />)}
  825. </Space>
  826. case 'TOP_VIDEO':
  827. return <video src={item?.topVideoSpec?.videoUrl} width={150} controls key={index}></video>
  828. }
  829. })}</div>
  830. </div>
  831. </>
  832. }
  833. {
  834. queryForm?.adqPageList && queryForm?.adqPageList[targetKey]?.map((adq: any) => {
  835. return <div className={style.acc} key={adq.adAccountId}>
  836. <div className={style.accName} style={{ fontWeight: 800 }}>{adq.adAccountId}</div>
  837. <div className={style.accCon}>
  838. <span className={style.title}>{adq.pageList[0].pageName}</span>
  839. </div>
  840. </div>
  841. })
  842. }
  843. </> : <Empty image={Empty.PRESENTED_IMAGE_SIMPLE} />}
  844. </div>
  845. </Spin>
  846. </Tabs.TabPane>
  847. })
  848. }
  849. </Tabs>
  850. </div>
  851. <div className={style.bottom}>{
  852. (queryForm?.taskMediaMaps && queryForm?.taskMediaMaps[targetKey]?.sysAdcreative) ? <>
  853. {queryForm?.taskMediaMaps && queryForm?.taskMediaMaps[targetKey]?.sysPageId && <Button type="link" onClick={() => { setLookVisible(true) }}>查看</Button>}
  854. <Button type="link" onClick={() => {
  855. setSelectImgVisible(true)
  856. // 判定是否用原生页顶部替换外部素材
  857. if (queryForm?.taskMediaMaps && queryForm?.taskMediaMaps[targetKey]?.sysAdcreative?.overrideCanvasHeadOption === 'OPTION_CANVAS_OVERRIDE_CREATIVE') {
  858. init({ mediaType: 'PAGE', cloudSize: undefined, adcreativeTemplateId: queryForm?.taskMediaMaps[targetKey]?.sysAdcreative?.adcreativeTemplateId })
  859. } else {
  860. init({ mediaType: 'PAGE', cloudSize: undefined })
  861. }
  862. }}>{queryForm?.taskMediaMaps && queryForm?.taskMediaMaps[targetKey]?.sysPageId ? '修改' : '选择落地页'}</Button>
  863. {accountCreateLogs?.length > 0 ? <Button type="link" onClick={() => {
  864. setPageVisible(true)
  865. if (queryForm?.taskMediaMaps && queryForm?.taskMediaMaps[targetKey]?.sysAdcreative?.overrideCanvasHeadOption === 'OPTION_CANVAS_OVERRIDE_CREATIVE') {
  866. setCloudParams({ adcreativeTemplateId: queryForm?.taskMediaMaps[targetKey]?.sysAdcreative?.adcreativeTemplateId })
  867. } else {
  868. setCloudParams({})
  869. }
  870. }}>云端落地页</Button> : <Tooltip title="请先选择媒体账户">
  871. <Button type="link">云端落地页</Button>
  872. </Tooltip>}
  873. </> : <Tooltip title="请先设置创意">
  874. <Button type="link"><span>选择落地页</span></Button>
  875. </Tooltip>}
  876. </div>
  877. </Col>
  878. </Row>
  879. </Col> : <Col span={16} xl={16} lg={24} md={24} sm={24} xs={24} className={style.conRight}>
  880. <Row className={style.conTitle}><Col span={24}>广告创意</Col></Row>
  881. <Row className={style.items}>
  882. {/* 创意 */}
  883. <CreativeCL queryForm={queryForm} setQueryForm={setQueryForm} clearData={clearData} getSysAdcreative={getSysAdcreative} targetKey={targetKey} />
  884. {/* 落地页 */}
  885. <Col className={style.conRightBorder} style={{ maxWidth: '25%', border: 'none' }}>
  886. <div className={style.top}>
  887. 落地页
  888. {(queryForm?.taskMediaMaps && queryForm?.taskMediaMaps[targetKey]?.cropUserGroupMap?.length > 0) && <CustomerServiceModal data={queryForm?.taskMediaMaps[targetKey]?.cropUserGroupMap} onChange={(data) => {
  889. let newQueryForm = JSON.parse(JSON.stringify(queryForm))
  890. newQueryForm.taskMediaMaps[targetKey].cropUserGroupMap = data
  891. setQueryForm(newQueryForm)
  892. }} />}
  893. </div>
  894. <div className={style.center}>
  895. {queryForm?.taskMediaMaps?.filter((item, index) => index === 0)?.map((item, index) => {
  896. return <Spin spinning={get.loading} key={index}>
  897. <div className={style.centerContent}>
  898. {item?.sysPageId || item?.accountPageIdMap ? <>
  899. {(item?.sysPageId && queryForm?.pageList) && <>
  900. <div>落地页名称:{queryForm?.pageList[targetKey]?.pageName || ''}</div>
  901. <div>分享名称:{queryForm?.pageList[targetKey]?.shareContentSpec?.shareTitle || ''}</div>
  902. <div>分享描述:{queryForm?.pageList[targetKey]?.shareContentSpec?.shareDescription || ''}</div>
  903. <div style={{ marginBottom: 10 }}>原生推广页顶部素材预览:
  904. <div>{queryForm?.pageList[targetKey]?.pageSpecsList && queryForm?.pageList[targetKey]?.pageSpecsList[0]?.pageElementsSpecList?.filter((item: any, index: number) => index === 0)?.map((item: { elementType: 'TOP_IMAGE' | 'TOP_VIDEO' | 'TOP_SLIDER', topImageSpec: any, topSliderSpec: any, topVideoSpec: any }, index: number) => {
  905. switch (item?.elementType) {
  906. case 'TOP_IMAGE':
  907. return <Image width={80} src={item?.topImageSpec?.imageUrl} style={{ borderRadius: 8, overflow: 'hidden' }} key={index} />
  908. case 'TOP_SLIDER':
  909. return <Space wrap key={index}>
  910. {item?.topSliderSpec?.imageUrlList?.map((url: string, index: number) => <Image width={70} src={url} style={{ borderRadius: 8 }} key={'TOP_SLIDER' + index} />)}
  911. </Space>
  912. case 'TOP_VIDEO':
  913. return <video src={item?.topVideoSpec?.videoUrl} width={150} controls key={index}></video>
  914. }
  915. })}</div>
  916. </div>
  917. </>}
  918. {queryForm?.adqPageList && queryForm?.adqPageList[targetKey]?.map((adq: any) => {
  919. return <div className={style.acc} key={adq.adAccountId}>
  920. <div className={style.accName} style={{ fontWeight: 800 }}>{adq.adAccountId}</div>
  921. <div className={style.accCon}>
  922. <span className={style.title}>{adq.pageList[0].pageName}</span>
  923. </div>
  924. </div>
  925. })}
  926. </> : <Empty image={Empty.PRESENTED_IMAGE_SIMPLE} />}
  927. </div>
  928. </Spin>
  929. })}
  930. </div>
  931. <div className={style.bottom}>{
  932. (queryForm?.taskMediaMaps && queryForm?.taskMediaMaps[targetKey]?.sysAdcreative) ? <>
  933. {queryForm?.taskMediaMaps && queryForm?.taskMediaMaps[targetKey]?.sysPageId && <Button type="link" onClick={() => { setLookVisible(true) }}>查看</Button>}
  934. <Button type="link" onClick={() => {
  935. setSelectImgVisible(true)
  936. // 判定是否用原生页顶部替换外部素材
  937. if (queryForm?.taskMediaMaps && queryForm?.taskMediaMaps[targetKey]?.sysAdcreative?.overrideCanvasHeadOption === 'OPTION_CANVAS_OVERRIDE_CREATIVE') {
  938. init({ mediaType: 'PAGE', cloudSize: undefined, adcreativeTemplateId: queryForm?.taskMediaMaps[targetKey]?.sysAdcreative?.adcreativeTemplateId })
  939. } else {
  940. init({ mediaType: 'PAGE', cloudSize: undefined })
  941. }
  942. }}>{queryForm?.taskMediaMaps && queryForm?.taskMediaMaps[targetKey]?.sysPageId ? '修改' : '选择落地页'}</Button>
  943. {accountCreateLogs?.length > 0 ? <Button type="link" onClick={() => {
  944. setPageVisible(true)
  945. if (queryForm?.taskMediaMaps && queryForm?.taskMediaMaps[targetKey]?.sysAdcreative?.overrideCanvasHeadOption === 'OPTION_CANVAS_OVERRIDE_CREATIVE') {
  946. setCloudParams({ adcreativeTemplateId: queryForm?.taskMediaMaps[targetKey]?.sysAdcreative?.adcreativeTemplateId })
  947. } else {
  948. setCloudParams({})
  949. }
  950. }}>云端落地页</Button> : <Tooltip title="请先选择媒体账户">
  951. <Button type="link">云端落地页</Button>
  952. </Tooltip>}
  953. </> : <Tooltip title="请先设置创意">
  954. <Button type="link"><span>选择落地页</span></Button>
  955. </Tooltip>}
  956. </div>
  957. </Col>
  958. </Row>
  959. </Col>}
  960. </Row>
  961. {/* =============广告底部按钮=========== */}
  962. <Space className={style.bts}>
  963. <Button type='primary' onClick={severBd}>存为预设</Button>
  964. <Button type='primary' onClick={preview}><SearchOutlined /> 批量预览广告</Button>
  965. <Button onClick={delBdPlan}>清空配置/预设</Button>
  966. </Space>
  967. </div>
  968. </Card>
  969. <Card
  970. className={style.createAd}
  971. hoverable
  972. extra={tableData?.length > 0 ? <Space>
  973. <span>推广计划总数:{tableData?.length}</span>
  974. <span>广告总数:{tableData?.length}</span>
  975. {/* {tableSelect?.length > 0 && <span> 已选:<span style={{ color: '#1890FF' }}>{tableSelect?.length}</span> 条</span>} */}
  976. {
  977. <Button type='primary' onClick={() => {
  978. // if (tableSelect.length === 0) {
  979. // message.error('请选择要提交的计划!')
  980. // return
  981. // };
  982. setSubVisible(true)
  983. }}>批量提交审核</Button>
  984. }
  985. </Space> : false
  986. }
  987. >
  988. {tableData?.length > 0 ? <div className={style.cardBody}>
  989. <div className={style.content} style={{ marginTop: 20 }}>
  990. <Tables
  991. columns={columns()}
  992. dataSource={tableData}
  993. total={0}
  994. size="small"
  995. bordered
  996. scroll={{ x: 2000 }}
  997. myKey={'myId'}
  998. // rowSelection={{
  999. // selectedRowKeys: tableSelect?.map((item: any) => item?.myId.toString()),
  1000. // onChange: (selectedRowKeys: React.Key[], selectedRows: any) => {
  1001. // setTableSelect(selectedRows)
  1002. // }
  1003. // }}
  1004. />
  1005. </div>
  1006. </div> : <div style={{ minHeight: 400, display: 'flex', justifyContent: 'center', alignItems: 'center' }}>
  1007. <Empty description="请先完成模块配置后,再预览广告计划" />
  1008. </div>}
  1009. </Card>
  1010. {/* 选择商品 */}
  1011. {goodsVisible && <GoodsModal visible={goodsVisible} data={accountCreateLogs} onClose={() => setGoodsVisible(false)} onChange={(e) => { setAccountCreateLogs(e); setGoodsVisible(false); clearData() }} />}
  1012. {/* 选择数据源 */}
  1013. {sourceVisible && <DataSourceModal visible={sourceVisible} promotedObjectType={queryForm.promotedObjectType} data={accountCreateLogs} onClose={() => setSourceVisible(false)} onChange={(e) => { setAccountCreateLogs(e); setSourceVisible(false); clearData() }} />}
  1014. {/* 选择转化ID */}
  1015. {idVisible && <IdModal visible={idVisible} data={accountCreateLogs} onClose={() => setIdVisible(false)} onChange={(e) => { setAccountCreateLogs(e); setSourceVisible(false); clearData() }} />}
  1016. {/* 选择ADQ落地页 */}
  1017. {pageVisible && <PageModal cloudParams={cloudParams} visible={pageVisible} data={accountCreateLogs} onClose={() => setPageVisible(false)} onChange={(e) => { setAdqPage(e); setPageVisible(false); clearData() }} />}
  1018. {/* 选择素材 */}
  1019. {selectImgVisible && <SelectCloud visible={selectImgVisible} onClose={() => setSelectImgVisible(false)} onChange={setPage} isBack={false} />}
  1020. {/* 查看落地页 */}
  1021. {lookVisible && <LookLanding visible={lookVisible} onClose={() => setLookVisible(false)} id={queryForm?.taskMediaMaps && queryForm?.taskMediaMaps[targetKey].sysPageId} />}
  1022. {/* 设置名称 */}
  1023. {subVisible && <SubmitModal data={getSysAdgroups?.data} visible={subVisible} onClose={() => setSubVisible(false)} onChange={submit} ajax={createAdBatch} />}
  1024. </Space>
  1025. }
  1026. export default CreateAd