addMaterial.tsx 54 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805
  1. import { CloseCircleOutlined, DeleteOutlined, PlusOutlined } from "@ant-design/icons"
  2. import { Button, Card, Dropdown, Empty, Form, InputNumber, Modal, Popconfirm, Space, message } from "antd"
  3. import React, { useEffect, useState } from "react"
  4. import styles from './index.less'
  5. import VideoNews from "@/pages/launchSystemNew/components/newsModal/videoNews"
  6. import { chunkArray1, getVideoImgUrl } from "@/utils/utils"
  7. import VideoFrameSelect from "@/pages/launchSystemV3/components/VideoFrameSelect"
  8. import New1Radio from "@/pages/launchSystemV3/components/New1Radio"
  9. import SelectCloudNew from "@/pages/launchSystemV3/material/cloudNew/selectCloudNew"
  10. interface Props {
  11. adLength: number,
  12. creativeTemplateId: number
  13. materialData: any
  14. deliveryMode: string,
  15. isSelectRemote?: boolean
  16. value?: any,
  17. visible?: boolean
  18. onClose?: () => void
  19. onChange?: (value: any) => void
  20. accountCreateLogs?: PULLIN.AccountCreateLogsProps[]
  21. }
  22. const AddMaterial: React.FC<Props> = ({ creativeTemplateId, materialData, deliveryMode, visible, isSelectRemote, value, onChange, onClose, adLength, accountCreateLogs }) => {
  23. /*********************************/
  24. const [form] = Form.useForm();
  25. const dynamicGroup = Form.useWatch('dynamicGroup', form)
  26. const mediaType = Form.useWatch('mediaType', form)
  27. const [materialConfig, setMaterialConfig] = useState<{
  28. adcreativeTemplateId?: number,
  29. type: string,
  30. cloudSize: { relation: string, width: number, height: number }[],
  31. list: any[],
  32. index: number,
  33. max: number,
  34. sliderImgContent: any,
  35. isGroup?: boolean
  36. }>({
  37. type: '',//类型
  38. cloudSize: [],//素材搜索条件
  39. list: [],//素材
  40. index: 0, // 素材组下标
  41. max: 1,//素材数量
  42. sliderImgContent: undefined
  43. })//图片素材配置
  44. const [selectVideoVisible, setSelectVideoVisible] = useState(false)
  45. const [mLength, setMLength] = useState<number>(1)
  46. const [videoUploads, setVideoUploads] = useState<any>()
  47. const [imgUploads, setImgUploads] = useState<any>()
  48. const [minNumber, setMinNumber] = useState<number>(3)
  49. const [mCount, setMCount] = useState<number>(1)
  50. const [selectCloudData, setSelectCloudData] = useState<{
  51. defaultParams: {
  52. sizeQueries?: {
  53. width: number,
  54. height: number,
  55. relation: string
  56. }[],
  57. materialType: 'image' | 'video'
  58. fileSize: number
  59. }
  60. num: number
  61. }>()
  62. /*********************************/
  63. useEffect(() => {
  64. if (materialData && Object.keys(materialData).length > 0) {
  65. let fKey = Object.keys(materialData)[0];
  66. let children = materialData[fKey]?.children
  67. let childrenKey = Object.keys(children)
  68. setMLength(childrenKey?.length)
  69. let videoData = childrenKey?.find(item => item === 'short_video1' || item === 'video_id')
  70. if (videoData) {
  71. setVideoUploads(children[videoData])
  72. }
  73. let imageData = childrenKey?.find(item => item === 'cover_id' || item === 'image_id')
  74. if (imageData) {
  75. setImgUploads(children[imageData])
  76. }
  77. let imageListData = childrenKey?.find(item => item === 'list')
  78. if (imageListData) {
  79. let data = children[imageListData]
  80. if (fKey === 'image_list') {
  81. setMinNumber(data.arrayProperty.mixNumber)
  82. setImgUploads({ ...data['children']['image_id'], arrayProperty: data.arrayProperty, name: 'image_list' })
  83. } else if (fKey === 'element_story') {
  84. setMinNumber(data.arrayProperty.mixNumber)
  85. setImgUploads({ ...data['children']['image'], arrayProperty: data.arrayProperty, name: 'element_story' })
  86. }
  87. }
  88. } else {
  89. setVideoUploads({})
  90. setImgUploads({})
  91. }
  92. }, [materialData])
  93. const setFrame = (url: string, num: number, field: string) => {
  94. let newDynamicGroup = dynamicGroup?.map((item: any, index: number) => {
  95. if (num === index) {
  96. if (item) {
  97. item[field] = { ...item[field], url, id: null }
  98. return { ...item }
  99. } else {
  100. return { [field]: { url, id: null, materialType: 0 } }
  101. }
  102. }
  103. return item
  104. })
  105. form.setFieldsValue({ dynamicGroup: newDynamicGroup })
  106. }
  107. const handleOk = (values: any) => {
  108. const { mediaType, dynamicGroup } = values
  109. if (mediaType === 2 && dynamicGroup.length > adLength) {
  110. message.error({
  111. content: `创意组分配规则选择“顺序分配到广告”时,创意组总数必须小于等于广告总数。当前广告总数:${adLength},创意组总数:${dynamicGroup.length}`,
  112. duration: 8
  113. })
  114. return
  115. }
  116. onChange?.({ mediaType, dynamicMaterialDTos: { dynamicGroup } })
  117. }
  118. useEffect(() => {
  119. console.log('value--->', value)
  120. if (value) {
  121. const { dynamicMaterialDTos, mediaType } = value
  122. form.setFieldsValue({ ...dynamicMaterialDTos, mediaType })
  123. }
  124. }, [value])
  125. const clearTem = (index: number, count: number) => {
  126. let newDynamicGroup = dynamicGroup?.map((item: any, i: number) => {
  127. if (i === index) {
  128. let oldList = item?.list?.filter((_: any, li: number) => count !== li)
  129. return { list: oldList }
  130. }
  131. return item
  132. })
  133. form.setFieldsValue({ dynamicGroup: newDynamicGroup })
  134. }
  135. const selectGroupImg = (index: number, num: number) => {
  136. setSelectCloudData({ defaultParams: { sizeQueries: [{ width: 800, height: 800, relation: '=' }], fileSize: 400 * 1024, materialType: 'image' }, num })
  137. setMaterialConfig({
  138. ...materialConfig,
  139. type: 'image',
  140. max: num,
  141. index,
  142. adcreativeTemplateId: creativeTemplateId,
  143. isGroup: true
  144. })
  145. setTimeout(() => {
  146. setSelectVideoVisible(true)
  147. }, 100)
  148. }
  149. // 获取组件化创意素材数量
  150. const getComponentCount = (list: any[]): string => {
  151. let arrayImgCount = 0, imageCount = 0, videoCount = 0
  152. list?.forEach((item: any) => {
  153. if (Array.isArray(item)) {
  154. arrayImgCount++
  155. } else if (item?.url?.includes('mp4')) {
  156. videoCount++
  157. } else {
  158. imageCount++
  159. }
  160. })
  161. return `${imageCount}张图片,${videoCount}个视频,${arrayImgCount}个组图`
  162. }
  163. return <Modal
  164. title={<Space>
  165. <strong style={{ fontSize: 20 }}>创意素材</strong>
  166. {deliveryMode === 'DELIVERY_MODE_CUSTOMIZE' ? <>
  167. {videoUploads && Object.keys(videoUploads)?.length > 0 && <Button type="link" onClick={() => {
  168. setSelectCloudData({ defaultParams: { sizeQueries: creativeTemplateId === 1708 ? [{ relation: '>=', width: 1280, height: 720 }] : [{ relation: '>=', width: videoUploads.restriction.videoRestriction.minWidth, height: videoUploads.restriction.videoRestriction.minHeight }], fileSize: videoUploads.restriction.videoRestriction.fileSize * 1024, materialType: 'video' }, num: 100 })
  169. setMaterialConfig({
  170. ...materialConfig,
  171. type: videoUploads.name,
  172. max: 1,
  173. index: 99999,
  174. adcreativeTemplateId: creativeTemplateId
  175. })
  176. setTimeout(() => {
  177. setSelectVideoVisible(true)
  178. }, 100)
  179. }}>批量添加视频素材</Button>}
  180. {imgUploads && Object.keys(imgUploads)?.length > 0 && <Button type="link" onClick={() => {
  181. setSelectCloudData({ defaultParams: { sizeQueries: [{ relation: '=', width: imgUploads.restriction.imageRestriction.width, height: imgUploads.restriction.imageRestriction.height }], fileSize: imgUploads.restriction.imageRestriction.fileSize * 1024, materialType: 'image' }, num: 100 })
  182. setMaterialConfig({
  183. ...materialConfig,
  184. type: imgUploads.name,
  185. max: (imgUploads.name === 'image_list' || imgUploads.name === 'element_story') ? imgUploads.arrayProperty.maxNumber : 1,
  186. index: 99999,
  187. adcreativeTemplateId: creativeTemplateId
  188. })
  189. setTimeout(() => {
  190. setSelectVideoVisible(true)
  191. }, 100)
  192. }}>批量添加图片素材</Button>}
  193. </> : <>
  194. <InputNumber size="small" min={1} style={{ width: 50 }} value={mCount} max={15} onChange={(e) => setMCount(e || 0)} />
  195. <Button type="link" onClick={() => {
  196. setSelectCloudData({
  197. num: 100,
  198. defaultParams: {
  199. materialType: 'image',
  200. sizeQueries: [
  201. { relation: '=', width: 800, height: 800 },
  202. { relation: '=', width: 1280, height: 720 },
  203. { relation: '=', width: 720, height: 1280 },
  204. { relation: '=', width: 960, height: 334 },
  205. { relation: '=', width: 480, height: 320 },
  206. ],
  207. fileSize: 400 * 1024
  208. }
  209. })
  210. setMaterialConfig({
  211. ...materialConfig,
  212. type: 'image',
  213. max: 100,
  214. index: 20000,
  215. adcreativeTemplateId: creativeTemplateId,
  216. isGroup: false
  217. })
  218. setTimeout(() => {
  219. setSelectVideoVisible(true)
  220. }, 100)
  221. }}>批量添加图片素材</Button>
  222. <Button type="link" onClick={() => {
  223. setSelectCloudData({
  224. num: 100,
  225. defaultParams: {
  226. materialType: 'video',
  227. sizeQueries: [
  228. { relation: '>=', width: 1280, height: 720 },
  229. { relation: '>=', width: 720, height: 1280 }
  230. ],
  231. fileSize: 512000 * 1024
  232. }
  233. })
  234. setMaterialConfig({
  235. ...materialConfig,
  236. type: 'video',
  237. max: 100,
  238. index: 20000,
  239. adcreativeTemplateId: creativeTemplateId,
  240. isGroup: false
  241. })
  242. setTimeout(() => {
  243. setSelectVideoVisible(true)
  244. }, 100)
  245. }}>批量添加视频素材</Button>
  246. </>}
  247. {(dynamicGroup && dynamicGroup?.length > 1) && <Popconfirm
  248. title="是否清空?"
  249. onConfirm={() => form.setFieldsValue({ dynamicGroup: [undefined] })}
  250. okText="是"
  251. cancelText="否"
  252. >
  253. <Button type="link" danger>一键清空</Button>
  254. </Popconfirm>}
  255. </Space>}
  256. open={visible}
  257. onCancel={onClose}
  258. footer={null}
  259. width={900}
  260. className={`modalResetCss`}
  261. bodyStyle={{ padding: '0 0 40px', position: 'relative', borderRadius: '0 0 8px 8px' }}
  262. maskClosable={false}
  263. >
  264. <Form
  265. form={form}
  266. name="newMaterial"
  267. labelAlign='left'
  268. layout="vertical"
  269. colon={false}
  270. style={{ backgroundColor: '#f1f4fc', maxHeight: 650, overflow: 'hidden', overflowY: 'auto', padding: 10, borderRadius: '0 0 8px 8px' }}
  271. scrollToFirstError={{
  272. behavior: 'smooth',
  273. block: 'center'
  274. }}
  275. onFinishFailed={({ errorFields }) => {
  276. message.error(errorFields?.[0]?.errors?.[0])
  277. }}
  278. onFinish={handleOk}
  279. initialValues={{
  280. dynamicGroup: [undefined]
  281. }}
  282. >
  283. <Card className="cardResetCss" style={{ marginBottom: 10 }}>
  284. <Form.Item name="mediaType" label={<strong>创意组分配规则</strong>} style={{ marginBottom: 0 }} rules={[{ required: true, message: '请选择创意组分配规则!' }]}>
  285. <New1Radio
  286. data={[{ label: '全广告复用', value: 0 }, { label: '平均分配到广告', value: 1 }, { label: '顺序分配到广告', value: 2 }, { label: '账号下平均分配到广告', value: 3 }]}
  287. onChange={(e) => {
  288. if (e === 2 && dynamicGroup?.length > adLength) {
  289. form.setFieldsValue({ dynamicGroup: dynamicGroup.slice(0, adLength) })
  290. }
  291. }}
  292. />
  293. </Form.Item>
  294. </Card>
  295. <Form.List name="dynamicGroup">
  296. {(fields, { add, remove }) => (<>
  297. <div style={{ display: 'flex', flexWrap: 'wrap', gap: 10 }}>
  298. {fields.map((field, num) => (<Card
  299. title={<Space>
  300. <strong style={{ fontSize: 18 }}>创意组{num + 1}</strong>
  301. {deliveryMode === 'DELIVERY_MODE_COMPONENT' && <>
  302. <Dropdown
  303. menu={{
  304. items: [
  305. {
  306. label: '添加视频',
  307. key: 'addVideo',
  308. onClick: () => {
  309. setSelectCloudData({
  310. num: 15 - (dynamicGroup?.[num]?.['list']?.length || 0),
  311. defaultParams: {
  312. materialType: 'video',
  313. sizeQueries: [
  314. { relation: '>=', width: 1280, height: 720 },
  315. { relation: '>=', width: 720, height: 1280 }
  316. ],
  317. fileSize: 512000 * 1024
  318. }
  319. })
  320. setMaterialConfig({
  321. ...materialConfig,
  322. type: 'video',
  323. max: 15 - (dynamicGroup?.[num]?.['list']?.length || 0),
  324. index: num,
  325. adcreativeTemplateId: creativeTemplateId,
  326. isGroup: false
  327. })
  328. setTimeout(() => {
  329. setSelectVideoVisible(true)
  330. }, 100)
  331. }
  332. },
  333. {
  334. label: '添加图片',
  335. key: 'addImg',
  336. onClick: () => {
  337. setSelectCloudData({
  338. num: 15 - (dynamicGroup?.[num]?.['list']?.length || 0),
  339. defaultParams: {
  340. materialType: 'image',
  341. sizeQueries: [
  342. { relation: '=', width: 800, height: 800 },
  343. { relation: '=', width: 1280, height: 720 },
  344. { relation: '=', width: 720, height: 1280 },
  345. { relation: '=', width: 960, height: 334 },
  346. { relation: '=', width: 480, height: 320 },
  347. ],
  348. fileSize: 400 * 1024
  349. }
  350. })
  351. setMaterialConfig({
  352. ...materialConfig,
  353. type: 'image',
  354. max: 15 - (dynamicGroup?.[num]?.['list']?.length || 0),
  355. index: num,
  356. adcreativeTemplateId: creativeTemplateId,
  357. isGroup: false
  358. })
  359. setTimeout(() => {
  360. setSelectVideoVisible(true)
  361. }, 100)
  362. }
  363. }
  364. ]
  365. }}
  366. placement="bottomLeft"
  367. arrow
  368. >
  369. <Button type="primary">添加图片/视频</Button>
  370. </Dropdown>
  371. <Dropdown
  372. menu={{
  373. items: [
  374. { label: '1:1 九图', key: '1', disabled: dynamicGroup?.[num]?.['list']?.length >= 15, onClick: () => { selectGroupImg(num, 9) } },
  375. { label: '1:1 六图', key: '1', disabled: dynamicGroup?.[num]?.['list']?.length >= 15, onClick: () => { selectGroupImg(num, 6) } },
  376. { label: '1:1 三图', key: '2', disabled: dynamicGroup?.[num]?.['list']?.length >= 15, onClick: () => { selectGroupImg(num, 3) } },
  377. { label: '1:1 四图', key: '3', disabled: dynamicGroup?.[num]?.['list']?.length >= 15, onClick: () => { selectGroupImg(num, 4) } },
  378. ]
  379. }}
  380. placement="bottomLeft"
  381. arrow
  382. >
  383. <Button type="primary">上传组图</Button>
  384. </Dropdown>
  385. </>}
  386. </Space>}
  387. className="cardResetCss"
  388. key={field.key}
  389. style={{ width: deliveryMode === 'DELIVERY_MODE_CUSTOMIZE' ? ([641, 642, 643, 720, 721, 722, 1529, 618].includes(creativeTemplateId) || dynamicGroup?.length === 1) ? '100%' : 'calc(50% - 5px)' : '100%' }}
  390. extra={fields?.length > 1 && <DeleteOutlined className={styles.clear} onClick={() => remove(field.name)} style={{ color: 'red' }} />}
  391. >
  392. {deliveryMode === 'DELIVERY_MODE_CUSTOMIZE' ? <Space size={30} style={{ width: '100%' }} className={styles.space}>
  393. {Object.keys(materialData)?.map(key => {
  394. let m = materialData[key]
  395. let children = m.children
  396. return Object.keys(children).map(k => {
  397. let item = children[k]
  398. if (k === 'short_video1' || k === 'video_id') {
  399. return <Form.Item
  400. {...field}
  401. label={<strong>{item.description}</strong>}
  402. rules={[{ required: true, message: '请选择素材!' }]}
  403. name={[field.name, item.name]}
  404. key={k}
  405. >
  406. <div className={`${styles.box} ${styles.video}`} style={{ width: 300, height: 160 }} onClick={() => {
  407. setSelectCloudData({
  408. num: 1,
  409. defaultParams: {
  410. materialType: 'video',
  411. sizeQueries: creativeTemplateId === 1708 ? [{ relation: '=', width: 1280, height: 720 }] : [{ relation: item.restriction.videoRestriction.minWidth > item.restriction.videoRestriction.minHeight ? '=' : '>=', width: item.restriction.videoRestriction.minWidth, height: item.restriction.videoRestriction.minHeight }],
  412. fileSize: item.restriction.videoRestriction.fileSize * 1024
  413. }
  414. })
  415. setMaterialConfig({
  416. ...materialConfig,
  417. type: item.name,
  418. max: 1,
  419. index: num,
  420. adcreativeTemplateId: creativeTemplateId
  421. })
  422. setTimeout(() => {
  423. setSelectVideoVisible(true)
  424. }, 100)
  425. }}>
  426. <div className={styles.p}>
  427. {dynamicGroup?.length > 0 && dynamicGroup[num] && Object.keys(dynamicGroup[num])?.includes(item.name) ? <VideoNews keyFrameImageUrl={dynamicGroup[num][item.name]['keyFrameImageUrl']} src={dynamicGroup[num][item.name]['url']} style={{ display: 'block', width: 'auto', margin: 0, height: '100%' }} maskImgStyle={{ position: 'absolute', top: '50%', left: '50%', width: 40, height: 40, transform: 'translate(-50%, -50%)', zIndex: 10 }} /> : <>
  428. <span>{`推荐尺寸(${creativeTemplateId === 1708 ? 1280 : item.restriction.videoRestriction.minWidth} x ${creativeTemplateId === 1708 ? 720 : item.restriction.videoRestriction.minHeight})`}</span>
  429. <span>{`${item.restriction.videoRestriction.fileFormat?.map((str: any) => str?.replace('MEDIA_TYPE_', ''))};< ${item.restriction.videoRestriction.fileSize / 1024}M;时长 ≥ ${item.restriction.videoRestriction.minDuration}s,≤ ${item.restriction.videoRestriction.maxDuration}s,必须带有声音`}</span>
  430. </>}
  431. </div>
  432. </div>
  433. </Form.Item>
  434. }
  435. if (item.name === 'image_id' || item.name === 'cover_id') {
  436. return <Form.Item
  437. {...field}
  438. label={<strong>{item.description}</strong>}
  439. rules={[{ required: true, message: '请选择素材!' }]}
  440. name={[field.name, item.name]}
  441. key={key}
  442. >
  443. <Space align="end">
  444. <div className={`${styles.box} ${styles.image}`} style={{ width: 300, height: 160 }} onClick={() => {
  445. setSelectCloudData({
  446. num: 1,
  447. defaultParams: {
  448. materialType: 'image',
  449. sizeQueries: [{ relation: '=', width: item.restriction.imageRestriction.width, height: item.restriction.imageRestriction.height }],
  450. fileSize: item.restriction.imageRestriction.fileSize * 1024
  451. }
  452. })
  453. setMaterialConfig({
  454. ...materialConfig,
  455. type: item.name,
  456. max: 1,
  457. index: num,
  458. adcreativeTemplateId: creativeTemplateId
  459. })
  460. setTimeout(() => {
  461. setSelectVideoVisible(true)
  462. }, 100)
  463. }}>
  464. <p>
  465. {dynamicGroup?.length > 0 && dynamicGroup[num] && Object.keys(dynamicGroup[num])?.includes(item.name) ? <img src={dynamicGroup[num][item.name]['url']} /> : <>
  466. <span>{`推荐尺寸(${item.restriction.imageRestriction.width} x ${item.restriction.imageRestriction.height})`}</span>
  467. <span>{`${item.restriction.imageRestriction.fileFormat?.map((str: any) => str?.replace('IMAGE_TYPE_', ''))};小于 ${item.restriction.imageRestriction.fileSize}KB`}</span>
  468. </>}
  469. </p>
  470. </div>
  471. {videoUploads && Object.keys(videoUploads)?.length > 0 && <div style={{ width: 32 }}>
  472. {dynamicGroup?.length > 0 && dynamicGroup[num] && ((Object.keys(dynamicGroup[num])?.includes('video_id') && dynamicGroup[num]['video_id']['materialType'] === 0) || (Object.keys(dynamicGroup[num])?.includes('short_video1') && dynamicGroup[num]['short_video1']['materialType'] === 0)) && <VideoFrameSelect onChange={(e) => setFrame(e, num, item.name)} url={dynamicGroup[num]?.['video_id']?.['url'] || dynamicGroup[num]?.['short_video1']?.['url']} />}
  473. </div>}
  474. </Space>
  475. </Form.Item>
  476. }
  477. if (item.name === 'list') {
  478. let name = ''
  479. let imageData: any = {}
  480. if (key === 'image_list') {
  481. imageData = item.children.image_id
  482. name = 'image_list';
  483. } else if (key === 'element_story') {
  484. imageData = item.children.image
  485. name = 'element_story'
  486. }
  487. return <Form.Item
  488. {...field}
  489. label={<strong>{imageData.description}</strong>}
  490. rules={[
  491. { required: true, type: 'array', len: minNumber || item.arrayProperty.maxNumber, message: '素材数量不对!' },
  492. { required: true, message: '请选择素材!' },
  493. ]}
  494. name={[field.name, name]}
  495. key={key}
  496. >
  497. <div className={`${styles.box} ${item.arrayProperty.maxNumber >= 3 ? styles.image_list : styles.imageMater}`} style={item.arrayProperty.maxNumber >= 3 ? { flexFlow: 'row', width: '100%', gap: 2 } : {}} onClick={() => {
  498. setSelectCloudData({
  499. num: item.arrayProperty.maxNumber,
  500. defaultParams: {
  501. materialType: 'image',
  502. sizeQueries: [{ relation: '=', width: imageData.restriction.imageRestriction.width, height: imageData.restriction.imageRestriction.height }],
  503. fileSize: imageData.restriction.imageRestriction.fileSize * 1024
  504. }
  505. })
  506. setMaterialConfig({
  507. ...materialConfig,
  508. type: name,
  509. max: item.arrayProperty.maxNumber,
  510. index: num,
  511. adcreativeTemplateId: creativeTemplateId
  512. })
  513. setTimeout(() => {
  514. setSelectVideoVisible(true)
  515. }, 100)
  516. }}>
  517. {Array(item.arrayProperty.maxNumber).fill('').map((arr, index1) => {
  518. return <p key={index1} style={item.arrayProperty.maxNumber === 9 ? { width: 92, height: 92 } : item.arrayProperty.maxNumber >= 3 ? { width: 130, height: 130 } : { justifyContent: 'center' }}>
  519. {dynamicGroup?.length > 0 && dynamicGroup[num] && Object.keys(dynamicGroup[num])?.includes(name) && dynamicGroup[num][name][index1] ? <img src={dynamicGroup[num][name][index1]['url']} /> : <>
  520. <span>{`推荐尺寸(${imageData.restriction.imageRestriction.width} x ${imageData.restriction.imageRestriction.height})`}</span>
  521. <span>{`${imageData.restriction.imageRestriction.fileFormat?.map((str: any) => str?.replace('IMAGE_TYPE_', ''))};小于 ${imageData.restriction.imageRestriction.fileSize}KB`}</span>
  522. </>}
  523. </p>
  524. })}
  525. </div>
  526. </Form.Item>
  527. }
  528. return null
  529. })
  530. })}
  531. </Space> : <Form.Item
  532. {...field}
  533. label={<strong>创意素材</strong>}
  534. rules={[{ required: true, message: '请选择素材!' }]}
  535. name={[field.name, 'list']}
  536. >
  537. <div className={`${styles.box} ${styles.video}`} style={{ width: '100%', height: 'auto', backgroundColor: 'rgb(247, 249, 252)' }}>
  538. {dynamicGroup?.length && dynamicGroup?.[num]?.['list']?.length > 0 ? <div className={styles.boxList}>
  539. <div className={styles.boxList_title}>
  540. <span>上传素材 <span style={{ marginLeft: 5, color: '#999', fontWeight: 'normal' }}>已选:{getComponentCount(dynamicGroup?.[num]?.['list'])}</span></span>
  541. <a onClick={() => {
  542. let newDynamicGroup = dynamicGroup?.map((item: any, i: number) => {
  543. if (i === num) {
  544. return { list: [] }
  545. }
  546. return item
  547. })
  548. form.setFieldsValue({ dynamicGroup: newDynamicGroup })
  549. }}>清空</a>
  550. </div>
  551. <div className={styles.boxList_body}>
  552. {dynamicGroup?.[num]?.['list']?.map((item: any, index: number) => {
  553. if (Array.isArray(item)) {
  554. let length = item.length
  555. return <div className={styles.boxList_body_item} key={index}>
  556. <div className={styles.tag}>{length}图</div>
  557. <div className={styles.content}>
  558. {item.map((l, i) => <img src={l?.url} key={i} style={{ width: length >= 6 ? 33.3 : 49.9 }} />)}
  559. </div>
  560. <div className={styles.clear} onClick={() => { clearTem(num, index) }}><CloseCircleOutlined /></div>
  561. </div>
  562. } else if (item?.url?.includes('mp4') || item?.keyFrameImageUrl) {
  563. return <div className={styles.boxList_body_item} key={index}>
  564. <div className={styles.content}>
  565. <VideoNews src={item?.url} keyFrameImageUrl={item?.keyFrameImageUrl} style={{ width: 100, height: 100 }} maskBodyStyle={{ backgroundColor: "rgba(242, 246, 254, 0.1)" }} />
  566. </div>
  567. <div className={styles.clear} onClick={() => { clearTem(num, index) }}><CloseCircleOutlined /></div>
  568. </div>
  569. } else {
  570. return <div className={styles.boxList_body_item} key={index}>
  571. <div className={styles.content}><img src={item?.url} /></div>
  572. <div className={styles.clear} onClick={() => { clearTem(num, index) }}><CloseCircleOutlined /></div>
  573. </div>
  574. }
  575. })}
  576. </div>
  577. </div> : <Empty image={Empty.PRESENTED_IMAGE_SIMPLE} description="暂无素材内容,可通过上方添加" />}
  578. </div>
  579. </Form.Item>}
  580. </Card>))}
  581. </div>
  582. {!(mediaType === 2 && dynamicGroup?.length >= adLength) && <Form.Item style={{ marginBottom: 0, marginTop: 10 }}>
  583. <Button type="dashed" style={{ color: '#1890ff' }} onClick={() => add()} block icon={<PlusOutlined />}>添加创意组</Button>
  584. </Form.Item>}
  585. </>)}
  586. </Form.List>
  587. <Form.Item className="submit_pull">
  588. <Space>
  589. <Button onClick={onClose}>取消</Button>
  590. <Button type="primary" htmlType="submit" className="modalResetCss">
  591. 确定
  592. </Button>
  593. </Space>
  594. </Form.Item>
  595. </Form>
  596. {/* 选择素材 */}
  597. {(selectVideoVisible && selectCloudData) && <SelectCloudNew
  598. {...selectCloudData}
  599. accountCreateLogs={accountCreateLogs}
  600. visible={selectVideoVisible}
  601. isGroup={materialConfig?.isGroup}
  602. sliderImgContent={materialConfig.index === 99999 ? undefined :
  603. materialConfig.type === 'element_story' ? (dynamicGroup[materialConfig.index] && Object.keys(dynamicGroup[materialConfig.index])?.includes('element_story')) ? dynamicGroup[materialConfig.index]['element_story']?.map((item: any) => ({ oss_url: item.url, id: item.id, materialType: item?.materialType, material_type: selectCloudData.defaultParams.materialType, })) : undefined :
  604. materialConfig.type === 'image_list' ? (dynamicGroup[materialConfig.index] && Object.keys(dynamicGroup[materialConfig.index])?.includes('image_list')) ? dynamicGroup[materialConfig.index]['image_list']?.map((item: any) => ({ oss_url: item.url, id: item.id, materialType: item?.materialType, material_type: selectCloudData.defaultParams.materialType, })) : undefined :
  605. (dynamicGroup[materialConfig.index] && Object.keys(dynamicGroup[materialConfig.index])?.includes(materialConfig.type)) ? [{ oss_url: dynamicGroup[materialConfig.index][materialConfig.type]['url'], id: dynamicGroup[materialConfig.index][materialConfig.type]['id'], material_type: selectCloudData.defaultParams.materialType, materialType: dynamicGroup[materialConfig.index][materialConfig.type]?.['materialType'], key_frame_image_url: dynamicGroup[materialConfig.index][materialConfig.type]?.['keyFrameImageUrl'] }] : undefined
  606. }
  607. onClose={() => {
  608. setSelectVideoVisible(false)
  609. setSelectCloudData(undefined)
  610. }}
  611. onChange={(content: any) => {
  612. if (content.length > 0) {
  613. if (deliveryMode === 'DELIVERY_MODE_COMPONENT') { // 组件化创意
  614. if (materialConfig.index === 20000) {
  615. if (materialConfig.isGroup) {
  616. } else {
  617. const aContent = content.map((m: any) => {
  618. if (selectCloudData?.defaultParams?.materialType === 'video' && m?.materialType === 1) {
  619. return { id: m?.id, url: m?.oss_url, materialType: m?.materialType || 0, keyFrameImageUrl: m?.key_frame_image_url, accountId: m?.account_id }
  620. }
  621. return { id: m?.id, url: m?.oss_url, materialType: m?.materialType || 0, accountId: m?.account_id }
  622. })
  623. let newDynamicGroup = dynamicGroup?.map((item: any) => {
  624. let oldList = item?.list || []
  625. if (oldList.length < mCount) {
  626. let diffCount = mCount - oldList.length
  627. let cLength = aContent.length
  628. oldList = oldList.concat(aContent.splice(0, cLength > diffCount ? diffCount : cLength))
  629. }
  630. return { list: oldList }
  631. })
  632. if (aContent.length) {
  633. let newSc = chunkArray1(aContent, mCount)
  634. let newList: any[] = newSc.map((item: any) => {
  635. return { list: item }
  636. })
  637. newDynamicGroup = (newDynamicGroup || []).concat(newList)
  638. }
  639. form.setFieldsValue({ dynamicGroup: newDynamicGroup })
  640. }
  641. } else {
  642. let newDynamicGroup = dynamicGroup?.map((item: any, index: number) => {
  643. if (materialConfig.index === index) {
  644. let oldList = item?.list || []
  645. if (materialConfig.isGroup) {
  646. oldList = oldList.concat([content.map((m: any) => {
  647. if (selectCloudData?.defaultParams?.materialType === 'video' && m?.materialType === 1) {
  648. return { id: m?.id, url: m?.oss_url, materialType: m?.materialType || 0, keyFrameImageUrl: m?.key_frame_image_url, accountId: m?.account_id }
  649. }
  650. return { id: m?.id, url: m?.oss_url, materialType: m?.materialType || 0, accountId: m?.account_id }
  651. })])
  652. return { list: oldList }
  653. } else {
  654. oldList = oldList.concat(content.map((m: any) => {
  655. if (selectCloudData?.defaultParams?.materialType === 'video' && m?.materialType === 1) {
  656. return { id: m?.id, url: m?.oss_url, materialType: m?.materialType || 0, keyFrameImageUrl: m?.key_frame_image_url, accountId: m?.account_id }
  657. }
  658. return { id: m?.id, url: m?.oss_url, materialType: m?.materialType || 0, accountId: m?.account_id }
  659. }))
  660. return { list: oldList }
  661. }
  662. }
  663. return item
  664. })
  665. form.setFieldsValue({ dynamicGroup: newDynamicGroup })
  666. }
  667. } else { // 自定义创意
  668. if (materialConfig.index === 99999) {
  669. if (materialConfig.type === 'image_list' || materialConfig.type === 'element_story') {
  670. let urls = content?.map((item: any) => ({ id: item?.id, url: item?.oss_url, materialType: item?.materialType || 0, accountId: item?.account_id }))
  671. let max = materialConfig.max
  672. let materialsNew = dynamicGroup.map((item: any) => {
  673. let newItem = item || {}
  674. // 判断是否有字段,是否设置了值
  675. if (Object.keys(newItem).includes(materialConfig.type) && newItem[materialConfig.type]) {
  676. if (max > newItem[materialConfig.type].length && urls.length > 0) {
  677. let difference = max - newItem[materialConfig.type].length
  678. let material: any[] = []
  679. if (urls.length >= difference) {
  680. material = urls.splice(0, difference)
  681. } else {
  682. material = urls.splice(0, urls.length)
  683. }
  684. newItem[materialConfig.type] = [...newItem[materialConfig.type], ...material]
  685. return newItem
  686. } else {
  687. return newItem
  688. }
  689. } else {
  690. if (urls.length >= max) {
  691. let material = urls.splice(0, max)
  692. return { ...newItem, [materialConfig.type]: material }
  693. } else if (urls.length > 0) {
  694. let material = urls.splice(0, urls.length)
  695. return { ...newItem, [materialConfig.type]: material }
  696. } else {
  697. return newItem
  698. }
  699. }
  700. })
  701. if (urls.length > 0) {
  702. let data = Array(Math.ceil(urls.length / max)).fill(undefined).map(item => {
  703. if (urls.length >= max) {
  704. let material = urls.splice(0, max)
  705. return { [materialConfig.type]: material }
  706. } else {
  707. let material = urls.splice(0, urls.length)
  708. return { [materialConfig.type]: material }
  709. }
  710. })
  711. materialsNew = [...materialsNew, ...data]
  712. }
  713. console.log('materialsNew-->', materialsNew)
  714. form.setFieldsValue({ dynamicGroup: materialsNew })
  715. } else {
  716. let newMaterials = content?.map((item: any) => {
  717. if (["short_video1", 'video_id'].includes(materialConfig.type) && mLength === 2) {
  718. return { [materialConfig.type]: { url: item?.oss_url, keyFrameImageUrl: item.key_frame_image_url, id: item?.id, materialType: item?.materialType || 0, accountId: item?.account_id }, cover_id: { url: item?.materialType === 1 ? item?.key_frame_image_url : getVideoImgUrl(item?.oss_url), id: null, materialType: item?.materialType || 0, accountId: item?.account_id } }
  719. }
  720. return { [materialConfig.type]: { url: item?.oss_url, id: item?.id, materialType: item?.materialType || 0, accountId: item?.account_id } }
  721. })
  722. if (newMaterials.length > 0) {
  723. if (dynamicGroup?.every((item: any) => !item)) { // 没设置过
  724. form.setFieldsValue({ dynamicGroup: newMaterials })
  725. } else { // 设置过
  726. let materialsNew = dynamicGroup.map((item: any) => {
  727. let newItem = item || {}
  728. if (Object.keys(newItem).includes(materialConfig.type) && newItem[materialConfig.type]) {
  729. return item
  730. } else {
  731. if (newMaterials.length > 0) {
  732. let material = newMaterials.splice(0, 1)
  733. return { ...newItem, ...material[0] }
  734. } else {
  735. return item
  736. }
  737. }
  738. })
  739. if (newMaterials.length > 0) {
  740. materialsNew = [...materialsNew, ...newMaterials]
  741. }
  742. form.setFieldsValue({ dynamicGroup: materialsNew })
  743. }
  744. }
  745. }
  746. } else {
  747. let newDynamicGroup = dynamicGroup?.map((item: any, index: number) => {
  748. if (materialConfig.index === index) {
  749. if (materialConfig.type === 'image_list' || materialConfig.type === 'element_story') {
  750. if (item) {
  751. item[materialConfig.type] = content?.map((item: any) => ({ id: item?.id, url: item?.oss_url, materialType: item?.materialType || 0, accountId: item?.account_id }))
  752. return { ...item }
  753. } else {
  754. return { [materialConfig.type]: content?.map((item: any) => ({ id: item?.id, url: item?.oss_url, materialType: item?.materialType || 0, accountId: item?.account_id })) }
  755. }
  756. } else {
  757. if (item) {
  758. let d: any = { id: content[0]?.id, url: content[0]?.oss_url, materialType: content[0]?.materialType || 0, accountId: content[0]?.account_id }
  759. if (["short_video1", 'video_id'].includes(materialConfig.type) && content[0]?.materialType === 1) {
  760. d.keyFrameImageUrl = content[0]?.key_frame_image_url
  761. }
  762. item[materialConfig.type] = d
  763. return { ...item }
  764. } else {
  765. if (["short_video1", 'video_id'].includes(materialConfig.type) && mLength === 2) {
  766. return { [materialConfig.type]: { id: content[0]?.id, url: content[0]?.oss_url, keyFrameImageUrl: content[0]?.key_frame_image_url, materialType: content[0]?.materialType || 0, accountId: content[0]?.account_id }, cover_id: { id: null, url: content[0]?.materialType === 1 ? content[0]?.key_frame_image_url : getVideoImgUrl(content[0]?.oss_url), materialType: content[0]?.materialType || 0, accountId: content[0]?.account_id } }
  767. }
  768. return { [materialConfig.type]: { id: content[0]?.id, url: content[0]?.oss_url, materialType: content[0]?.materialType || 0, accountId: content[0]?.account_id } }
  769. }
  770. }
  771. }
  772. return item
  773. })
  774. form.setFieldsValue({ dynamicGroup: newDynamicGroup })
  775. }
  776. }
  777. }
  778. setSelectVideoVisible(false)
  779. setSelectCloudData(undefined)
  780. }}
  781. />}
  782. </Modal>
  783. }
  784. export default React.memo(AddMaterial)