123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431 |
- import InputName from "@/components/InputName"
- import { useAjax } from "@/Hook/useAjax"
- import { getImagesInfoApi, getVideosInfoApi } from "@/services/adqV3/global"
- import { txtLength } from "@/utils/utils"
- import { DeleteOutlined, PlusOutlined } from "@ant-design/icons"
- import { Button, Card, Form, message, Modal, Space, Spin } from "antd"
- import React, { useEffect, useState } from "react"
- import styles from '../../tencentAdPutIn/create/Material/index.less'
- import VideoNews from "@/pages/launchSystemNew/components/newsModal/videoNews"
- import { useModel } from "umi"
- import SelectCloud from "@/pages/launchSystemNew/components/selectCloud"
- import { batchCreateDownPageApi } from "@/services/adqV3"
- interface Props {
- accountId: number
- pageData: any
- visible?: boolean
- onClose?: () => void
- onChange?: () => void
- }
- /**
- * 批量复制落地页
- * @returns
- */
- const CopyPage: React.FC<Props> = ({ accountId, pageData, visible, onChange, onClose }) => {
- /********************************/
- const { init } = useModel('useLaunchAdq.useBdMediaPup')
- const [materialConfig, setMaterialConfig] = useState<{
- adcreativeTemplateId?: number,
- type: string,
- cloudSize: { relation: string, width: number, height: number }[],
- list: any[],
- index: number,
- max: number,
- sliderImgContent: any,
- isGroup?: boolean
- }>({
- type: '',//类型
- cloudSize: [],//素材搜索条件
- list: [],//素材
- index: 0, // 素材组下标
- max: 1,//素材数量
- sliderImgContent: undefined
- })//图片素材配置
- const [selectVideoVisible, setSelectVideoVisible] = useState(false)
- const [form] = Form.useForm();
- const downPageMaterialDTOS = Form.useWatch('downPageMaterialDTOS', form)
- const [mType, setMtype] = useState<{ width: number, height: number, type: "IMAGE" | 'VIDEO' | 'CAROUSEL', number: number }>()
- const getImagesInfo = useAjax((params) => getImagesInfoApi(params))
- const getVideosInfo = useAjax((params) => getVideosInfoApi(params))
- const batchCreateDownPage = useAjax((params) => batchCreateDownPageApi(params))
- /********************************/
- useEffect(() => {
- console.log(pageData)
- if (pageData?.pageElementsSpecList) {
- form.setFieldsValue({ pageName: pageData?.pageName })
- let { elementType, ...spec } = pageData?.pageElementsSpecList[0]
- switch (elementType) {
- case "IMAGE": // 图片
- case "CAROUSEL": // 轮播
- let imageIdList = spec.imageSpec.imageIdList
- getImagesInfo.run({ adAccountId: accountId, imageIds: [imageIdList[0]], pageNum: 1, pageSize: 1 }).then(res => {
- if (res?.records?.length) {
- const { imageWidth, imageHeight } = res.records[0]
- setMtype({ width: imageWidth, height: imageHeight, type: elementType, number: imageIdList.length })
- }
- })
- break
- case "VIDEO": // 视频
- let videoId = spec.videoSpec.videoId
- getVideosInfo.run({ adAccountId: accountId, videoIds: [videoId] }).then(res => {
- console.log(res)
- if (res?.length) {
- const { width, height } = res[0]
- setMtype({ width, height, type: elementType, number: 1 })
- }
- })
- break
- }
- }
- }, [pageData])
- const handleOk = (values: any) => {
- console.log(values)
- const { pageName, downPageMaterialDTOS: data } = values
- let downPageMaterialDTOS: { materialType: number, videoId?: number, imageId?: number[] }[] = []
- if (mType?.type === 'VIDEO') {
- downPageMaterialDTOS = data.map((item: { videoId: { id: any; materialType: any } }) => {
- const { id, materialType } = item.videoId
- return { videoId: id, materialType }
- })
- } else {
- downPageMaterialDTOS = data.map((item: { imageId: { id: any; materialType: any }[] }) => {
- const { materialType } = item.imageId[0]
- return { imageId: item.imageId.map(item => item.id), materialType }
- })
- }
- batchCreateDownPage.run({ pageName, downPageMaterialDTOS, accountId, templateId: pageData.pageId }).then(res => {
- if (res?.data?.length) {
- message.error(res.data.toString())
- } else {
- message.success('新增成功')
- onChange?.()
- }
- })
- }
- return <Modal
- title={<Space>
- <strong>批量替换顶部素材复制落地页</strong>
- {(mType?.type && ['CAROUSEL', 'IMAGE'].includes(mType?.type)) && <Button type="link" onClick={() => {
- init({ mediaType: 'IMG', num: 100, cloudSize: [[{ relation: '=', width: mType.width, height: mType.height }]], maxSize: 307200 })
- setMaterialConfig({
- ...materialConfig,
- type: 'imageId',
- max: mType.number || 1,
- index: 99999,
- adcreativeTemplateId: 721
- })
- setTimeout(() => {
- setSelectVideoVisible(true)
- }, 100)
- }}>批量添加图片素材</Button>}
- {(mType?.type && ['VIDEO'].includes(mType?.type)) && <Button type="link" onClick={() => {
- init({ mediaType: 'VIDEO', num: 100, cloudSize: [[{ relation: '=', width: mType.width, height: mType.height }]], maxSize: 20971520 })
- setMaterialConfig({
- ...materialConfig,
- type: 'videoId',
- max: 1,
- index: 99999,
- adcreativeTemplateId: 311
- })
- setTimeout(() => {
- setSelectVideoVisible(true)
- }, 100)
- }}>批量添加视频素材</Button>}
- </Space>}
- visible={visible}
- onCancel={onClose}
- className="modalResetCss"
- width={900}
- bodyStyle={{ padding: '0 0 40px', position: 'relative', borderRadius: '0 0 8px 8px' }}
- footer={null}
- >
- <Form
- form={form}
- name="copyPage"
- labelAlign='left'
- layout="vertical"
- colon={false}
- style={{ backgroundColor: '#f1f4fc', maxHeight: 650, overflow: 'hidden', overflowY: 'auto', padding: 10, borderRadius: '0 0 8px 8px' }}
- scrollToFirstError={{
- behavior: 'smooth',
- block: 'center'
- }}
- onFinishFailed={({ errorFields }) => {
- message.error(errorFields?.[0]?.errors?.[0])
- }}
- onFinish={handleOk}
- initialValues={{
- downPageMaterialDTOS: [undefined]
- }}
- >
- <Card className="cardResetCss" style={{ marginBottom: 10 }}>
- <Form.Item
- label={<strong>落地页名称</strong>}
- name='pageName'
- rules={[
- { required: true, message: '请输入落地页名称!' },
- {
- required: true, message: '广告名称不能包含特殊字符:< > & ‘ ” / 以及TAB、换行、回车键,请修改', validator(_, value) {
- let reg = /[&‘’“”/\n\t\f]/ig
- if (value && reg.test(value)) {
- return Promise.reject()
- }
- return Promise.resolve()
- }
- },
- {
- required: true, message: '请确保落地页名称长度不超过40个字', validator(_, value) {
- if (value && txtLength(value) > 40) {
- return Promise.reject()
- }
- return Promise.resolve()
- }
- }
- ]}
- >
- <InputName placeholder='落地页名称' style={{ width: 680 }} length={40} />
- </Form.Item>
- </Card>
- {mType ? <Form.List name="downPageMaterialDTOS">
- {(fields, { add, remove }) => (<>
- <div style={{ display: 'flex', flexWrap: 'wrap', gap: 10 }}>
- {fields.map((field, num) => (<Card
- title={<strong style={{ fontSize: 18 }}>素材组{num + 1}</strong>}
- className="cardResetCss"
- key={field.key}
- style={{ width: mType?.type === 'CAROUSEL' ? '100%' : downPageMaterialDTOS?.length > 1 ? 'calc(50% - 5px)' : '100%' }}
- extra={fields?.length > 1 && <DeleteOutlined className={styles.clear} onClick={() => remove(field.name)} style={{ color: 'red' }} />}
- >
- <Space size={30} style={{ width: '100%' }} className={styles.space}>
- {mType?.type === "VIDEO" ? <Form.Item
- {...field}
- label={<strong>视频</strong>}
- rules={[{ required: true, message: '请选择素材!' }]}
- name={[field.name, 'videoId']}
- >
- <div className={`${styles.box} ${styles.video}`} style={{ width: 300, height: 160 }} onClick={() => {
- init({ mediaType: 'VIDEO', cloudSize: [[{ relation: '=', width: mType.width, height: mType.height }]], maxSize: 20971520 })
- setMaterialConfig({
- ...materialConfig,
- type: 'videoId',
- max: 1,
- index: num,
- adcreativeTemplateId: 311
- })
- setTimeout(() => {
- setSelectVideoVisible(true)
- }, 100)
- }}>
- <div className={styles.p}>
- {downPageMaterialDTOS?.length > 0 && downPageMaterialDTOS[num] && Object.keys(downPageMaterialDTOS[num])?.includes('videoId') ? <VideoNews src={downPageMaterialDTOS[num]['videoId']['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 }} /> : <>
- <span>{`推荐尺寸(${mType?.width} x ${mType?.height})`}</span>
- <span>{`${['MEDIA_TYPE_MP4', 'MEDIA_TYPE_MOV', 'MEDIA_TYPE_AVI'].map((str: any) => str?.replace('MEDIA_TYPE_', ''))};< ${20}M;时长 ≥ ${5}s,≤ ${300}s,必须带有声音`}</span>
- </>}
- </div>
- </div>
- </Form.Item> : mType?.type === 'IMAGE' ? <Form.Item
- {...field}
- label={<strong>图片</strong>}
- rules={[{ required: true, message: '请选择素材!' }]}
- name={[field.name, 'imageId']}
- >
- <Space align="end">
- <div className={`${styles.box} ${styles.image}`} style={{ width: 300, height: 160 }} onClick={() => {
- init({ mediaType: 'IMG', cloudSize: [[{ relation: '=', width: mType.width, height: mType.height }]], maxSize: 307200 })
- setMaterialConfig({
- ...materialConfig,
- type: 'imageId',
- max: 1,
- index: num,
- adcreativeTemplateId: 721
- })
- setTimeout(() => {
- setSelectVideoVisible(true)
- }, 100)
- }}>
- <p>
- {downPageMaterialDTOS?.length > 0 && downPageMaterialDTOS[num]?.imageId?.length ? <img src={downPageMaterialDTOS[num]['imageId'][0]['url']} /> : <>
- <span>{`推荐尺寸(${mType?.width} x ${mType?.height})`}</span>
- <span>{`${['IMAGE_TYPE_JPG', 'IMAGE_TYPE_PNG'].map((str: any) => str?.replace('IMAGE_TYPE_', ''))};小于 300KB`}</span>
- </>}
- </p>
- </div>
- </Space>
- </Form.Item> : mType?.type === 'CAROUSEL' ? <Form.Item
- {...field}
- label={<strong>轮播图</strong>}
- rules={[
- { required: true, type: 'array', len: mType.number, message: '素材数量不对!' },
- { required: true, message: '请选择素材!' },
- ]}
- name={[field.name, 'imageId']}
- >
- <div className={`${styles.box} ${mType.number >= 3 ? styles.image_list : styles.imageMater}`} style={mType.number >= 3 ? { flexFlow: 'row', width: '100%', gap: 2 } : {}} onClick={() => {
- init({ mediaType: 'IMG', num: mType.number, cloudSize: [[{ relation: '=', width: mType.width, height: mType.height }]], maxSize: 307200 })
- setMaterialConfig({
- ...materialConfig,
- type: 'imageId',
- max: mType.number,
- index: num,
- adcreativeTemplateId: 721
- })
- setTimeout(() => {
- setSelectVideoVisible(true)
- }, 100)
- }}>
- {Array(mType.number).fill('').map((arr, index1) => {
- return <p key={index1} style={mType.number >= 3 ? { width: 130, height: 130 } : { justifyContent: 'center' }}>
- {downPageMaterialDTOS?.length > 0 && downPageMaterialDTOS[num] && Object.keys(downPageMaterialDTOS[num])?.includes('imageId') && downPageMaterialDTOS[num]['imageId'][index1] ? <img src={downPageMaterialDTOS[num]['imageId'][index1]['url']} /> : <>
- <span>{`推荐尺寸(${mType?.width} x ${mType?.height})`}</span>
- <span>{`${['IMAGE_TYPE_JPG', 'IMAGE_TYPE_PNG']?.map((str: any) => str?.replace('IMAGE_TYPE_', ''))};小于 ${300}KB`}</span>
- </>}
- </p>
- })}
- </div>
- </Form.Item> : null}
- </Space>
- </Card>))}
- </div>
- <Form.Item style={{ marginBottom: 0, marginTop: 10 }}>
- <Button type="dashed" style={{ color: '#1890ff' }} onClick={() => add()} block icon={<PlusOutlined />}>添加素材组</Button>
- </Form.Item>
- </>)}
- </Form.List> : <Spin spinning={getImagesInfo.loading}><div style={{ width: '100%', height: 100 }}></div></Spin>}
- <Form.Item className="submit_pull">
- <Space>
- <Button onClick={onClose}>取消</Button>
- <Button type="primary" htmlType="submit" className="modalResetCss" loading={batchCreateDownPage.loading}>
- 确定
- </Button>
- </Space>
- </Form.Item>
- </Form>
- {selectVideoVisible && <SelectCloud
- isGroup={materialConfig?.isGroup}
- visible={selectVideoVisible}
- onClose={() => setSelectVideoVisible(false)}
- sliderImgContent={materialConfig.index === 99999 ? undefined :
- materialConfig.type === 'imageId' ? downPageMaterialDTOS[materialConfig.index]?.imageId?.length ? downPageMaterialDTOS[materialConfig.index]['imageId']?.map((item: any) => item) : undefined :
- (downPageMaterialDTOS[materialConfig.index] && Object.keys(downPageMaterialDTOS[materialConfig.index])?.includes(materialConfig.type)) ? [{ url: downPageMaterialDTOS[materialConfig.index][materialConfig.type] }] : undefined
- }
- onChange={(content: any) => {
- if (content.length > 0) {
- console.log(content)
- if (materialConfig.index === 99999) {
- if (materialConfig.type === 'imageId') {
- let urls = content?.map((item: any) => ({ id: item?.id, url: item?.url, materialType: 0 }))
- let max = materialConfig.max
- let materialsNew = downPageMaterialDTOS.map((item: any) => {
- let newItem = item || {}
- // 判断是否有字段,是否设置了值
- if (Object.keys(newItem).includes(materialConfig.type) && newItem[materialConfig.type]) {
- if (max > newItem[materialConfig.type].length && urls.length > 0) {
- let difference = max - newItem[materialConfig.type].length
- let material: any[] = []
- if (urls.length >= difference) {
- material = urls.splice(0, difference)
- } else {
- material = urls.splice(0, urls.length)
- }
- newItem[materialConfig.type] = [...newItem[materialConfig.type], ...material]
- return newItem
- } else {
- return newItem
- }
- } else {
- if (urls.length >= max) {
- let material = urls.splice(0, max)
- return { ...newItem, [materialConfig.type]: material }
- } else if (urls.length > 0) {
- let material = urls.splice(0, urls.length)
- return { ...newItem, [materialConfig.type]: material }
- } else {
- return newItem
- }
- }
- })
- if (urls.length > 0) {
- let data = Array(Math.ceil(urls.length / max)).fill(undefined).map(item => {
- if (urls.length >= max) {
- let material = urls.splice(0, max)
- return { [materialConfig.type]: material }
- } else {
- let material = urls.splice(0, urls.length)
- return { [materialConfig.type]: material }
- }
- })
- materialsNew = [...materialsNew, ...data]
- }
- console.log('materialsNew-->', materialsNew)
- form.setFieldsValue({ downPageMaterialDTOS: materialsNew })
- } else {
- let newMaterials = content?.map((item: any) => {
- return { [materialConfig.type]: { url: item?.url, id: item?.id, materialType: 0 } }
- })
- if (newMaterials.length > 0) {
- if (downPageMaterialDTOS?.every((item: any) => !item)) { // 没设置过
- form.setFieldsValue({ downPageMaterialDTOS: newMaterials })
- } else { // 设置过
- let materialsNew = downPageMaterialDTOS.map((item: any) => {
- let newItem = item || {}
- if (Object.keys(newItem).includes(materialConfig.type) && newItem[materialConfig.type]) {
- return item
- } else {
- if (newMaterials.length > 0) {
- let material = newMaterials.splice(0, 1)
- return { ...newItem, ...material[0] }
- } else {
- return item
- }
- }
- })
- if (newMaterials.length > 0) {
- materialsNew = [...materialsNew, ...newMaterials]
- }
- form.setFieldsValue({ downPageMaterialDTOS: materialsNew })
- }
- }
- }
- } else {
- let newDynamicGroup = downPageMaterialDTOS?.map((item: any, index: number) => {
- if (materialConfig.index === index) {
- if (materialConfig.type === 'imageId') {
- if (item) {
- item[materialConfig.type] = content?.map((item: any) => ({ id: item?.id, url: item?.url, materialType: 0 }))
- return { ...item }
- } else {
- return { [materialConfig.type]: content?.map((item: any) => ({ id: item?.id, url: item?.url, materialType: 0 })) }
- }
- } else {
- if (item) {
- item[materialConfig.type] = { id: content[0]?.id, url: content[0]?.url, materialType: 0 }
- return { ...item }
- } else {
- return { [materialConfig.type]: { id: content[0]?.id, url: content[0]?.url, materialType: 0 } }
- }
- }
- }
- return item
- })
- form.setFieldsValue({ downPageMaterialDTOS: newDynamicGroup })
- }
- }
- setSelectVideoVisible(false)
- }}
- />}
- </Modal>
- }
- export default React.memo(CopyPage)
|