index.tsx 67 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104
  1. import React, { useCallback, useEffect, useMemo, useState } from 'react'
  2. import { Modal, Form, Input, Divider, Select, Radio, Switch, Spin, List, Checkbox, Space, Button, message, Image, Empty } from 'antd'
  3. import styles from './index.less'
  4. import { useAjax } from '@/Hook/useAjax'
  5. import { getText, get_adcreative_template, get_adcreative_template_list, get_tools_video_capture } from '@/services/launchAdq/global'
  6. import { AdcreativeTemplate, AdcreativeTemplateList } from '@/services/launchAdq'
  7. import { mySet } from '@/utils/arrFn'
  8. import SelectCloud from '@/pages/launchSystemNew/components/selectCloud'
  9. import { useModel } from 'umi'
  10. import { ModalConfig } from '../../ad';
  11. import { outAdcreativeTemplateIdFun } from '../../../localAd/adenum'
  12. import { CreateAdProps } from '@/services/launchAdq/createAd'
  13. import { createSysAdcreative } from '@/services/launchAdq/creative'
  14. import { creativeConfig, overrideCanvasHeadOptionEnum } from './config'
  15. import BrandImage from './brandImage'
  16. import HeadNickJump from './headNickJump'
  17. import moment from 'moment'
  18. interface Props {
  19. queryForm: Partial<CreateAdProps>,
  20. title?: string,
  21. visible: boolean,
  22. PupFn: (arg: ModalConfig) => void,
  23. callback: (params: any) => void,
  24. confirmLoading?: boolean,
  25. type?: 'add' | 'look' | 'edit',//新增,查看,编辑
  26. dataInfo?: any
  27. }
  28. /**创意模板*/
  29. function CreativePup(props: Props) {
  30. let { visible, confirmLoading, PupFn, callback, type, dataInfo, queryForm } = props
  31. const { currentUser }: any = useModel('@@initialState', model => ({ currentUser: model.initialState?.currentUser }))
  32. let [template_checked, settemplate_checked] = useState<boolean>(dataInfo?.isTemplate || false)
  33. let { promotedObjectType, sysAdgroup } = queryForm
  34. let { siteSet } = sysAdgroup
  35. const { init } = useModel('useLaunchAdq.useBdMediaPup')
  36. let arg = type === 'look' ? { footer: null } : {}
  37. // 请求
  38. const getAdcreativeTemplate = useAjax((params) => get_adcreative_template(params))
  39. const getAdcreativeTemplateList = useAjax((params) => get_adcreative_template_list(params))
  40. const getTextLsit = useAjax((params) => getText(params))
  41. const addSysAdgroup = useAjax((params) => createSysAdcreative(params))
  42. const getVideoCapture = useAjax((params) => get_tools_video_capture(params))
  43. // 变量
  44. const [adcreative_template, set_adcreative_template] = useState<AdcreativeTemplate>()
  45. const [adcreative_template_list, set_adcreative_template_list] = useState<AdcreativeTemplateList[]>([])
  46. const [selectImgVisible, set_selectImgVisible] = useState(false)
  47. const [selectVideoVisible, set_selectVideoVisible] = useState(false)
  48. const [videoImgsVisbile, set_videoImgsVisbile] = useState(false)
  49. const [descriptionShow, setdescriptionshow] = useState(false)
  50. const [endPageDescShow, setendPageDescnshow] = useState(false)
  51. const [isShowSc, set_isShowSc] = useState(false)//是否展示素材选项
  52. const [infoSet, set_infoSet] = useState(false)//回填设置已完成
  53. const [videoImgs, set_videoImgs] = useState<{//视频封面图设置
  54. activeUrl: string,//选中的视频封面图地址
  55. preview: boolean,//是否开启图片点击预览
  56. urlList: any[],//生成的视频封面列表
  57. }>({
  58. activeUrl: '',
  59. preview: false,
  60. urlList: [
  61. 'https://test-adq-media.oss-cn-hangzhou.aliyuncs.com/image/21D8D51AD98C4FF8BF41F1C2D28EA39F.jpg',
  62. 'https://test-adq-media.oss-cn-hangzhou.aliyuncs.com/image/80DBE1AB3EDE4E85ABAE5F1670D9FED0.jpg',
  63. 'https://test-adq-media.oss-cn-hangzhou.aliyuncs.com/image/BCB2DAB86BDB4549BCB8E493C4F29E82.jpg',
  64. 'https://test-adq-media.oss-cn-hangzhou.aliyuncs.com/image/545A4C2A5B874C82A9D1C0C063624AE5.jpg'
  65. ]
  66. })
  67. const [titleShow, settitleshow] = useState(false)
  68. const [form] = Form.useForm();
  69. const [pupState, setPupState] = useState({
  70. kp_show: false,
  71. xd_show: false,
  72. sj_show: false,
  73. bq_show: false,
  74. sp_show: false
  75. })
  76. const [imgMaterialConfig, setImgMaterialConfig] = useState<{
  77. adcreativeTemplateId?: number,
  78. type: string,
  79. cloudSize: { relation: string, width: number, height: number }[],
  80. list: any[],
  81. max: number
  82. }>({
  83. type: '',//类型
  84. cloudSize: [],//素材搜索条件
  85. list: [],//素材
  86. max: 1,//素材数量
  87. })//图片素材配置
  88. const [videoMaterialConfig, setVideoMaterialConfig] = useState<{
  89. adcreativeTemplateId?: number,
  90. type: string,
  91. cloudSize: { relation: string, width: number, height: number }[],
  92. list: any[],
  93. max: number
  94. }>({
  95. type: '',//类型
  96. cloudSize: [],//素材搜索条件
  97. list: [],//素材
  98. max: 1,//素材数量
  99. })//图片素材配置
  100. const [conversionList, setConversionList] = useState<any>(null)
  101. let pageType = Form.useWatch('pageType', form)
  102. let adcreativeTemplateId = Form.useWatch('adcreativeTemplateId', form)
  103. let actionBtn = Form.useWatch('actionBtn', form)
  104. // let siteSet = Form.useWatch('siteSet', form)
  105. let overrideCanvasHeadOption = Form.useWatch('overrideCanvasHeadOption', form)
  106. let adcreativeElementsType = Form.useWatch('adcreativeElementsType', form)
  107. let dataShow = Form.useWatch('dataShow', form)
  108. let conversionDataType = Form.useWatch('conversionDataType', form)
  109. let titles = Form.useWatch('title', form)
  110. let description = Form.useWatch('description', form)
  111. let videoOver = Form.useWatch('videoOver', form)
  112. let endPageDesc = Form.useWatch('endPageDesc', form)
  113. let linkPageType = Form.useWatch('linkPageType', form)
  114. // 确定事件
  115. const handleOk = useCallback(() => {
  116. form.validateFields().then(values => {
  117. console.log('values=>1', values)
  118. let newValues = JSON.parse(JSON.stringify(values))
  119. for (let key in newValues) {
  120. switch (key) {
  121. case 'image'://图素材
  122. newValues.adcreativeElements = {
  123. ...newValues.adcreativeElements,
  124. imageUrl: imgMaterialConfig?.list[0]?.url,
  125. }
  126. delete newValues[key]
  127. break;
  128. case 'video'://视频素材
  129. newValues.adcreativeElements = {
  130. ...newValues.adcreativeElements,
  131. videoUrl: videoMaterialConfig?.list[0]?.url,
  132. }
  133. delete newValues[key]
  134. break;
  135. case 'image_list'://图素材
  136. newValues.adcreativeElements = {
  137. ...newValues.adcreativeElements,
  138. imageUrlList: imgMaterialConfig.list?.map(item => item.url),
  139. description: newValues.description,
  140. }
  141. delete newValues[key]
  142. break;
  143. case 'short_video1'://视频素材
  144. newValues.adcreativeElements = {
  145. ...newValues.adcreativeElements,
  146. shortVideoStruct: {
  147. shortVideo1Url: videoMaterialConfig?.list[0]?.url
  148. },
  149. description: newValues.description,
  150. }
  151. delete newValues[key]
  152. break;
  153. case 'description'://文案
  154. newValues.adcreativeElements = { ...newValues.adcreativeElements, description: newValues.description }
  155. break;
  156. case 'title'://文案
  157. newValues.adcreativeElements = { ...newValues.adcreativeElements, title: newValues.title }
  158. break;
  159. case 'endPageType'://视频结束l类型
  160. newValues.adcreativeElements = { ...newValues.adcreativeElements, endPage: { ...newValues.adcreativeElements.endPage, endPageType: newValues.endPageType } }
  161. delete newValues[key]
  162. break;
  163. case 'endPageDesc'://视频结束文案
  164. newValues.adcreativeElements = { ...newValues.adcreativeElements, endPage: { ...newValues.adcreativeElements.endPage, endPageDesc: newValues.endPageDesc } }
  165. delete newValues[key]
  166. break;
  167. case 'buttonText'://特殊行动按钮
  168. newValues.adcreativeElements = { ...newValues.adcreativeElements, buttonText: newValues.buttonText }
  169. delete newValues[key]
  170. break;
  171. case 'brand'://品牌形象
  172. newValues.adcreativeElements = {
  173. ...newValues.adcreativeElements, brand: {
  174. brandName: newValues.brand.split('_')[0],
  175. brandImgUrl: newValues.brand.split('_')[1]
  176. }
  177. }
  178. break;
  179. case 'profile':
  180. newValues.adcreativeElements = {
  181. ...newValues.adcreativeElements, brand: {
  182. brandName: newValues.profile.split('_')[0],
  183. brandImgUrl: newValues.profile.split('_')[1]
  184. }
  185. }
  186. newValues.profile = {
  187. headImageUrl: newValues.profile.split('_')[1],
  188. profileName: newValues.profile.split('_')[0],
  189. description: newValues.profile.split('_')[2]
  190. }
  191. break
  192. case 'pageUrl'://跳转落地页
  193. newValues.linkPageSpec = {
  194. ...newValues.linkPageSpec,
  195. pageUrl: newValues.pageUrl
  196. }
  197. delete newValues.pageUrl
  198. break;
  199. case 'miniProgramId':
  200. newValues.linkPageSpec = {
  201. ...newValues.linkPageSpec,
  202. miniProgramSpec: {
  203. miniProgramId: newValues.miniProgramId,
  204. miniProgramPath: newValues.miniProgramPath
  205. }
  206. }
  207. delete newValues.miniProgramId
  208. delete newValues.miniProgramPath
  209. break;
  210. }
  211. }
  212. if (!newValues.adcreativeElements) {
  213. newValues.adcreativeElements = {}
  214. }
  215. //假如不存在promotedObjectType
  216. if (!newValues?.promotedObjectType) {
  217. newValues['promotedObjectType'] = queryForm.promotedObjectType
  218. }
  219. // 假如不存在siteSet
  220. if (!newValues?.siteSet) {
  221. newValues['siteSet'] = queryForm.sysAdgroup.siteSet
  222. }
  223. delete newValues.description //删除外层文案
  224. delete newValues.title //删除外层文案
  225. delete newValues.adcreativeElementsType //删除创意形式
  226. delete newValues.dataShow //删除数据开关
  227. delete newValues.actionBtn //删除行动开关
  228. delete newValues.brand //品牌形象
  229. // 假如使用了落地页顶部素材替换外部素材
  230. if (newValues.overrideCanvasHeadOption === 'OPTION_CANVAS_OVERRIDE_CREATIVE') {
  231. console.log(adcreative_template?.adcreativeElements)
  232. adcreative_template?.adcreativeElements?.filter(item => item.required && item.name === 'image_list' || item.name === 'short_video1' || item.name === 'video' || item.name === 'image').forEach(item => {
  233. switch (item.name) {
  234. case 'image'://图素材
  235. newValues.adcreativeElements = {
  236. ...newValues.adcreativeElements,
  237. imageUrl: '',
  238. }
  239. break;
  240. case 'video'://视频素材
  241. newValues.adcreativeElements = {
  242. ...newValues.adcreativeElements,
  243. videoUrl: '',
  244. }
  245. break;
  246. case 'image_list'://图素材
  247. newValues.adcreativeElements = {
  248. ...newValues.adcreativeElements,
  249. imageUrlList: [],
  250. }
  251. break;
  252. case 'short_video1'://视频素材
  253. newValues.adcreativeElements = {
  254. ...newValues.adcreativeElements,
  255. shortVideoStruct: {
  256. shortVideo1Url: ''
  257. },
  258. }
  259. break;
  260. }
  261. })
  262. }
  263. console.log('newValues=>2', newValues)
  264. newValues['isTemplate'] = template_checked
  265. // // 开启存为模板开关执行
  266. callback(newValues)
  267. })
  268. }, [form, imgMaterialConfig, videoMaterialConfig, queryForm, template_checked, adcreative_template, isShowSc])
  269. // 获取创意形式列表
  270. useEffect(() => {
  271. if (siteSet?.length > 0 && promotedObjectType) {
  272. getAdcreativeTemplateList.run({
  273. siteSet,
  274. promotedObjectType,
  275. campaignType: 'CAMPAIGN_TYPE_NORMAL',
  276. }).then(res => {
  277. let newArr: any = []
  278. // 过滤掉相同的和即将下线的
  279. if (!res) {
  280. return
  281. }
  282. //
  283. Object.values(res)?.forEach((arr: any) => {
  284. Array.isArray(arr) && arr?.forEach((item: any) => {
  285. if (newArr.length > 0) {//假如已存在ID,需要过滤相同
  286. if (outAdcreativeTemplateIdFun(item.adcreativeTemplateId) && newArr.every((i: { adcreativeTemplateId: any }) => i.adcreativeTemplateId !== item.adcreativeTemplateId)) {//不重复的添加
  287. newArr.push(item)
  288. } else {
  289. // 找出通用创意
  290. newArr = newArr?.map((arr: { adcreativeTemplateId: any }) => {
  291. if (arr.adcreativeTemplateId === item.adcreativeTemplateId) {
  292. return { ...arr, isGeneral: true }
  293. }
  294. return arr
  295. })
  296. }
  297. } else {//不存在ID直接过滤掉即将下线的
  298. if (outAdcreativeTemplateIdFun(item.adcreativeTemplateId)) {
  299. newArr.push(item)
  300. }
  301. }
  302. })
  303. })
  304. /*****暂时排除激励和banner有问题******/
  305. if (siteSet.some((i: string) => i === 'SITE_SET_MOMENTS')) {
  306. newArr = newArr.filter((item: { adcreativeTemplateId: number }) => item.adcreativeTemplateId !== 910 && item.adcreativeTemplateId !== 925)
  307. }
  308. set_adcreative_template_list(newArr)
  309. })
  310. }
  311. }, [siteSet, promotedObjectType])
  312. // 获取创意形式详情
  313. const getTemplate = useCallback((id: any, ok?: any) => {
  314. // CAMPAIGN_TYPE_NORMAL
  315. if (siteSet?.length > 0 && promotedObjectType && id) {
  316. if (id) {
  317. getAdcreativeTemplate.run({
  318. siteSet,
  319. promotedObjectType,
  320. adcreativeTemplateId: id
  321. }).then(res => {
  322. if (res?.length > 0) {
  323. form.setFieldsValue({ adcreativeName: res[0]?.adcreativeTemplateAppellation + '_' + moment().format('YYYYMMDDhhmmss') + '_' + currentUser.userId })
  324. set_adcreative_template(res[0])
  325. if (siteSet?.some((name: string) => name === 'SITE_SET_MOMENTS')) {
  326. let id = res[0].adcreativeTemplateId
  327. set_isShowSc(!!creativeConfig[id])//判定当前创意是否需要展示替换素材选项
  328. if (creativeConfig[id] && !ok) {//假如不等于回填元素的ID
  329. form.setFieldsValue({ overrideCanvasHeadOption: creativeConfig[id].overrideCanvasHeadOption[0] })
  330. }
  331. }
  332. templateChange(res[0], ok)
  333. }
  334. })
  335. }
  336. }
  337. }, [siteSet, promotedObjectType])
  338. // 获取对应落地页按钮
  339. const pageTypeList = useMemo(() => {
  340. if (adcreativeTemplateId) {
  341. let arr: any = adcreative_template?.landingPageConfig?.supportPageTypeList
  342. return arr
  343. }
  344. return null
  345. }, [adcreativeTemplateId, adcreative_template])
  346. // 获取对应行动按钮数据
  347. const linkNameList = useMemo(() => {
  348. if (pageType) {
  349. let arr = (pageTypeList?.filter((item: { pageType: any; }) => item.pageType === pageType)[0] as any)?.supportLinkNameType?.list
  350. return arr
  351. }
  352. return null
  353. }, [pageType, pageTypeList])
  354. // 跳转落地页
  355. const linkPageList = useMemo(() => {
  356. if (pageType) {
  357. let arr = (pageTypeList?.filter((item: { pageType: any; }) => item.pageType === pageType)[0] as any)?.supportLinkPageType?.list
  358. return arr
  359. }
  360. return null
  361. }, [pageType, pageTypeList])
  362. const typeChange = useCallback((adcreativeElementsType) => {
  363. if (adcreativeElementsType && adcreative_template_list?.length > 0) {
  364. let adcreativeTemplateIdArr = adcreative_template_list?.filter(item => item.adcreativeTemplateStyle === adcreativeElementsType)
  365. console.log('typeChange====>', adcreativeTemplateIdArr[0].adcreativeTemplateId)
  366. getTemplate(adcreativeTemplateIdArr[0].adcreativeTemplateId)
  367. form.setFieldsValue({ adcreativeTemplateId: adcreativeTemplateIdArr[0].adcreativeTemplateId })
  368. }
  369. }, [adcreative_template_list])
  370. //每次选中创意设置该展示的界面
  371. const templateChange = useCallback((adcreative_template, ok?: any) => {
  372. let states = {
  373. kp_show: false,
  374. xd_show: true,
  375. sj_show: false,
  376. bq_show: false,
  377. sp_show: false
  378. }
  379. let values: any = { pageType: 'PAGE_TYPE_CANVAS_WECHAT', }
  380. if (adcreative_template) {
  381. let pageList = adcreative_template?.landingPageConfig?.supportPageTypeList?.filter((i: { description: string | string[] }) => i.description.includes('微信原生推广页'))//当前版本只获取微信原生页,后期改进
  382. let pageType = pageList?.length ? pageList[0]?.pageType : null
  383. //数据展示组件
  384. if (adcreative_template.adcreativeAttributes.some((item: { name: string }) => item.name === 'conversion_data_type' || item.name === 'conversion_target_type')) {
  385. let arr = adcreative_template.adcreativeAttributes?.filter((item: { name: string; }) => item.name === 'conversion_data_type' || item.name === 'conversion_target_type')
  386. let newObj: any = {}
  387. arr.forEach((item: { propertyDetail: { enumDetail: { enumeration: any[] } }; name: string | number }) => {
  388. let arr: any[] = mySet(item.propertyDetail.enumDetail.enumeration)
  389. newObj[item.name] = arr
  390. })
  391. setConversionList(newObj)
  392. states = { ...states, sj_show: true }
  393. if (newObj.conversion_data_type) {
  394. values = { ...values, conversionDataType: newObj.conversion_data_type[0].value }
  395. }
  396. if (newObj.conversion_target_type) {
  397. values = { ...values, conversionTargetType: newObj.conversion_target_type[0].value }
  398. }
  399. }
  400. //行动按钮组件存在
  401. if (states.xd_show) {
  402. let linkNameList = (pageList?.filter((item: { pageType: any; }) => item.pageType === pageType)[0] as any)?.supportLinkNameType?.list
  403. let linkPageList = (pageList?.filter((item: { pageType: any; }) => item.pageType === pageType)[0] as any)?.supportLinkPageType?.list
  404. if (linkNameList && !linkPageType) {
  405. if (!ok) {
  406. let linkNameType = linkNameList[0]?.linkNameType
  407. let linkPageType = linkPageList?.some((i: { linkPageType: string }) => i.linkPageType === "LINK_PAGE_TYPE_CANVAS_WECHAT") ? "LINK_PAGE_TYPE_CANVAS_WECHAT" : linkPageList[0]?.linkPageType
  408. values = { ...values, linkNameType, linkPageType, actionBtn: true }
  409. }
  410. } else {
  411. states = { ...states, xd_show: false }
  412. }
  413. }
  414. // 特殊行动按钮
  415. if (adcreative_template.adcreativeElements?.find((item: { name: string }) => item.name === 'button_text') && !ok) {
  416. values = { ...values, buttonText: adcreative_template?.adcreativeElements?.find((item: { name: string }) => item.name === 'button_text')?.enumProperty?.enumeration[0].value }
  417. }
  418. // 视频结束页 end_page
  419. if (adcreative_template.adcreativeElements.some((item: { name: string }) => item.name === 'end_page')) {
  420. // let endPageType =adcreative_template?.adcreativeElements?.filter(item=>item.name === 'end_page_type')[0]?.enumProperty?.enumeration
  421. if (!ok) {
  422. values = { ...values, endPageType: 'END_PAGE_AVATAR_NICKNAME_HIGHLIGHT' }
  423. }
  424. states = { ...states, sp_show: true }
  425. }
  426. setPupState(states)
  427. form.setFieldsValue(values)
  428. }
  429. }, [pageType, linkPageType])
  430. // 版位改变清空数据
  431. useEffect(() => {
  432. if (imgMaterialConfig.adcreativeTemplateId && adcreativeTemplateId !== imgMaterialConfig.adcreativeTemplateId) {
  433. setImgMaterialConfig({ ...imgMaterialConfig, adcreativeTemplateId: undefined, list: [] })
  434. }
  435. if (videoMaterialConfig.adcreativeTemplateId && adcreativeTemplateId !== videoMaterialConfig.adcreativeTemplateId) {
  436. setVideoMaterialConfig({ ...videoMaterialConfig, adcreativeTemplateId: undefined, list: [] })
  437. }
  438. }, [adcreativeTemplateId, imgMaterialConfig, videoMaterialConfig])
  439. // 文案助手
  440. const textList = useCallback((arg: { maxTextLength: number, keyword?: string }) => {
  441. let { maxTextLength, keyword } = arg
  442. getTextLsit.run({ keyword: keyword || titles || description, maxTextLength })
  443. }, [titles, description])
  444. // 监听点击取消文案助手弹窗
  445. useEffect(() => {
  446. let modal = document.querySelector('.myModal')
  447. let onBiurdescription = (e: any) => {
  448. let d = document.querySelector('.my_description')
  449. let t = document.querySelector('.my_title')
  450. let p = document.querySelector('.my_endPageDesc')
  451. if (!d?.contains(e.target)) {
  452. setdescriptionshow(false)
  453. }
  454. if (!t?.contains(e.target)) {
  455. settitleshow(false)
  456. }
  457. if (!p?.contains(e.target)) {
  458. setendPageDescnshow(false)
  459. }
  460. }
  461. modal?.addEventListener('click', onBiurdescription)
  462. return () => {
  463. modal?.removeEventListener('click', onBiurdescription)
  464. }
  465. }, [])
  466. // 数据回填
  467. useEffect(() => {
  468. if (!infoSet && dataInfo && adcreative_template_list?.length > 0) {
  469. let { adcreativeName, adcreativeTemplateId, conversionDataType, conversionTargetType, linkNameType, linkPageType, pageType, promotedObjectType, siteSet, profile, adcreativeElements, overrideCanvasHeadOption, linkPageSpec } = dataInfo
  470. let { description, imageUrl, title, videoUrl, imageUrlList, endPage, shortVideoStruct, brand, buttonText } = adcreativeElements
  471. let obj: any = {
  472. adcreativeName,
  473. siteSet,
  474. promotedObjectType,
  475. adcreativeTemplateId,
  476. }
  477. getTemplate(adcreativeTemplateId, true)
  478. console.log(2222, dataInfo)
  479. if ([720, 721, 618, 1708, 722, 1529].some(n => n === adcreativeTemplateId)) {
  480. obj = { ...obj, adcreativeElementsType: '视频' }
  481. } else {
  482. obj = { ...obj, adcreativeElementsType: '图片' }
  483. }
  484. if (conversionDataType) {
  485. obj = { ...obj, conversionDataType, dataShow: true }
  486. }
  487. if (conversionTargetType) {
  488. obj = { ...obj, conversionTargetType, dataShow: true }
  489. }
  490. if (linkNameType) {
  491. obj = { ...obj, linkNameType, actionBtn: true }
  492. }
  493. if (linkPageType) {
  494. obj = { ...obj, linkPageType, actionBtn: true }
  495. }
  496. if (pageType) {
  497. obj = { ...obj, pageType }
  498. }
  499. if (description) {
  500. obj = { ...obj, description }
  501. }
  502. if (title) {
  503. obj = { ...obj, title }
  504. }
  505. if (endPage) {
  506. obj = { ...obj, videoOver: true, ...endPage }
  507. }
  508. if (overrideCanvasHeadOption) {
  509. obj = { ...obj, overrideCanvasHeadOption }
  510. }
  511. if (linkPageSpec?.pageUrl) {
  512. obj = { ...obj, pageUrl: linkPageSpec?.pageUrl }
  513. }
  514. if (linkPageSpec?.miniProgramSpec && linkPageSpec?.miniProgramSpec?.miniProgramPath) {
  515. obj = { ...obj, miniProgramPath: linkPageSpec?.miniProgramSpec?.miniProgramPath, miniProgramId: linkPageSpec?.miniProgramSpec?.miniProgramId }
  516. }
  517. if (brand && brand.brandImgUrl && brand.brandName) {
  518. obj = { ...obj, brand: brand.brandName + '_' + brand.brandImgUrl }
  519. }
  520. if (profile && profile.headImageUrl && profile.profileName && profile.description) {
  521. obj = { ...obj, profile: profile.profileName + '_' + profile.headImageUrl + '_' + profile.description }
  522. }
  523. if (buttonText) {
  524. obj = { ...obj, buttonText }
  525. }
  526. if (videoUrl) {
  527. setVideoMaterialConfig({
  528. cloudSize: [],
  529. list: [{ url: videoUrl }],
  530. max: 1,
  531. type: 'video',
  532. adcreativeTemplateId
  533. })
  534. obj = { ...obj, video: videoUrl }
  535. }
  536. if (imageUrl) {
  537. setImgMaterialConfig({
  538. cloudSize: [],
  539. list: [{ url: imageUrl }],
  540. max: 1,
  541. type: 'image',
  542. adcreativeTemplateId
  543. })
  544. obj = { ...obj, image: imageUrl }
  545. }
  546. if (imageUrlList) {
  547. setImgMaterialConfig({
  548. cloudSize: [],
  549. list: imageUrlList?.map((url: any) => ({ url })),
  550. max: imageUrlList.length,
  551. type: 'image_list',
  552. adcreativeTemplateId
  553. })
  554. obj = { ...obj, image_list: imageUrlList }
  555. }
  556. if (shortVideoStruct) {
  557. setVideoMaterialConfig({
  558. cloudSize: [],
  559. list: [{ url: shortVideoStruct.shortVideo1Url }],
  560. max: 1,
  561. type: 'short_video1',
  562. adcreativeTemplateId
  563. })
  564. obj = { ...obj, short_video1: shortVideoStruct.shortVideo1Url }
  565. }
  566. console.log('数据回填====>', obj)
  567. form.setFieldsValue(obj)
  568. set_infoSet(true)
  569. }
  570. // 不是数据回填首次打开界面选中视频
  571. if (!infoSet && !dataInfo && adcreative_template_list?.length > 0) {
  572. typeChange('视频')
  573. set_infoSet(true)
  574. }
  575. }, [dataInfo, adcreative_template_list, adcreative_template, infoSet])
  576. // 生成视频封面图
  577. const videoToImgs = useCallback(() => {
  578. if (videoMaterialConfig.list[0]) {
  579. set_videoImgsVisbile(true)
  580. // let url = videoMaterialConfig.list[0].url
  581. // fetch(url).then(res => res.blob()).then(async (blob) => {
  582. // let file = new File([blob], 'sp', { type: blob.type })
  583. // // let md5 = await getMD5(file)
  584. // let formData = new FormData()
  585. // formData.append('videoFile', file)
  586. // formData.append('number', '12')
  587. // getVideoCapture.run(formData).then(res => {
  588. // console.log(res)
  589. // })
  590. // })
  591. } else {
  592. message.warning('请先选择视频文件!!!')
  593. }
  594. }, [videoMaterialConfig.list])
  595. return <Modal
  596. visible={visible}
  597. title={type === 'add' ? '新建创意' : type === 'look' ? '创意详情' : '编辑创意'}
  598. onCancel={() => { PupFn({ visible: false, dataInfo: null, type: 'add' }) }}
  599. // onOk={handleOk}
  600. width={1200}
  601. confirmLoading={confirmLoading}
  602. footer={<Space>
  603. <Button onClick={() => { PupFn({ visible: false, dataInfo: null, type: 'add' }) }}>取消</Button>
  604. <Button type='primary' onClick={handleOk}>确定</Button>
  605. {<Checkbox checked={template_checked} onChange={(e) => {
  606. let checked = e.target.checked
  607. settemplate_checked(checked)
  608. }}>存为模板</Checkbox>}
  609. </Space>}
  610. className='myModal'
  611. {...arg}
  612. >
  613. <Form
  614. form={form}
  615. labelCol={{ span: 5 }}
  616. labelWrap={true}
  617. className='ad_form_style'
  618. initialValues={
  619. {
  620. adcreativeElementsType: '视频',
  621. }
  622. }
  623. >
  624. {/* ============================================================创意形式============================================================= */}
  625. <Divider orientation='center'>创意形式</Divider>
  626. {/* ============================================================创意形式============================================================= */}
  627. <Form.Item label={<strong>创意形式</strong>} name='adcreativeElementsType'>
  628. <Radio.Group onChange={(e) => {
  629. let value = e.target.value
  630. typeChange(value)
  631. }}>
  632. <Radio.Button value="视频">视频</Radio.Button>
  633. <Radio.Button value="图片">图片</Radio.Button>
  634. </Radio.Group>
  635. </Form.Item>
  636. {
  637. getAdcreativeTemplateList?.loading ? <Spin tip="Loading..." style={{ width: '100%' }}></Spin> :
  638. <>
  639. <Form.Item style={{ marginLeft: 177 }} name='adcreativeTemplateId'>
  640. <Radio.Group className={styles.adcreative_template} onChange={(e) => {
  641. let id = e.target.value
  642. getTemplate(id)
  643. }}>
  644. {adcreative_template_list?.filter(item => item.adcreativeTemplateStyle === adcreativeElementsType && item.supportBidModeList.includes(queryForm?.sysAdgroup?.bidMode))?.map((item: any) => {
  645. return <Radio.Button value={item.adcreativeTemplateId} key={item.adcreativeTemplateId}>
  646. <div className={styles.adcreative_template_item}>
  647. {item.isGeneral && <span style={{ color: '#4080ff', fontSize: 10 }}>所选版位通投</span>}
  648. <img src={item.adcreativeSampleImage} />
  649. <span style={{ fontSize: 12, height: 20, lineHeight: '20px' }}>{item.adcreativeTemplateAppellation}</span>
  650. <span style={{ fontSize: 12, height: 20, lineHeight: '20px' }}>{item.adcreativeTemplateId}</span>
  651. </div>
  652. </Radio.Button>
  653. })}
  654. </Radio.Group>
  655. </Form.Item>
  656. {/* ============================================================创意内容============================================================= */}
  657. <Divider orientation='center'>创意内容</Divider>
  658. {/* =============================================================头像及昵称跳转页===================================================================== */}
  659. {queryForm.promotedObjectType === 'PROMOTED_OBJECT_TYPE_LEAD_AD' ? adcreative_template?.adcreativeAttributes?.find(item => item.name === 'profile_id') ? <Form.Item label={<strong>头像及昵称跳转页</strong>} name='profile' rules={[{ required: true, message: '请选择一个头像及昵称跳转页,与广告创意一起展示' }]}>
  660. <HeadNickJump />
  661. </Form.Item> : <Form.Item label={<strong>品牌形象</strong>} name='brand' rules={[{ required: true, message: '请选择一个头像及昵称跳转页,与广告创意一起展示' }]}>
  662. <BrandImage />
  663. </Form.Item> : null}
  664. {/* ============================================================素材============================================================= */}
  665. {/* 优先展示视频或图片,朋友圈常规不勾选使用外部素材替换内部,隐藏此选项,后期自动将落地页顶部素材添加进入 */}
  666. {((overrideCanvasHeadOption !== 'OPTION_CANVAS_OVERRIDE_CREATIVE') || siteSet.every((name: string) => name !== 'SITE_SET_MOMENTS')) && <div style={{ display: 'flex', flexFlow: 'column' }}>
  667. {
  668. adcreative_template?.adcreativeElements?.filter(item => item.required && item.name === 'image_list' || item.name === 'short_video1' || item.name === 'video' || item.name === 'image').map(item => {
  669. return <Form.Item
  670. label={<strong>{item.description === '图片' && adcreative_template?.adcreativeElements?.some(item => item.name === 'video') ? '视频封面图' : item.description}</strong>}
  671. key={item.name}
  672. >
  673. {/* 视频 */}
  674. {
  675. (item.name === 'short_video1' || item.name === 'video') && <Form.Item
  676. noStyle
  677. rules={[{ required: true, message: '请选择素材!' }]}
  678. name={item.name}
  679. style={item.description === '图片' && adcreative_template?.adcreativeElements?.some(item => item.name === 'video') ? { order: 2 } : {}}
  680. >
  681. <div className={`${styles.box} ${styles.video}`} onClick={() => {
  682. init({ mediaType: 'VIDEO', cloudSize: adcreativeTemplateId === 1708 ? [[{ relation: '=', width: 1280, height: 720 }]] : [[{ relation: '=', width: item.restriction.videoRestriction.minWidth, height: item.restriction.videoRestriction.minHeight }]], maxSize: item.restriction.videoRestriction.fileSize * 1024 })
  683. setTimeout(() => {
  684. set_selectVideoVisible(true)
  685. setVideoMaterialConfig({
  686. ...videoMaterialConfig,
  687. type: item.name,
  688. max: 1,
  689. adcreativeTemplateId
  690. })
  691. }, 100)
  692. }}>
  693. <p>
  694. {
  695. videoMaterialConfig?.list[0] ? <video src={videoMaterialConfig?.list[0].url} controls /> : <>
  696. <span>{`推荐尺寸(${adcreativeTemplateId === 1708 ? 1280 : item.restriction.videoRestriction.minWidth} x ${adcreativeTemplateId === 1708 ? 720 : item.restriction.videoRestriction.minHeight})`}</span>
  697. <span>{`${item.restriction.videoRestriction.fileFormat?.map(str => str?.replace('MEDIA_TYPE_', ''))};< ${item.restriction.videoRestriction.fileSize / 1024}M;时长 ≥ ${item.restriction.videoRestriction.minDuration}s,≤ ${item.restriction.videoRestriction.maxDuration}s,必须带有声音`}</span>
  698. </>
  699. }
  700. </p>
  701. </div>
  702. </Form.Item>
  703. }
  704. {/* 单图 */}
  705. {
  706. item.name === 'image' && <Form.Item
  707. noStyle
  708. rules={[{ required: true, message: '请选择素材!' }]}
  709. name={item.name}
  710. style={item.description === '图片' && adcreative_template?.adcreativeElements?.some(item => item.name === 'video') ? { order: 2 } : {}}
  711. >
  712. <div className={`${styles.box} ${styles.image}`} onClick={() => {
  713. init({ mediaType: 'IMG', cloudSize: [[{ relation: '=', width: item.restriction.imageRestriction.width, height: item.restriction.imageRestriction.height }]], maxSize: item.restriction.imageRestriction.fileSize * 1024 })
  714. setTimeout(() => {
  715. set_selectImgVisible(true)
  716. setImgMaterialConfig({
  717. ...imgMaterialConfig,
  718. type: item.name,
  719. max: 1,
  720. adcreativeTemplateId
  721. })
  722. }, 100)
  723. }}>
  724. <p>
  725. {imgMaterialConfig?.list[0] ? <img src={imgMaterialConfig?.list[0].url} /> : <>
  726. <span>{`推荐尺寸(${item.restriction.imageRestriction.width} x ${item.restriction.imageRestriction.height})`}</span>
  727. <span>{`${item.restriction.imageRestriction.fileFormat?.map(str => str?.replace('IMAGE_TYPE_', ''))};小于 ${item.restriction.imageRestriction.fileSize}KB`}</span>
  728. </>}
  729. </p>
  730. </div>
  731. </Form.Item>
  732. }
  733. {/* {
  734. item.description === '图片' && adcreative_template?.adcreativeElements?.some(item => item.name === 'video') && <Button onClick={videoToImgs} size='small' type='primary' disabled={!videoMaterialConfig.list[0]}>从视频生成封面图</Button>
  735. } */}
  736. {/* 多图 */}
  737. {
  738. item.name === 'image_list' && <Form.Item
  739. noStyle
  740. rules={[{ required: true, message: '请选择素材!' }]}
  741. name={item.name}
  742. style={item.description === '图片' && adcreative_template?.adcreativeElements?.some(item => item.name === 'video') ? { order: 2 } : {}}
  743. >
  744. <div className={`${styles.box} ${item.arrayProperty.maxNumber >= 3 ? styles.image_list : styles.image}`} onClick={() => {
  745. init({ mediaType: 'IMG', num: item.arrayProperty.maxNumber, cloudSize: [[{ relation: '=', width: item.restriction.imageRestriction.width, height: item.restriction.imageRestriction.height }]], maxSize: item.restriction.imageRestriction.fileSize * 1024 })
  746. setTimeout(() => {
  747. set_selectImgVisible(true)
  748. setImgMaterialConfig({
  749. ...imgMaterialConfig,
  750. type: item.name,
  751. max: item.arrayProperty.maxNumber,
  752. adcreativeTemplateId
  753. })
  754. }, 100)
  755. }}>
  756. {
  757. Array(item.arrayProperty.maxNumber).fill('').map((arr, index) => {
  758. return <p key={index}>
  759. {
  760. imgMaterialConfig?.list[index] ? <img src={imgMaterialConfig?.list[index].url} /> : <>
  761. <span>{`推荐尺寸(${item.restriction.imageRestriction.width} x ${item.restriction.imageRestriction.height})`}</span>
  762. <span>{`${item.restriction.imageRestriction.fileFormat?.map(str => str?.replace('IMAGE_TYPE_', ''))};小于 ${item.restriction.imageRestriction.fileSize}KB`}</span>
  763. </>
  764. }
  765. </p>
  766. })
  767. }
  768. </div>
  769. </Form.Item>
  770. }
  771. </Form.Item>
  772. })
  773. }
  774. </div>}
  775. {/* 标题 */}
  776. {
  777. adcreative_template?.adcreativeElements?.filter(item => item.name === 'title').map(item => {
  778. return <div key={item.fieldType}>
  779. <Form.Item label={<strong>{item.description}(选填)</strong>} className={'my_title'} >
  780. <Form.Item name={item.name} rules={[{ pattern: RegExp(item.restriction.textRestriction.textPattern?.replace(/\+/ig, `{1,${item.restriction.textRestriction.maxLength}}`)), message: '请输入正确的' + item.description }]} noStyle>
  781. <Input
  782. placeholder={'请输入' + item.description}
  783. style={{ width: 500 }}
  784. allowClear
  785. onFocus={() => {
  786. settitleshow(true)
  787. textList({ maxTextLength: item.restriction.textRestriction.maxLength })
  788. }}
  789. onChange={(e) => {
  790. let value = e.target.value
  791. textList({ maxTextLength: item.restriction.textRestriction.maxLength, keyword: value })
  792. }}
  793. />
  794. </Form.Item>
  795. <span>{`${titles?.length ?? 0}/${item.restriction.textRestriction.maxLength}`}</span>
  796. {
  797. titleShow && <List
  798. loading={getTextLsit?.loading}
  799. size="small"
  800. style={{ maxHeight: 300, overflowX: 'auto' }}
  801. bordered
  802. dataSource={getTextLsit?.data?.returnTexts}
  803. renderItem={(item: any) => <List.Item onClick={() => {
  804. form.setFieldsValue({ title: item.text })
  805. settitleshow(false)
  806. }}><span >{item.text}{item.tag && <span className={styles.crt}>{'CTR 高'}</span>}</span></List.Item>}
  807. />
  808. }
  809. </Form.Item>
  810. </div>
  811. })
  812. }
  813. {//过滤了不必传和品牌名称,品牌标识图(外部传)短视频结构(组装使用)
  814. adcreative_template?.adcreativeElements?.filter(item => item.required && item.name === 'description').map(item => {
  815. let maxNum = adcreativeTemplateId === 1708 || adcreativeTemplateId === 1707 ? pupState.xd_show ? 10 : item.restriction.textRestriction.maxLength : item.restriction.textRestriction.maxLength
  816. return <div key={item.fieldType}>
  817. <Form.Item label={<strong>{item.description}</strong>} className={'my_description'}>
  818. <Form.Item name={item.name} noStyle rules={[{ required: true, pattern: RegExp(item.restriction.textRestriction.textPattern?.replace(/\+/ig, `{1,${maxNum}}`)), message: '请输入正确的' + item.description }]}>
  819. <Input
  820. placeholder={'请输入' + item.description}
  821. style={{ width: 500 }}
  822. onFocus={() => {
  823. setdescriptionshow(true)
  824. textList({ maxTextLength: maxNum })
  825. }}
  826. onChange={(e) => {
  827. let value = e.target.value
  828. textList({ maxTextLength: maxNum, keyword: value })
  829. }}
  830. allowClear
  831. />
  832. </Form.Item>
  833. <span>{`${description?.length ?? 0}/${maxNum}`}</span>
  834. {
  835. descriptionShow && <List
  836. loading={getTextLsit?.loading}
  837. size="small"
  838. style={{ maxHeight: 300, overflowX: 'auto' }}
  839. bordered
  840. dataSource={getTextLsit?.data?.returnTexts}
  841. renderItem={(item: any) => <List.Item onClick={(e: any) => {
  842. form.setFieldsValue({ description: item.text })
  843. setdescriptionshow(false)
  844. }}><span >{item.text}{item.tag && <span className={styles.crt}>{'CTR 高'}</span>}</span></List.Item>}
  845. />
  846. }
  847. </Form.Item>
  848. </div>
  849. })
  850. }
  851. {/* ============================================================落地页============================================================= */}
  852. {adcreativeTemplateId ? <Form.Item label={<strong>落地页</strong>} name='pageType' >
  853. <Radio.Group>
  854. {
  855. pageTypeList?.map((item: any) => {
  856. return <Radio.Button value={item.pageType} key={item.pageType} disabled={!item.description.includes('微信原生推广页')}>{item.description.includes('微信原生推广页') ? '微信原生推广页' : item.description}</Radio.Button>
  857. })
  858. }
  859. </Radio.Group>
  860. </Form.Item> : <div style={{ minHeight: 400, display: 'flex', justifyContent: 'center', alignItems: 'center' }}>
  861. <Empty description="请先选择创意形式" />
  862. </div>}
  863. {
  864. pageType === 'PAGE_TYPE_CANVAS_WECHAT' && isShowSc && <Form.Item label={<strong>素材选项</strong>} name='overrideCanvasHeadOption'>
  865. <Radio.Group >
  866. {
  867. adcreativeTemplateId && creativeConfig[adcreativeTemplateId]?.overrideCanvasHeadOption?.map((item: string | number) => {
  868. return <Radio value={item} key={item}>{overrideCanvasHeadOptionEnum[item]}</Radio>
  869. })
  870. }
  871. </Radio.Group>
  872. </Form.Item>
  873. }
  874. {/* ============================================================普通行动按钮============================================================= */}
  875. {
  876. pupState.xd_show && <Form.Item label={<strong>行动按钮</strong>} name='actionBtn' valuePropName="checked">
  877. <Switch checkedChildren="开启" unCheckedChildren="关闭" />
  878. </Form.Item>
  879. }
  880. {
  881. actionBtn && <>
  882. <Form.Item name='linkNameType' label={<strong>按钮文案</strong>}>
  883. <Select style={{ width: 200 }} showSearch filterOption={(input, option) =>
  884. (option!.children as unknown as string).toLowerCase().includes(input.toLowerCase())
  885. } allowClear>
  886. {
  887. linkNameList?.map((item: any) => {
  888. return <Select.Option value={item.linkNameType} key={item.linkNameType}>{item.description}</Select.Option>
  889. })
  890. }
  891. </Select>
  892. </Form.Item>
  893. <Form.Item label={<strong>跳转落地页</strong>}>
  894. <Form.Item name='linkPageType' noStyle>
  895. <Radio.Group style={{ display: 'flex' }}>
  896. {
  897. linkPageList?.map((item: { linkPageType: string; description: string; }, index: number) => {
  898. return <Radio.Button value={item.linkPageType} key={item.linkPageType} >{item.description}</Radio.Button>
  899. })
  900. }
  901. </Radio.Group>
  902. </Form.Item>
  903. {/* 自定义落地页地址 */}
  904. {linkPageType === "LINK_PAGE_TYPE_DEFAULT" && <Form.Item name='pageUrl' rules={[{ required: true, message: '请输入自定义落地页地址' }]} style={{ marginTop: 10, marginBottom: 0 }}>
  905. <Input placeholder='请输入自定义落地页地址' style={{ width: 300 }} />
  906. </Form.Item>}
  907. {/* 小程序 */}
  908. {
  909. linkPageType === "LINK_PAGE_TYPE_MINI_PROGRAM_WECHAT" && <Form.Item noStyle >
  910. <Form.Item rules={[{ required: true, message: '请输入小程序原始ID' }]} name='miniProgramId' style={{ marginTop: 10, marginBottom: 0 }} >
  911. <Input placeholder='请输入小程序原始ID' style={{ width: 300 }} />
  912. </Form.Item>
  913. <Form.Item rules={[{ required: true, message: '请输入小程序链接' }]} name='miniProgramPath' style={{ marginTop: 10, marginBottom: 0 }}>
  914. <Input placeholder='请输入小程序链接' style={{ width: 300 }} />
  915. </Form.Item>
  916. </Form.Item>
  917. }
  918. </Form.Item>
  919. {/* 落地页 */}
  920. </>
  921. }
  922. {/* ============================================================特殊行动按钮============================================================= */}
  923. {
  924. adcreative_template?.adcreativeElements?.find(item => item.name === 'button_text') && <Form.Item label={<strong>行动按钮</strong>} >
  925. <Form.Item valuePropName="checked" noStyle >
  926. <Switch checkedChildren="开启" unCheckedChildren="关闭" checked={true} disabled defaultChecked={true} />
  927. </Form.Item>
  928. </Form.Item>
  929. }
  930. {
  931. adcreative_template?.adcreativeElements?.find(item => item.name === 'button_text') && <Form.Item name='buttonText' label={<strong>按钮文案</strong>} rules={[{ required: true, message: '请选择按钮文案!' }]}>
  932. <Select style={{ width: 200 }} showSearch filterOption={(input, option) =>
  933. (option!.children as unknown as string).toLowerCase().includes(input.toLowerCase())
  934. } allowClear>
  935. {
  936. adcreative_template?.adcreativeElements?.find(item => item.name === 'button_text')?.enumProperty?.enumeration?.map((item: any) => {
  937. return <Select.Option value={item.value} key={item.value}>{item.value}</Select.Option>
  938. })
  939. }
  940. </Select>
  941. </Form.Item>
  942. }
  943. {/* ============================================================数据展示============================================================= */}
  944. {pupState.sj_show && <Form.Item label={<strong>数据展示</strong>} name='dataShow' valuePropName="checked">
  945. <Switch checkedChildren="开启" unCheckedChildren="关闭" />
  946. </Form.Item>}
  947. {
  948. dataShow && <>
  949. <Form.Item name='conversionDataType' label={<strong>数据类型</strong>}>
  950. <Radio.Group>
  951. {
  952. conversionList?.conversion_data_type?.map((item: { value: string; description: string; }, index: number) => {
  953. return <Radio.Button value={item.value} key={item.value}>{item.description}</Radio.Button>
  954. })
  955. }
  956. </Radio.Group>
  957. </Form.Item>
  958. {conversionList?.conversion_target_type && conversionDataType === 'CONVERSION_DATA_ADMETRIC' && <Form.Item name='conversionTargetType' label={<strong>转化行为</strong>}>
  959. <Radio.Group>
  960. {
  961. conversionList?.conversion_target_type?.map((item: { value: string; description: string; }, index: number) => {
  962. return <Radio.Button value={item.value} key={item.value}>{item.description}</Radio.Button>
  963. })
  964. }
  965. </Radio.Group>
  966. </Form.Item>}
  967. </>
  968. }
  969. {/* ============================================================视频结束页============================================================= */}
  970. {pupState.sp_show && <Form.Item label={<strong>视频结束页</strong>} name='videoOver' valuePropName="checked">
  971. <Switch checkedChildren="开启" unCheckedChildren="关闭" />
  972. </Form.Item>}
  973. {
  974. videoOver && <>
  975. <Form.Item name='endPageType' label={<strong>视频结束页类型</strong>} >
  976. <Radio.Group>
  977. {
  978. adcreative_template?.adcreativeElements?.filter(item => item.name === 'end_page_type')[0]?.enumProperty?.enumeration?.map((item) => {
  979. return <Radio.Button value={item.value} key={item.value}>{item.description}</Radio.Button>
  980. })
  981. }
  982. </Radio.Group>
  983. </Form.Item>
  984. <div className={'my_endPageDesc'} >
  985. <Form.Item label={<strong>结束文案</strong>}>
  986. <Form.Item name='endPageDesc' rules={[{ required: true, pattern: RegExp("^[^\\<\\>\\&'\\\"\\/\\x08\\x09\\x0A\\x0D\\\\]{1,12}$"), message: '请输入正确的结束页文案' }]} noStyle>
  987. <Input
  988. placeholder='请输入结束页文案'
  989. style={{ width: 300 }}
  990. onFocus={() => {
  991. setendPageDescnshow(true)
  992. textList({ maxTextLength: 12 })
  993. }}
  994. onChange={(e) => {
  995. let value = e.target.value
  996. textList({ maxTextLength: 12, keyword: value })
  997. }}
  998. allowClear
  999. />
  1000. </Form.Item>
  1001. <span>{endPageDesc?.length || 0}/12</span>
  1002. {
  1003. endPageDescShow && <List
  1004. loading={getTextLsit?.loading}
  1005. size="small"
  1006. style={{ maxHeight: 300, maxWidth: 300, overflowX: 'auto' }}
  1007. bordered
  1008. dataSource={getTextLsit?.data?.returnTexts}
  1009. renderItem={(item: any) => <List.Item onClick={(e: any) => {
  1010. form.setFieldsValue({ endPageDesc: item.text })
  1011. setendPageDescnshow(false)
  1012. }}><span >{item.text}{item.tag && <span className={styles.crt}>{'CTR 高'}</span>}</span></List.Item>}
  1013. />
  1014. }
  1015. </Form.Item>
  1016. </div>
  1017. </>
  1018. }
  1019. </>
  1020. }
  1021. {/* ============================================================基本信息============================================================= */}
  1022. <Divider orientation='center'>基本信息</Divider>
  1023. {/* ============================================================创意名称============================================================= */}
  1024. <Form.Item label={<strong>创意名称</strong>} name='adcreativeName' rules={[{ required: true, message: '请输入广告名称!' }]}>
  1025. <Input placeholder='创意名称' style={{ width: 300 }} />
  1026. </Form.Item>
  1027. </Form>
  1028. {/* 选择图片素材 */}
  1029. {
  1030. selectImgVisible && <SelectCloud
  1031. visible={selectImgVisible}
  1032. onClose={() => {
  1033. set_selectImgVisible(false)
  1034. }}
  1035. sliderImgContent={imgMaterialConfig.list}
  1036. onChange={(content) => {
  1037. if (content.length > 0) {
  1038. form.setFieldsValue({ [imgMaterialConfig.type]: imgMaterialConfig.type })
  1039. }
  1040. setImgMaterialConfig({ ...imgMaterialConfig, list: content })
  1041. set_selectImgVisible(false)
  1042. }} />
  1043. }
  1044. {/* 选择视频素材 */}
  1045. {
  1046. selectVideoVisible && <SelectCloud
  1047. visible={selectVideoVisible}
  1048. onClose={() => set_selectVideoVisible(false)}
  1049. sliderImgContent={videoMaterialConfig.list}
  1050. onChange={(content) => {
  1051. if (content.length > 0) {
  1052. form.setFieldsValue({ [videoMaterialConfig.type]: videoMaterialConfig.type })
  1053. }
  1054. setVideoMaterialConfig({ ...videoMaterialConfig, list: content })
  1055. set_selectVideoVisible(false)
  1056. }} />
  1057. }
  1058. {/* 视频封面图弹窗 */}
  1059. {
  1060. videoImgsVisbile && <Modal
  1061. visible={videoImgsVisbile}
  1062. title={<div>生成封面图 <Switch checkedChildren="开启预览" unCheckedChildren="关闭预览" checked={videoImgs.preview} onChange={(checked) => { set_videoImgs({ ...videoImgs, preview: checked }) }} /></div>}
  1063. onOk={() => {
  1064. if (videoImgs.activeUrl) {
  1065. setImgMaterialConfig({ ...imgMaterialConfig, list: [{ url: videoImgs.activeUrl }] })
  1066. set_videoImgsVisbile(false)
  1067. } else {
  1068. message.error('请选择图片,获取使用取消按钮关闭弹窗!')
  1069. }
  1070. }}
  1071. onCancel={() => { set_videoImgsVisbile(false) }}
  1072. confirmLoading={getVideoCapture.loading}
  1073. width={600}
  1074. >
  1075. <Radio.Group className={styles.videoImgs} onChange={(e) => {
  1076. let url = e.target.value
  1077. set_videoImgs({ ...videoImgs, activeUrl: url })
  1078. }}>
  1079. {
  1080. videoImgs?.urlList?.map((item: any, index: number) => {
  1081. return <Radio.Button value={item} key={index}>
  1082. <Image src={item} preview={videoImgs.preview} />
  1083. </Radio.Button>
  1084. })
  1085. }
  1086. </Radio.Group>
  1087. </Modal>
  1088. }
  1089. </Modal >
  1090. }
  1091. export default CreativePup