|
@@ -1,14 +1,17 @@
|
|
|
import React, { useCallback, useEffect, useMemo, useState } from 'react'
|
|
|
-import { Modal, Form, Input, Divider, Select, Radio, Switch, Spin } from 'antd'
|
|
|
+import { Modal, Form, Input, Divider, Select, Radio, Switch, Spin, List } from 'antd'
|
|
|
import { SiteSetEnum, PromotedObjectType } from '@/services/launchAdq/enum'
|
|
|
import { ModalConfig } from '.'
|
|
|
import styles from './index.less'
|
|
|
import { outAdcreativeTemplateIdFun } from '../adenum';
|
|
|
import { useAjax } from '@/Hook/useAjax'
|
|
|
-import { get_adcreative_template, get_adcreative_template_list } from '@/services/launchAdq/global'
|
|
|
+import { getText, get_adcreative_template, get_adcreative_template_list } from '@/services/launchAdq/global'
|
|
|
import { AdcreativeTemplate, AdcreativeTemplateList } from '@/services/launchAdq'
|
|
|
import { mySet } from '@/utils/arrFn'
|
|
|
import SelectCloud from '@/pages/launchSystemNew/components/selectCloud'
|
|
|
+import { useModel } from '@/.umi/plugin-model/useModel'
|
|
|
+import { DebounceSelect, fetchUserList } from '@/components/DebounceSelect'
|
|
|
+import e from '@umijs/deps/compiled/express'
|
|
|
interface Props {
|
|
|
title?: string,
|
|
|
visible: boolean,
|
|
@@ -19,13 +22,17 @@ interface Props {
|
|
|
/**创意模板*/
|
|
|
function CreativeModal(props: Props) {
|
|
|
let { visible, title, confirmLoading, PupFn, callback } = props
|
|
|
+ const { init } = useModel('useLaunchAdq.useBdMediaPup')
|
|
|
// 请求
|
|
|
const getAdcreativeTemplate = useAjax((params) => get_adcreative_template(params))
|
|
|
const getAdcreativeTemplateList = useAjax((params) => get_adcreative_template_list(params))
|
|
|
+ const getTextLsit = useAjax((params) => getText(params))
|
|
|
// 变量
|
|
|
const [adcreative_template, set_adcreative_template] = useState<AdcreativeTemplate>()
|
|
|
const [adcreative_template_list, set_adcreative_template_list] = useState<AdcreativeTemplateList[]>([])
|
|
|
- const [selectImgVisible,set_selectImgVisible] = useState(true)
|
|
|
+ const [selectImgVisible, set_selectImgVisible] = useState(false)
|
|
|
+ const [descriptionShow, setdescriptionshow] = useState(false)
|
|
|
+ const [titleShow, settitleshow] = useState(false)
|
|
|
const [form] = Form.useForm();
|
|
|
const [pupState, setPupState] = useState({
|
|
|
kp_show: false,
|
|
@@ -34,6 +41,12 @@ function CreativeModal(props: Props) {
|
|
|
bq_show: false,
|
|
|
sp_show: false
|
|
|
})
|
|
|
+ const [materialConfig, setMaterialConfig] = useState<{ adcreativeTemplateId?: number, type: string, cloudSize: { relation: string, width: number, height: number }[], list: any[], max: number }>({
|
|
|
+ type: '',//类型
|
|
|
+ cloudSize: [],//素材搜索条件
|
|
|
+ list: [],//素材
|
|
|
+ max: 1,//素材数量
|
|
|
+ })//素材配置
|
|
|
const [conversionList, setConversionList] = useState<any>(null)
|
|
|
let pageType = Form.useWatch('pageType', form)
|
|
|
let adcreativeTemplateId = Form.useWatch('adcreativeTemplateId', form)
|
|
@@ -43,16 +56,62 @@ function CreativeModal(props: Props) {
|
|
|
let adcreativeElementsType = Form.useWatch('adcreativeElementsType', form)
|
|
|
let dataShow = Form.useWatch('dataShow', form)
|
|
|
let conversionDataType = Form.useWatch('conversionDataType', form)
|
|
|
+ let titles = Form.useWatch('title', form)
|
|
|
+ let description = Form.useWatch('description', form)
|
|
|
|
|
|
// 确定事件
|
|
|
const handleOk = useCallback(() => {
|
|
|
form.validateFields().then(values => {
|
|
|
+ console.log('values=>1', values)
|
|
|
let newValues = JSON.parse(JSON.stringify(values))
|
|
|
- console.log(newValues)
|
|
|
+ for (let key in newValues) {
|
|
|
+ switch (key) {
|
|
|
+ case 'image'://图素材
|
|
|
+ newValues.adcreativeElements = {
|
|
|
+ ...newValues.adcreativeElements,
|
|
|
+ image: materialConfig.list[0].url,
|
|
|
+ }
|
|
|
+ delete newValues[key]
|
|
|
+ break;
|
|
|
+ case 'video'://视频素材
|
|
|
+ newValues.adcreativeElements = {
|
|
|
+ ...newValues.adcreativeElements,
|
|
|
+ video: materialConfig.list[0].url,
|
|
|
+ }
|
|
|
+ delete newValues[key]
|
|
|
+ break;
|
|
|
+ case 'image_list'://图素材
|
|
|
+ // newValues.adcreativeElements = {
|
|
|
+ // video: materialConfig.list[0].url,
|
|
|
+ // description: newValues.description,
|
|
|
+ // }
|
|
|
+ // delete newValues[key]
|
|
|
+ break;
|
|
|
+ case 'short_video1'://视频素材
|
|
|
+ // newValues.adcreativeElements = {
|
|
|
+ // video: materialConfig.list[0].url,
|
|
|
+ // description: newValues.description,
|
|
|
+ // }
|
|
|
+ // delete newValues[key]
|
|
|
+ break;
|
|
|
+ case 'description'://文案
|
|
|
+ newValues.adcreativeElements = { ...newValues.adcreativeElements, description: newValues.description }
|
|
|
+ break;
|
|
|
+ case 'title'://文案
|
|
|
+ newValues.adcreativeElements = { ...newValues.adcreativeElements, title: newValues.title }
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ delete newValues.description //删除外层文案
|
|
|
+ delete newValues.title //删除外层文案
|
|
|
+ delete newValues.adcreativeElementsType //删除创意形式
|
|
|
+ delete newValues.dataShow //删除数据开关
|
|
|
+ delete newValues.actionBtn //删除行动开关
|
|
|
+ console.log('newValues=>2', newValues)
|
|
|
// callback(newValues)
|
|
|
})
|
|
|
// PupFn({ visible: false })
|
|
|
- }, [form])
|
|
|
+ }, [form, materialConfig])
|
|
|
// 获取创意形式列表
|
|
|
useEffect(() => {
|
|
|
if (siteSet?.length > 0 && promotedObjectType) {
|
|
@@ -63,7 +122,7 @@ function CreativeModal(props: Props) {
|
|
|
}).then(res => {
|
|
|
let newArr: any = []
|
|
|
// 过滤掉相同的和即将下线的
|
|
|
- Object.values(res).forEach((arr: any) => {
|
|
|
+ Object.values(res)?.forEach((arr: any) => {
|
|
|
Array.isArray(arr) && arr?.forEach((item: any) => {
|
|
|
if (newArr.length > 0) {
|
|
|
if (outAdcreativeTemplateIdFun(item.adcreativeTemplateId) && newArr.every((i: { adcreativeTemplateId: any }) => i.adcreativeTemplateId !== item.adcreativeTemplateId)) {
|
|
@@ -98,7 +157,9 @@ function CreativeModal(props: Props) {
|
|
|
promotedObjectType,
|
|
|
adcreativeTemplateId
|
|
|
}).then(res => {
|
|
|
- set_adcreative_template(res[0])
|
|
|
+ if (res?.length > 0) {
|
|
|
+ set_adcreative_template(res[0])
|
|
|
+ }
|
|
|
})
|
|
|
}
|
|
|
}
|
|
@@ -180,6 +241,33 @@ function CreativeModal(props: Props) {
|
|
|
form.setFieldsValue(values)
|
|
|
}
|
|
|
}, [adcreative_template])
|
|
|
+ // 版位改变清空数据
|
|
|
+ useEffect(() => {
|
|
|
+ if (materialConfig.adcreativeTemplateId && adcreativeTemplateId !== materialConfig.adcreativeTemplateId) {
|
|
|
+ setMaterialConfig({ ...materialConfig, adcreativeTemplateId: undefined, list: [] })
|
|
|
+ }
|
|
|
+ }, [adcreativeTemplateId, materialConfig])
|
|
|
+ // 文案助手
|
|
|
+ const textList = useCallback((arg: { maxTextLength: number, keyword?: string }) => {
|
|
|
+ let { maxTextLength, keyword } = arg
|
|
|
+ getTextLsit.run({ keyword: keyword || titles || description, maxTextLength })
|
|
|
+ }, [titles, description])
|
|
|
+ // 监听点击取消文案助手弹窗
|
|
|
+ useEffect(() => {
|
|
|
+ let modal = document.querySelector('.myModal')
|
|
|
+ let onBiurdescription = (e: any) => {
|
|
|
+ let d = document.querySelector('.my_description')
|
|
|
+ if (!d?.contains(e.target)) {
|
|
|
+ setdescriptionshow(false)
|
|
|
+ settitleshow(false)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ modal?.addEventListener('click', onBiurdescription)
|
|
|
+ return () => {
|
|
|
+ modal?.removeEventListener('click', onBiurdescription)
|
|
|
+ }
|
|
|
+
|
|
|
+ }, [])
|
|
|
return <Modal
|
|
|
visible={visible}
|
|
|
title={title + '创意'}
|
|
@@ -187,6 +275,7 @@ function CreativeModal(props: Props) {
|
|
|
onOk={handleOk}
|
|
|
width={1200}
|
|
|
confirmLoading={confirmLoading}
|
|
|
+ className='myModal'
|
|
|
>
|
|
|
<Form
|
|
|
form={form}
|
|
@@ -264,34 +353,83 @@ function CreativeModal(props: Props) {
|
|
|
{/* 优先展示视频或图片 */}
|
|
|
{
|
|
|
adcreative_template?.adcreativeElements?.filter(item => item.required && item.name === 'image_list' || item.name === 'short_video1' || item.name === 'video' || item.name === 'image').map(item => {
|
|
|
- return <Form.Item label={<strong>{item.description}</strong>} name={item.name} rules={[{ required: true, message: '请选择素材!' }]}>
|
|
|
+ return <Form.Item label={<strong>{item.description}</strong>} rules={[{ required: true, message: '请选择素材!' }]} key={item.name} name={item.name}>
|
|
|
+ {/* 视频 */}
|
|
|
{
|
|
|
- ( item.name === 'short_video1'||item.name === 'video' )&& <div className={`${styles.box} ${styles.video}`}>
|
|
|
+ (item.name === 'short_video1' || item.name === 'video') && <div className={`${styles.box} ${styles.video}`} onClick={() => {
|
|
|
+ init({ mediaType: 'VIDEO', cloudSize: [[{ relation: '=', width: item.restriction.videoRestriction.minWidth, height: item.restriction.videoRestriction.minHeight }]] })
|
|
|
+ setTimeout(() => {
|
|
|
+ set_selectImgVisible(true)
|
|
|
+ setMaterialConfig({
|
|
|
+ ...materialConfig,
|
|
|
+ type: item.name,
|
|
|
+ max: 1,
|
|
|
+ adcreativeTemplateId
|
|
|
+ })
|
|
|
+ }, 100)
|
|
|
+ }}>
|
|
|
<p>
|
|
|
- <span>{`推荐尺寸(${item.restriction.videoRestriction.minWidth} x ${item.restriction.videoRestriction.minHeight})`}</span>
|
|
|
- <span>{`${item.restriction.videoRestriction.fileFormat?.map(str => str?.replace('MEDIA_TYPE_', ''))};< ${item.restriction.videoRestriction.fileSize / 1024}M;时长 ≥ ${item.restriction.videoRestriction.minDuration}s,≤ ${item.restriction.videoRestriction.maxDuration}s,必须带有声音`}</span>
|
|
|
+ {
|
|
|
+ materialConfig?.list[0] ? <video src={materialConfig?.list[0].url} /> : <>
|
|
|
+ <span>{`推荐尺寸(${item.restriction.videoRestriction.minWidth} x ${item.restriction.videoRestriction.minHeight})`}</span>
|
|
|
+ <span>{`${item.restriction.videoRestriction.fileFormat?.map(str => str?.replace('MEDIA_TYPE_', ''))};< ${item.restriction.videoRestriction.fileSize / 1024}M;时长 ≥ ${item.restriction.videoRestriction.minDuration}s,≤ ${item.restriction.videoRestriction.maxDuration}s,必须带有声音`}</span>
|
|
|
+ </>
|
|
|
+ }
|
|
|
</p>
|
|
|
</div>
|
|
|
}
|
|
|
+ {/* 单图 */}
|
|
|
{
|
|
|
- item.name === 'image' && <div className={`${styles.box} ${styles.image}`}>
|
|
|
- <p>
|
|
|
- <span>{`推荐尺寸(${item.restriction.imageRestriction.width} x ${item.restriction.imageRestriction.height})`}</span>
|
|
|
- <span>{`${item.restriction.imageRestriction.fileFormat?.map(str => str?.replace('IMAGE_TYPE_', ''))};小于 ${item.restriction.imageRestriction.fileSize}KB`}</span>
|
|
|
- </p>
|
|
|
- </div>
|
|
|
+ item.name === 'image' && <div className={`${styles.box} ${styles.image}`} onClick={() => {
|
|
|
+ init({ mediaType: 'IMG', cloudSize: [[{ relation: '=', width: item.restriction.imageRestriction.width, height: item.restriction.imageRestriction.height }]] })
|
|
|
+ setTimeout(() => {
|
|
|
+ set_selectImgVisible(true)
|
|
|
+ setMaterialConfig({
|
|
|
+ ...materialConfig,
|
|
|
+ type: item.name,
|
|
|
+ max: 1,
|
|
|
+ adcreativeTemplateId
|
|
|
+ })
|
|
|
+ }, 100)
|
|
|
+
|
|
|
+ }}>
|
|
|
+ <p>
|
|
|
+ {materialConfig?.list[0] ? <img src={materialConfig?.list[0].url} /> : <>
|
|
|
+ <span>{`推荐尺寸(${item.restriction.imageRestriction.width} x ${item.restriction.imageRestriction.height})`}</span>
|
|
|
+ <span>{`${item.restriction.imageRestriction.fileFormat?.map(str => str?.replace('IMAGE_TYPE_', ''))};小于 ${item.restriction.imageRestriction.fileSize}KB`}</span>
|
|
|
+ </>
|
|
|
+ }
|
|
|
+ </p>
|
|
|
+ </div>
|
|
|
}
|
|
|
- {
|
|
|
- item.name === 'image_list' && <div className={`${styles.box} ${item.arrayProperty.maxNumber >= 3 ?styles.image_list : styles.image}`}>
|
|
|
+ {/* 多图 */}
|
|
|
+ {
|
|
|
+ item.name === 'image_list' && <div className={`${styles.box} ${item.arrayProperty.maxNumber >= 3 ? styles.image_list : styles.image}`} onClick={() => {
|
|
|
+ init({ mediaType: 'IMG', num: item.arrayProperty.maxNumber, cloudSize: [[{ relation: '=', width: item.restriction.imageRestriction.width, height: item.restriction.imageRestriction.height }]] })
|
|
|
+ setTimeout(() => {
|
|
|
+ set_selectImgVisible(true)
|
|
|
+ setMaterialConfig({
|
|
|
+ ...materialConfig,
|
|
|
+ type: item.name,
|
|
|
+ max: item.arrayProperty.maxNumber,
|
|
|
+ adcreativeTemplateId
|
|
|
+ })
|
|
|
+ }, 100)
|
|
|
+ }}>
|
|
|
{
|
|
|
- Array(item.arrayProperty.maxNumber).fill('').map((arr,index)=>{
|
|
|
+ Array(item.arrayProperty.maxNumber).fill('').map((arr, index) => {
|
|
|
return <p key={index}>
|
|
|
- <span>{`推荐尺寸(${item.restriction.imageRestriction.width} x ${item.restriction.imageRestriction.height})`}</span>
|
|
|
- <span>{`${item.restriction.imageRestriction.fileFormat?.map(str => str?.replace('IMAGE_TYPE_', ''))};小于 ${item.restriction.imageRestriction.fileSize}KB`}</span>
|
|
|
- </p>
|
|
|
+ {
|
|
|
+ materialConfig?.list[index] ? <img src={materialConfig?.list[index].url} /> : <>
|
|
|
+ <span>{`推荐尺寸(${item.restriction.imageRestriction.width} x ${item.restriction.imageRestriction.height})`}</span>
|
|
|
+ <span>{`${item.restriction.imageRestriction.fileFormat?.map(str => str?.replace('IMAGE_TYPE_', ''))};小于 ${item.restriction.imageRestriction.fileSize}KB`}</span>
|
|
|
+ </>
|
|
|
+ }
|
|
|
+
|
|
|
+ </p>
|
|
|
})
|
|
|
}
|
|
|
- </div>
|
|
|
+ </div>
|
|
|
}
|
|
|
</Form.Item>
|
|
|
})
|
|
@@ -299,20 +437,77 @@ function CreativeModal(props: Props) {
|
|
|
{/* 标题 */}
|
|
|
{
|
|
|
adcreative_template?.adcreativeElements?.filter(item => item.name === 'title').map(item => {
|
|
|
- return <Form.Item label={<strong>{item.description}(选填)</strong>} name={item.name} rules={[{ pattern: RegExp(item.restriction.textRestriction.textPattern), message: '请输入正确的' + item.description }]}>
|
|
|
- <Input placeholder={'请输入' + item.description} style={{ width: 500 }} />
|
|
|
- </Form.Item>
|
|
|
+ return <div key={item.fieldType}>
|
|
|
+ <Form.Item label={<strong>{item.description}(选填)</strong>} className={'my_description'} >
|
|
|
+ <Form.Item name={item.name} rules={[{ pattern: RegExp(item.restriction.textRestriction.textPattern), message: '请输入正确的' + item.description }]} noStyle>
|
|
|
+ <Input
|
|
|
+ placeholder={'请输入' + item.description}
|
|
|
+ style={{ width: 500 }}
|
|
|
+ onFocus={() => {
|
|
|
+ settitleshow(true)
|
|
|
+ textList({ maxTextLength: item.restriction.textRestriction.maxLength })
|
|
|
+ }}
|
|
|
+ onChange={(e) => {
|
|
|
+ let value = e.target.value
|
|
|
+ textList({ maxTextLength: item.restriction.textRestriction.maxLength, keyword: value })
|
|
|
+ }}
|
|
|
+ />
|
|
|
+ </Form.Item>
|
|
|
+ <span>{`${titles?.length??0}/${item.restriction.textRestriction.maxLength}`}</span>
|
|
|
+ {
|
|
|
+ titleShow && <List
|
|
|
+ loading={getTextLsit?.loading}
|
|
|
+ size="small"
|
|
|
+ style={{ maxHeight: 300, overflowX: 'auto' }}
|
|
|
+ bordered
|
|
|
+ dataSource={getTextLsit?.data?.returnTexts}
|
|
|
+ renderItem={(item: any) => <List.Item onClick={() => {
|
|
|
+ form.setFieldsValue({ title: item.text })
|
|
|
+ settitleshow(false)
|
|
|
+ }}><span >{item.text}{item.tag && <span className={styles.crt}>{'CTR 高'}</span>}</span></List.Item>}
|
|
|
+ />
|
|
|
+ }
|
|
|
+ </Form.Item>
|
|
|
+ </div>
|
|
|
})
|
|
|
}
|
|
|
{//过滤了不必传和品牌名称,品牌标识图(外部传)短视频结构(组装使用)
|
|
|
- // adcreative_template?.adcreativeElements?.filter(item => item.required && item.name !== 'brand_name' && item.name !== 'brand_img' && item.name !== 'short_video_struct' && item.name !== 'image_list' && item.name !== 'short_video1' && item.name !== 'video' ).map(item => {
|
|
|
adcreative_template?.adcreativeElements?.filter(item => item.required && item.name === 'description').map(item => {
|
|
|
- return <Form.Item label={<strong>{item.description}</strong>} name={item.name} rules={[{ required: true, pattern: RegExp(item.restriction.textRestriction.textPattern), message: '请输入正确的' + item.description }]}>
|
|
|
- <Input placeholder={'请输入' + item.description} style={{ width: 500 }} />
|
|
|
- </Form.Item>
|
|
|
+ return <div key={item.fieldType}>
|
|
|
+ <Form.Item label={<strong>{item.description}</strong>} className={'my_description'}>
|
|
|
+ <Form.Item name={item.name} noStyle rules={[{ required: true, pattern: RegExp(item.restriction.textRestriction.textPattern), message: '请输入正确的' + item.description }]}>
|
|
|
+ <Input
|
|
|
+ placeholder={'请输入' + item.description}
|
|
|
+ style={{ width: 500 }}
|
|
|
+ onFocus={() => {
|
|
|
+ setdescriptionshow(true)
|
|
|
+ textList({ maxTextLength: item.restriction.textRestriction.maxLength })
|
|
|
+ }}
|
|
|
+ onChange={(e) => {
|
|
|
+ let value = e.target.value
|
|
|
+ textList({ maxTextLength: item.restriction.textRestriction.maxLength, keyword: value })
|
|
|
+ }}
|
|
|
+ allowClear
|
|
|
+ />
|
|
|
+ </Form.Item>
|
|
|
+ <span>{`${description?.length??0}/${item.restriction.textRestriction.maxLength}`}</span>
|
|
|
+ {
|
|
|
+ descriptionShow && <List
|
|
|
+ loading={getTextLsit?.loading}
|
|
|
+ size="small"
|
|
|
+ style={{ maxHeight: 300, overflowX: 'auto' }}
|
|
|
+ bordered
|
|
|
+ dataSource={getTextLsit?.data?.returnTexts}
|
|
|
+ renderItem={(item: any) => <List.Item onClick={(e: any) => {
|
|
|
+ form.setFieldsValue({ description: item.text })
|
|
|
+ setdescriptionshow(false)
|
|
|
+ }}><span >{item.text}{item.tag && <span className={styles.crt}>{'CTR 高'}</span>}</span></List.Item>}
|
|
|
+ />
|
|
|
+ }
|
|
|
+ </Form.Item>
|
|
|
+ </div>
|
|
|
})
|
|
|
}
|
|
|
-
|
|
|
{/* ============================================================落地页============================================================= */}
|
|
|
<Form.Item label={<strong>落地页</strong>} name='pageType'>
|
|
|
<Radio.Group>
|
|
@@ -423,10 +618,21 @@ function CreativeModal(props: Props) {
|
|
|
}
|
|
|
</Form>
|
|
|
{/* //sliderImgContent={sliderImgContent} */}
|
|
|
- {/* 选择素材 */}
|
|
|
- {selectImgVisible && <SelectCloud visible={selectImgVisible} onClose={() => set_selectImgVisible(false)} onChange={(content)=>{
|
|
|
- console.log(content)
|
|
|
- }} />}
|
|
|
+ {/* 选择素材 */}
|
|
|
+ {
|
|
|
+ selectImgVisible && <SelectCloud
|
|
|
+ visible={selectImgVisible}
|
|
|
+ onClose={() => set_selectImgVisible(false)}
|
|
|
+ sliderImgContent={materialConfig.list}
|
|
|
+ onChange={(content) => {
|
|
|
+ if (content.length > 0) {
|
|
|
+ form.setFieldsValue({ [materialConfig.type]: materialConfig.type })
|
|
|
+ }
|
|
|
+ setMaterialConfig({ ...materialConfig, list: content })
|
|
|
+ set_selectImgVisible(false)
|
|
|
+ console.log(content)
|
|
|
+ }} />
|
|
|
+ }
|
|
|
</Modal >
|
|
|
}
|
|
|
export default CreativeModal
|