addMaterial.tsx 55 KB

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