index.tsx 40 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654
  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 { CloseOutlined, EditOutlined, QuestionCircleOutlined, SearchOutlined } from "@ant-design/icons"
  10. import { Button, Card, Col, Empty, Row, Select, Space, Spin, Tooltip, Image, message, Popover } from "antd"
  11. import React, { useEffect, useRef, useState } from "react"
  12. import { useModel } from "umi"
  13. import AdModal from "../../components/adModal"
  14. import CreativeModal from "../../components/creativeModal"
  15. import CrowdPackModal from "../../components/crowdPackModal"
  16. import DataSourceModal from "../../components/dataSourceModal"
  17. import GoodsModal from "../../components/goodsModal"
  18. import IdModal from "../../components/idModal"
  19. import LookLanding from "../../components/lookLanding"
  20. import PageModal from "../../components/pageModal"
  21. import SelectCloud from "../../components/selectCloud"
  22. import TargetingModal from "../../components/targetingModal"
  23. import TargetingTooltip from "../../components/targetingTooltip"
  24. import { WxAutoButton } from "../../req"
  25. import AdcreativeCol from "./adcreativeCol"
  26. import AdgroupsCol from "./adgroupsCol"
  27. import style from './index.less'
  28. import Selector from "./selector"
  29. import SubmitModal from "./submitModal"
  30. import columns from "./tableConfig"
  31. const CreateAd: React.FC = () => {
  32. /*************************/
  33. const { getAdAccount } = useModel('useLaunchAdq.useAdAuthorize')
  34. const [queryForm, setQueryForm] = useState<Partial<CreateAdProps>>({
  35. campaignName: '', // 计划名称
  36. campaignType: 'CAMPAIGN_TYPE_NORMAL', // 计划类型 CAMPAIGN_TYPE_NORMAL CAMPAIGN_TYPE_SEARCH
  37. promotedObjectType: 'PROMOTED_OBJECT_TYPE_WECHAT_OFFICIAL_ACCOUNT', // 推广目标类型
  38. speedMode: 'SPEED_MODE_STANDARD', // 投放速度模式
  39. sysAdgroupId: undefined, // 广告组内容
  40. sysTargetingId: undefined, // 定向包 id
  41. adgroupName: undefined, // 广告名称
  42. configuredStatus: 'AD_STATUS_SUSPEND', // 广告状态
  43. sysAdcreativeId: undefined, // 创意ID
  44. sysPageId: undefined, // 落地页Id
  45. })
  46. const [accountCreateLogs, setAccountCreateLogs] = useState<{ adAccountId: number, id: number, userActionSetsList?: number, productList?: any, conversionList?: any, customAudienceList?: any, excludedCustomAudienceList?: any, pageList?: any }[]>([]) // 账户
  47. const [adVisible, setAdVisible] = useState<boolean>(false) // 选择广告弹窗控制
  48. const [dxVisible, setDxVisible] = useState<boolean>(false) // 选择定向弹窗控制
  49. const [creativeVisible, setCreativeVisible] = useState<boolean>(false) // 选择创意弹窗控制
  50. const [goodsVisible, setGoodsVisible] = useState<boolean>(false) // 选择商品弹窗控制
  51. const [sourceVisible, setSourceVisible] = useState<boolean>(false) // 选择数据源弹窗控制
  52. const [idVisible, setIdVisible] = useState<boolean>(false) // 选择转化ID弹窗控制
  53. const [selectImgVisible, setSelectImgVisible] = useState<boolean>(false) // 选择转化ID弹窗控制
  54. const [lookVisible, setLookVisible] = useState<boolean>(false) // 选择转化ID弹窗控制
  55. const [subVisible, setSubVisible] = useState<boolean>(false) // 选择设置名称弹窗控制
  56. const [cpVisible, setCpVisible] = useState<boolean>(false) // 选择设置名称弹窗控制
  57. const [pageVisible, setPageVisible] = useState<boolean>(false) // 选择云端落地页控制
  58. const [wxButtonList, setWxButtonList] = useState<WxAutoButton[]>([])
  59. const [tableData, setTableData] = useState<any[]>([]) // 预览表格
  60. const [tableSelect, setTableSelect] = useState<any[]>([])
  61. const [geoLocationList, setGeoLocationList] = useState<any>({}) // 所有地域列表
  62. const [modelList, setModelList] = useState<any>({}) // 所有品牌手机
  63. const { init, get } = useModel('useLaunchAdq.useBdMediaPup')
  64. const tagsList_REGION = useAjax((params) => getTagsList(params))
  65. const tagsList_MODEL = useAjax((params) => getTagsList(params))
  66. const getSysAdgroups = useAjax((params) => getSysAdgroupsInfo(params))
  67. const getsysTargeting = useAjax((params) => getsysTargetingInfo(params))
  68. const getSysAdcreative = useAjax((params) => getSysAdcreativeInfo(params))
  69. const createAdBatch = useAjax((params) => createAdBatchApi(params))
  70. /*************************/
  71. /**数据回填 */
  72. useEffect(() => {
  73. let adqAdData = localStorage.getItem('ADQAD')
  74. if (adqAdData) {
  75. const { queryForm, accountCreateLogs } = JSON.parse(adqAdData)
  76. setQueryForm({ ...queryForm })
  77. setAccountCreateLogs(accountCreateLogs)
  78. }
  79. }, [])
  80. // 设置地域
  81. useEffect(() => {
  82. tagsList_REGION.run({ type: 'REGION' }).then(res => {
  83. if (res) {
  84. setGeoLocationList(() => (res as any[])?.reduce((prev: any, cur: { id: number }) => {
  85. prev[cur.id] = cur
  86. return prev
  87. }, {}))
  88. }
  89. })
  90. tagsList_MODEL.run({ type: 'DEVICE_BRAND_MODEL' }).then(res => {
  91. if (res) {
  92. setModelList(() => (res as any[])?.reduce((prev: any, cur: { id: number }) => {
  93. prev[cur.id] = cur
  94. return prev
  95. }, {}))
  96. }
  97. })
  98. }, [])
  99. // 获取账户列表
  100. useEffect(() => {
  101. getAdAccount.run()
  102. init({ mediaType: 'PAGE' })
  103. }, [])
  104. /** 获取广告详情 */
  105. useEffect(() => {
  106. if (queryForm?.sysAdgroupId) {
  107. getSysAdgroups.run(queryForm?.sysAdgroupId)
  108. }
  109. }, [queryForm?.sysAdgroupId])
  110. useEffect(() => {
  111. if (getSysAdgroups?.data?.bidMode !== 'BID_MODE_CPM' && accountCreateLogs?.length > 0) {
  112. let newAccountCreateLogs = accountCreateLogs?.map((item: any) => {
  113. if (item?.customAudienceList) {
  114. delete item?.customAudienceList
  115. }
  116. return { ...item }
  117. })
  118. setAccountCreateLogs([...newAccountCreateLogs])
  119. }
  120. }, [getSysAdgroups?.data?.bidMode])
  121. /** 获取创意详情 */
  122. useEffect(() => {
  123. if (queryForm?.sysAdcreativeId) {
  124. getSysAdcreative.run(queryForm?.sysAdcreativeId)
  125. }
  126. }, [queryForm?.sysAdcreativeId])
  127. /** 获取定向详情 */
  128. useEffect(() => {
  129. if (queryForm?.sysTargetingId) {
  130. getsysTargeting.run(queryForm?.sysTargetingId)
  131. }
  132. }, [queryForm?.sysTargetingId])
  133. /** 获取落地页详情 */
  134. useEffect(() => {
  135. if (queryForm?.sysPageId) {
  136. get.run({ mediaType: 'PAGE', sysMediaId: queryForm?.sysPageId }).then(res => {
  137. if (!Object.keys(res)?.includes('fail')) {
  138. let data = res
  139. let pageElementsSpecList = data?.pageSpecsList[0]?.pageElementsSpecList
  140. setWxButtonList(() => (pageElementsSpecList as any[])?.filter((item: { elementType: string }) => item?.elementType === 'ENTERPRISE_WX'))
  141. } else {
  142. setQueryForm({ ...queryForm, sysPageId: undefined })
  143. }
  144. })
  145. }
  146. }, [queryForm?.sysPageId])
  147. /** 删除商品内容 */
  148. const goodsDel = (index: number) => {
  149. let newArr = JSON.parse(JSON.stringify(accountCreateLogs))
  150. delete newArr[index].productList
  151. setAccountCreateLogs(newArr)
  152. }
  153. /** 删除云端内容 */
  154. const pageDel = (index: number) => {
  155. let newArr = JSON.parse(JSON.stringify(accountCreateLogs))
  156. delete newArr[index].pageList
  157. setAccountCreateLogs(newArr)
  158. }
  159. /** 删除数据源 */
  160. const sourceDel = (index: number, num: number) => {
  161. let newArr = JSON.parse(JSON.stringify(accountCreateLogs))
  162. newArr[index].userActionSetsList?.splice(num, 1)
  163. setAccountCreateLogs(newArr)
  164. }
  165. /** 删除人群包 */
  166. const cpDel = (index: number, num: number, key: string) => {
  167. let newArr = JSON.parse(JSON.stringify(accountCreateLogs))
  168. newArr[index][key]?.splice(num, 1)
  169. setAccountCreateLogs(newArr)
  170. }
  171. /** 设置落地页 */
  172. const setPage = (e: any) => {
  173. setQueryForm({ ...queryForm, sysPageId: e[0]?.id || undefined })
  174. setSelectImgVisible(false)
  175. }
  176. /** 预览 */
  177. const preview = () => {
  178. if (accountCreateLogs?.length === 0) {
  179. message.error('请选择媒体账户')
  180. return
  181. }
  182. if (!queryForm.promotedObjectType) {
  183. message.error('请选择推广目标')
  184. return
  185. }
  186. if (!queryForm.sysAdgroupId) {
  187. message.error('请先设置广告基本信息')
  188. return
  189. }
  190. if (!queryForm.sysTargetingId) {
  191. message.error('请选择定向')
  192. return
  193. }
  194. if (!queryForm.sysAdcreativeId) {
  195. message.error('请设置创意的基本信息')
  196. return
  197. }
  198. if (!accountCreateLogs?.every((item: any) => item.pageList?.length > 0)) { // 所有都选云端
  199. if (!queryForm.sysPageId) {
  200. message.error('请选择落地页')
  201. return
  202. }
  203. }
  204. let data = accountCreateLogs.map((item: any, index) => {
  205. return { ...item, ...queryForm, sysAdGroupData: getSysAdgroups?.data, targetingData: getsysTargeting?.data, sysAdcreativeData: { ...getSysAdcreative?.data }, pageData: get?.data }
  206. })
  207. console.log('data--->', data)
  208. setTableData(data)
  209. }
  210. const submit = (data: { adgroupName: string, campaignName: string }) => {
  211. console.log(111111, tableSelect);
  212. let params = { ...queryForm, ...data }
  213. let accountLogs = tableSelect.map((item: any) => {
  214. // userActionSetsList 数据源 productList 商品
  215. let data: any = { adAccountId: item.id }
  216. if (item?.userActionSetsList?.length > 0) { // 数据源
  217. data.userActionSets = item?.userActionSetsList?.map((item: any) => ({ id: item?.id, type: item?.type }))
  218. }
  219. if (item?.productList?.length > 0) { // 商品
  220. data.productId = item?.productList[0].productOuterId
  221. data.productCatalogId = item?.productList[0].productCatalogId
  222. }
  223. if (item?.customAudienceList?.length > 0) {
  224. data.customAudience = item?.customAudienceList?.map((item: any) => item.id)
  225. }
  226. if (item?.excludedCustomAudienceList?.length > 0) {
  227. data.excludedCustomAudience = item?.excludedCustomAudienceList?.map((item: any) => item.id)
  228. }
  229. if (item?.pageList) {
  230. data.pageId = item?.pageList[0].id
  231. }
  232. return data
  233. })
  234. params.accountCreateLogs = accountLogs
  235. createAdBatch.run(params).then(res => {
  236. if (res) {
  237. sessionStorage.setItem('CAMP', data?.campaignName)
  238. message.success('创建成功')
  239. window.location.href = '/#/launchSystemNew/launchManage/taskList'
  240. }
  241. })
  242. }
  243. /** 清除数据 */
  244. const clearData = () => {
  245. setTableData([])
  246. setTableSelect([])
  247. }
  248. /** 存为预设 */
  249. const severBd = () => {
  250. // queryForm accountCreateLogs
  251. localStorage.setItem('ADQAD', JSON.stringify({
  252. queryForm,
  253. accountCreateLogs
  254. }))
  255. message.success('存储成功')
  256. }
  257. /** 清除 */
  258. const delBdPlan = () => {
  259. localStorage.removeItem('ADQAD')
  260. setAccountCreateLogs([])
  261. setQueryForm({
  262. campaignName: '', // 计划名称
  263. campaignType: 'CAMPAIGN_TYPE_NORMAL', // 计划类型 CAMPAIGN_TYPE_NORMAL CAMPAIGN_TYPE_SEARCH
  264. promotedObjectType: 'PROMOTED_OBJECT_TYPE_WECHAT_OFFICIAL_ACCOUNT', // 推广目标类型
  265. speedMode: 'SPEED_MODE_STANDARD', // 投放速度模式
  266. sysAdgroupId: undefined, // 广告组内容
  267. sysTargetingId: undefined, // 定向包 id
  268. adgroupName: undefined, // 广告名称
  269. configuredStatus: 'AD_STATUS_SUSPEND', // 广告状态
  270. sysAdcreativeId: undefined, // 创意ID
  271. sysPageId: undefined, // 落地页Id
  272. })
  273. }
  274. return <Space direction="vertical" style={{ width: '100%' }}>
  275. <Card title={<div className={style.cardTitle}>配置区</div>} className={style.createAd} hoverable>
  276. <Space>
  277. <Selector label="媒体账户">
  278. <Select
  279. mode="multiple"
  280. style={{ minWidth: 200 }}
  281. placeholder="请选择媒体账户"
  282. maxTagCount={1}
  283. allowClear
  284. bordered={false}
  285. filterOption={(input: any, option: any) =>
  286. (option!.children as unknown as string).toLowerCase().includes(input.toLowerCase())
  287. }
  288. value={accountCreateLogs?.map((item: { id: number }) => item?.id)}
  289. onChange={(e, option) => {
  290. setAccountCreateLogs(option?.map((item: any) => ({ adAccountId: item?.children, id: item?.value })))
  291. clearData()
  292. }}
  293. >
  294. {getAdAccount?.data?.data?.map((item: any) => <Select.Option value={item.id} key={item.id}>{item.accountId}</Select.Option>)}
  295. {/* <Select.OptGroup label="Engineer">
  296. <Select.Option value="20632113">20632113</Select.Option>
  297. </Select.OptGroup> */}
  298. </Select>
  299. </Selector>
  300. <Selector label="推广目标">
  301. <Select style={{ width: 200 }} value={queryForm?.promotedObjectType} placeholder="请选择推广目标" bordered={false} showSearch filterOption={(input: any, option: any) =>
  302. (option!.children as unknown as string).toLowerCase().includes(input.toLowerCase())
  303. } onChange={(e) => { setQueryForm({ ...queryForm, promotedObjectType: e }); clearData() }}>
  304. {Object.keys(PromotedObjectType).map(key => {
  305. return <Select.Option value={key} key={key}>{PromotedObjectType[key]}</Select.Option>
  306. })}
  307. </Select>
  308. </Selector>
  309. </Space>
  310. <div className={style.cardBody}>
  311. <Row className={style.content}>
  312. <Col span={16} className={style.conLeft}>
  313. <Row className={`${style.conTitle} ${style.conRightBorder}`}><Col span={24}>广告</Col></Row>
  314. <Row className={style.items}>
  315. {/* =============广告基本信息=========== */}
  316. <Col className={style.conRightBorder}>
  317. <div className={style.top}>
  318. 广告基本信息
  319. </div>
  320. <div className={style.center}>
  321. <Spin spinning={getSysAdgroups.loading}>
  322. <div className={style.centerContent}>
  323. {(getSysAdgroups?.data && queryForm?.sysAdgroupId) ? <AdgroupsCol data={getSysAdgroups?.data} /> : <Empty image={Empty.PRESENTED_IMAGE_SIMPLE} />}
  324. </div>
  325. </Spin>
  326. </div>
  327. <div className={style.bottom}>
  328. {queryForm?.promotedObjectType ? <span onClick={() => { setAdVisible(true) }}>{getSysAdgroups?.data ? '修改' : '添加'}</span> : <Tooltip title="请先选择推广目标">
  329. <span>添加</span>
  330. </Tooltip>}
  331. </div>
  332. </Col>
  333. {/* =============定向包=========== */}
  334. <Col className={style.conRightBorder}>
  335. <div className={style.top}>
  336. 定向
  337. {getSysAdgroups?.data?.bidMode === 'BID_MODE_CPM' && <>{accountCreateLogs?.length > 0 && queryForm?.sysTargetingId ? <Button type="link" style={{ fontSize: 12, padding: 0 }} onClick={() => setCpVisible(true)}>选择定向包</Button> : <Tooltip title={accountCreateLogs?.length > 0 ? `请先添加定向` : `请先选择媒体账户`}>
  338. <Button type="link" style={{ fontSize: 12, padding: 0 }}>选择定向包</Button>
  339. </Tooltip>}</>}
  340. </div>
  341. <div className={style.center}>
  342. <Spin spinning={getsysTargeting.loading}>
  343. <div className={style.centerContent}>
  344. {queryForm?.sysTargetingId ? <>
  345. {accountCreateLogs?.some((item: any) => item?.customAudienceList?.length > 0) ? <>
  346. {getsysTargeting?.data && <Popover
  347. content={<div className={style.popover}>
  348. <TargetingTooltip data={getsysTargeting?.data} geoLocationList={geoLocationList} modelList={modelList} />
  349. </div>}
  350. trigger="hover"
  351. placement="right"
  352. >
  353. <div className={style.popoverContent}>
  354. <div>定向名称: <span>{getsysTargeting?.data?.targetingName}</span></div>
  355. <div>定向描述: <span>{getsysTargeting?.data?.description || '<空>'}</span></div>
  356. </div>
  357. </Popover>}
  358. {accountCreateLogs?.map((item: any, index: number) => {
  359. if (item?.customAudienceList) {
  360. return <div className={style.acc} key={index}>
  361. <div className={style.accName} style={{ fontWeight: 800 }}>{item.adAccountId}</div>
  362. {item?.customAudienceList?.length > 0 && <>
  363. <div className={style.accName}>定向用户群</div>
  364. {
  365. item?.customAudienceList?.map((pack: { name: string, id: number }, index1: number) => {
  366. return <div className={style.accCon} key={pack.id}>{pack.name}<CloseOutlined className={style.close} onClick={() => {
  367. cpDel(index, index1, 'customAudienceList')
  368. }} /></div>
  369. })
  370. }
  371. </>}
  372. {item?.excludedCustomAudienceList?.length > 0 && <>
  373. <div className={style.accName} style={{ marginTop: 5 }}>排除用户群</div>
  374. {
  375. item?.excludedCustomAudienceList?.map((pack: { name: string, id: number }, index1: number) => {
  376. return <div className={style.accCon} key={pack.id}>{pack.name}<CloseOutlined className={style.close} onClick={() => {
  377. cpDel(index, index1, 'excludedCustomAudienceList')
  378. }} /></div>
  379. })
  380. }
  381. </>}
  382. </div>
  383. } else {
  384. return null
  385. }
  386. })}
  387. </> : <>
  388. <div>定向名称: <span>{getsysTargeting?.data?.targetingName}</span></div>
  389. <div>定向描述: <span>{getsysTargeting?.data?.description || '<空>'}</span></div>
  390. <TargetingTooltip data={getsysTargeting?.data} geoLocationList={geoLocationList} modelList={modelList} />
  391. </>}
  392. </> : <Empty image={Empty.PRESENTED_IMAGE_SIMPLE} />}
  393. </div>
  394. </Spin>
  395. </div>
  396. <div className={style.bottom}><span onClick={() => { setDxVisible(true) }}>{getsysTargeting?.data ? '修改' : '添加'}</span></div>
  397. </Col>
  398. {/* =============商品=========== */}
  399. <Col className={style.conRightBorder}>
  400. <div className={style.top}>
  401. 商品{/* <span>已选:{1}</span> */}
  402. </div>
  403. <div className={style.center}>
  404. <div className={style.centerContent}>
  405. {accountCreateLogs?.map((item: any, index: number) => {
  406. if (item?.productList) {
  407. return <div className={style.acc} key={index}>
  408. <div className={style.accName} style={{ fontWeight: 800 }}>{item.adAccountId}</div>
  409. {
  410. item?.productList?.map((pack: { productName: string, author: string, id: number }, index: number) => {
  411. return <div className={style.accCon} key={pack.id}>{pack.productName}<CloseOutlined className={style.close} onClick={() => {
  412. goodsDel(index)
  413. }} /></div>
  414. })
  415. }
  416. </div>
  417. } else {
  418. return null
  419. }
  420. })}
  421. </div>
  422. </div>
  423. <div className={style.bottom}>
  424. {accountCreateLogs?.length > 0 ? <span onClick={() => { setGoodsVisible(true) }}>编辑</span> : <Tooltip title="请先选择媒体账户">
  425. <span>编辑</span>
  426. </Tooltip>}
  427. </div>
  428. </Col>
  429. {/* 数据源 */}
  430. <Col className={style.conRightBorder}>
  431. <div className={style.top}>
  432. 数据源 {/* <span>已选:{1}</span> */}
  433. </div>
  434. <div className={style.center}>
  435. {/* userActionSetsList */}
  436. <div className={style.centerContent}>
  437. {accountCreateLogs?.map((item: any, index: number) => {
  438. if (item?.userActionSetsList && item?.userActionSetsList?.length > 0) {
  439. return <div className={style.acc} key={index}>
  440. <div className={style.accName} style={{ fontWeight: 800 }}>{item.adAccountId}</div>
  441. {
  442. item?.userActionSetsList?.map((pack: { name: string, type: string, id: number }, index1: number) => {
  443. return <div className={style.accCon} key={pack.id}> <span className={style.title}>{pack.name}{' > '}{pack.type}</span> <CloseOutlined className={style.close} onClick={() => {
  444. sourceDel(index, index1)
  445. }} /></div>
  446. })
  447. }
  448. </div>
  449. } else {
  450. return null
  451. }
  452. })}
  453. </div>
  454. </div>
  455. <div className={style.bottom}>
  456. {accountCreateLogs?.length > 0 ? <span onClick={() => { setSourceVisible(true) }}>编辑</span> : <Tooltip title="请先选择媒体账户">
  457. <span>编辑</span>
  458. </Tooltip>}
  459. </div>
  460. </Col>
  461. </Row>
  462. </Col>
  463. {/* =============广告创意=========== */}
  464. <Col span={8} className={style.conRight}>
  465. <Row className={style.conTitle}><Col span={24}>广告创意</Col></Row>
  466. <Row className={style.items}>
  467. {/* 创意 */}
  468. <Col span={12} className={style.conRightBorder}>
  469. <div className={style.top}>创意基本信息</div>
  470. <div className={style.center}>
  471. <Spin spinning={getSysAdcreative.loading}>
  472. <div className={style.centerContent}>
  473. {(getSysAdcreative?.data && queryForm?.sysAdcreativeId) && <AdcreativeCol data={getSysAdcreative?.data} />}
  474. </div>
  475. </Spin>
  476. </div>
  477. <div className={style.bottom}>{queryForm?.sysAdgroupId ? <>
  478. <Button type="link" onClick={() => { setCreativeVisible(true) }}>{queryForm?.sysAdcreativeId ? '修改' : '添加'}</Button>
  479. </> : <Tooltip title="请先设置广告">
  480. <Button type="link"><span>添加</span></Button>
  481. </Tooltip>}
  482. </div>
  483. </Col>
  484. {/* 落地页 */}
  485. <Col span={12} >
  486. <div className={style.top}>
  487. <span>落地页 <Tooltip title="云端落地页优先于本地落地页">
  488. <QuestionCircleOutlined />
  489. </Tooltip></span>
  490. {wxButtonList?.length > 0 && <Button type="link" size="small">配置客服</Button>}
  491. </div>
  492. <div className={style.center}>
  493. <Spin spinning={get.loading}>
  494. <div className={style.centerContent}>
  495. {accountCreateLogs?.some((item: any) => item.pageList?.length > 0 || (queryForm?.sysPageId && (get?.data && !Object.keys(get?.data)?.includes('fail')))) ? <>
  496. {(queryForm?.sysPageId && !accountCreateLogs?.every((item: any) => item.pageList?.length > 0)) && <>
  497. <div>落地页名称:{get?.data?.pageName || ''}</div>
  498. <div>分享名称:{get?.data?.shareContentSpec?.shareTitle || ''}</div>
  499. <div>分享描述:{get?.data?.shareContentSpec?.shareDescription || ''}</div>
  500. <div style={{ marginBottom: 10 }}>原生推广页顶部素材预览:
  501. <div>{get?.data?.pageSpecsList && get?.data?.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) => {
  502. switch (item?.elementType) {
  503. case 'TOP_IMAGE':
  504. return <Image width={80} src={item.topImageSpec.imageUrl} style={{ borderRadius: 8, overflow: 'hidden' }} key={index} />
  505. case 'TOP_SLIDER':
  506. return <Space wrap key={index}>
  507. {item?.topSliderSpec?.imageUrlList?.map((url: string, index: number) => <Image width={70} src={url} style={{ borderRadius: 8 }} key={'TOP_SLIDER' + index} />)}
  508. </Space>
  509. case 'TOP_VIDEO':
  510. return <video src={item.topVideoSpec.videoUrl} width={150} controls key={index}></video>
  511. }
  512. })}</div>
  513. </div>
  514. </>}
  515. {accountCreateLogs?.map((item: any, index: number) => {
  516. if (item?.pageList && item?.pageList?.length > 0) {
  517. return <div className={style.acc} key={index}>
  518. <div className={style.accName} style={{ fontWeight: 800 }}>{item.adAccountId}</div>
  519. {
  520. item?.pageList?.map((pack: { pageName: string, type: string, id: number }, index1: number) => {
  521. return <div className={style.accCon} key={pack.id}> <span className={style.title}>{pack.pageName}</span> <CloseOutlined className={style.close} onClick={() => {
  522. pageDel(index)
  523. }} /></div>
  524. })
  525. }
  526. </div>
  527. } else {
  528. return null
  529. }
  530. })}
  531. </> : <Empty image={Empty.PRESENTED_IMAGE_SIMPLE} />}
  532. </div>
  533. </Spin>
  534. </div>
  535. <div className={style.bottom}>{queryForm?.sysAdcreativeId ? <>
  536. {queryForm?.sysPageId && <Button type="link" onClick={() => { setLookVisible(true) }}>查看</Button>}
  537. <Button type="link" onClick={() => { setSelectImgVisible(true) }}>{queryForm?.sysPageId ? '修改' : '选择落地页'}</Button>
  538. {accountCreateLogs?.length > 0 ? <Button type="link" onClick={() => { setPageVisible(true) }}>云端落地页</Button> : <Tooltip title="请先选择媒体账户">
  539. <Button type="link">云端落地页</Button>
  540. </Tooltip>}
  541. </> : <Tooltip title="请先设置创意">
  542. <Button type="link"><span>选择落地页</span></Button>
  543. </Tooltip>}
  544. </div>
  545. </Col>
  546. </Row>
  547. </Col>
  548. </Row>
  549. {/* =============广告底部按钮=========== */}
  550. <Space className={style.bts}>
  551. <Button type='primary' onClick={severBd}>存为预设</Button>
  552. <Button type='primary' onClick={preview}><SearchOutlined /> 批量预览广告</Button>
  553. <Button onClick={delBdPlan}>清空配置/预设</Button>
  554. </Space>
  555. </div>
  556. </Card>
  557. <Card
  558. className={style.createAd}
  559. hoverable
  560. extra={tableData?.length > 0 ? <Space>
  561. <span>推广计划总数:{accountCreateLogs?.length}</span>
  562. <span>广告总数:{accountCreateLogs?.length}</span>
  563. {tableSelect?.length > 0 && <span> 已选:<span style={{ color: '#1890FF' }}>{tableSelect?.length}</span> 条</span>}
  564. {
  565. <Button type='primary' onClick={() => {
  566. if (tableSelect.length === 0) {
  567. message.error('请选择要提交的计划!')
  568. return
  569. };
  570. setSubVisible(true)
  571. }}>批量提交审核</Button>
  572. }
  573. </Space> : false
  574. }
  575. >
  576. {tableData?.length > 0 ? <div className={style.cardBody}>
  577. <div className={style.content} style={{ marginTop: 20 }}>
  578. <Tables
  579. columns={columns()}
  580. dataSource={tableData}
  581. total={0}
  582. size="small"
  583. bordered
  584. scroll={{ x: 1800 }}
  585. rowSelection={{
  586. selectedRowKeys: tableSelect?.map((item: any) => item?.id.toString()),
  587. onChange: (selectedRowKeys: React.Key[], selectedRows: any) => {
  588. setTableSelect(selectedRows)
  589. }
  590. }}
  591. />
  592. </div>
  593. </div> : <div style={{ minHeight: 400, display: 'flex', justifyContent: 'center', alignItems: 'center' }}>
  594. <Empty description="请先完成模块配置后,再预览广告计划" />
  595. </div>}
  596. </Card>
  597. {/* 选择广告 */}
  598. {adVisible && <AdModal visible={adVisible} onClose={() => setAdVisible(false)} promotedObjectType={queryForm.promotedObjectType as string} onChange={(e) => { setQueryForm({ ...queryForm, sysAdgroupId: e, sysAdcreativeId: undefined }); setAdVisible(false); clearData() }} sysAdgroupId={queryForm?.sysAdgroupId} />}
  599. {/* 选择定向 */}
  600. {dxVisible && <TargetingModal visible={dxVisible} onClose={() => setDxVisible(false)} onChange={(e) => { setQueryForm({ ...queryForm, sysTargetingId: e }); setDxVisible(false); clearData() }} sysTargetingId={queryForm?.sysTargetingId} />}
  601. {/* 选择创意 */}
  602. {creativeVisible && <CreativeModal siteSet={getSysAdgroups?.data?.siteSet} visible={creativeVisible} onClose={() => setCreativeVisible(false)} onChange={(e) => { setQueryForm({ ...queryForm, sysAdcreativeId: e }); setCreativeVisible(false); clearData() }} sysAdcreativeId={queryForm?.sysAdcreativeId} promotedObjectType={queryForm.promotedObjectType as string} />}
  603. {/* 选择商品 */}
  604. {goodsVisible && <GoodsModal visible={goodsVisible} data={accountCreateLogs} onClose={() => setGoodsVisible(false)} onChange={(e) => { setAccountCreateLogs(e); setGoodsVisible(false); clearData() }} />}
  605. {/* 选择数据源 */}
  606. {sourceVisible && <DataSourceModal visible={sourceVisible} data={accountCreateLogs} onClose={() => setSourceVisible(false)} onChange={(e) => { setAccountCreateLogs(e); setSourceVisible(false); clearData() }} />}
  607. {/* 选择转化ID */}
  608. {idVisible && <IdModal visible={idVisible} data={accountCreateLogs} onClose={() => setIdVisible(false)} onChange={(e) => { setAccountCreateLogs(e); setSourceVisible(false); clearData() }} />}
  609. {/* 选择定向包 */}
  610. {cpVisible && <CrowdPackModal visible={cpVisible} data={accountCreateLogs} onClose={() => setCpVisible(false)} onChange={(e) => { setAccountCreateLogs(e); setCpVisible(false); clearData() }} />}
  611. {/* 选择ADQ落地页 */}
  612. {pageVisible && <PageModal visible={pageVisible} data={accountCreateLogs} onClose={() => setPageVisible(false)} onChange={(e) => { setAccountCreateLogs(e); setPageVisible(false); clearData() }} />}
  613. {/* 选择素材 */}
  614. {selectImgVisible && <SelectCloud visible={selectImgVisible} onClose={() => setSelectImgVisible(false)} onChange={setPage} isBack={false} />}
  615. {/* 查看落地页 */}
  616. {lookVisible && <LookLanding visible={lookVisible} onClose={() => setLookVisible(false)} id={queryForm?.sysPageId as any} />}
  617. {/* 设置名称 */}
  618. {subVisible && <SubmitModal data={getSysAdgroups?.data} visible={subVisible} onClose={() => setSubVisible(false)} onChange={submit} ajax={createAdBatch} />}
  619. </Space>
  620. }
  621. export default CreateAd