addMaterial.tsx 60 KB

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