123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545 |
- import { Button, Card, Form, Modal, Radio, Space, Spin, message } from "antd"
- import React, { useContext, useEffect, useState } from "react"
- import '../../index.less'
- import { getCreativeDetailsApi, getCreativeTemplateListApi } from "@/services/adqV3/global";
- import { useAjax } from "@/Hook/useAjax";
- import { DELIVERY_MODE_ENUM, pageSpecFieldConVert, pageSpecFieldConVertUn } from "../../const";
- import New2Radio from "@/pages/launchSystemV3/components/New2Radio";
- import New1Radio from "@/pages/launchSystemV3/components/New1Radio";
- import { outAdcreativeTemplateIdFun } from "@/pages/launchSystemNew/launchManage/localAd/adenum";
- import { DispatchAddelivery } from "..";
- import { processData, randomString } from "@/utils/utils";
- import CreativeTemplateContent from "./creativeTemplateContent";
- import CreativeConversionAssistant from "./creativeConversionAssistant";
- import CreativeTemplateSetup from "./creativeTemplateSetup";
- export const DispatchDynamic = React.createContext<PULLIN.DynamicReactContent | null>(null);
- interface Props {
- value?: any,
- visible?: boolean
- creativeTemplateStyle?: string,
- onClose?: () => void
- onChange?: (value: any) => void
- }
- /**
- * 创意新建
- * @param param0
- * @returns
- */
- const NewDynamic: React.FC<Props> = ({ value, visible, onClose, onChange, creativeTemplateStyle: oldCreativeTemplateStyle }) => {
- /**********************************/
- const { addelivery, setMaterialData, setTextData } = useContext(DispatchAddelivery)!;
- const { adgroups } = addelivery
- const [form] = Form.useForm();
- const creativeTemplateStyle = Form.useWatch('creativeTemplateStyle', form);
- const deliveryMode = Form.useWatch('deliveryMode', form);
- const [marketingGoalTypeList, setMarketingGoalTypeList] = useState<PULLIN.DataType[]>([])
- const [adcreativeTemplateList, setAdcreativeTemplateList] = useState<PULLIN.AdcreativeTemplateList[]>([])
- const [creativeComponents, setCreativeComponents] = useState<any>({})
- const [isUpdate, setIsUpdate] = useState<boolean>(false)
- const { marketingGoal, marketingAssetOuterSpec, marketingCarrierType, siteSet, wechatPosition, automaticSiteEnabled } = adgroups
- const [newMaterialData, setNewMaterialData] = useState<any>({}) // 素材数据
- const [newTextData, setNewTextData] = useState<any>({})
- const getCreativeTemplateList = useAjax((params) => getCreativeTemplateListApi(params))
- const getCreativeDetails = useAjax((params) => getCreativeDetailsApi(params))
- /**********************************/
- useEffect(() => {
- if (deliveryMode === 'DELIVERY_MODE_CUSTOMIZE') { // 自定义创意
- getCreativeTemplateList.run({
- marketingGoal,
- marketingTargetType: marketingAssetOuterSpec.marketingTargetType,
- marketingCarrierType,
- siteSet,
- wechatSceneSpecPosition: wechatPosition || []
- }).then((res: any) => {
- let newArr: any = []
- let newData: any[] = []
- // 过滤掉相同的和即将下线的
- if (!res) {
- return
- }
- if (automaticSiteEnabled) {
- delete res?.SITE_SET_WECHAT
- }
- let creativeTemplateStyle = ''
- Object.values(res)?.forEach(arr => {
- newData.push(arr)
- if (Array.isArray(arr)) {
- arr?.forEach((item: any) => {
- let adcreativeTemplateListStructAdpermit = item?.adcreativeTemplateListStructAdpermit
- if (adcreativeTemplateListStructAdpermit) {
- creativeTemplateStyle += adcreativeTemplateListStructAdpermit?.creativeTemplateStyle
- let creativeTemplateId = adcreativeTemplateListStructAdpermit.creativeTemplateId
- if (newArr.length > 0) {//假如已存在ID,需要过滤相同
- if (outAdcreativeTemplateIdFun(creativeTemplateId) && newArr.every((i: { creativeTemplateId: any }) => i.creativeTemplateId !== creativeTemplateId)) {//不重复的添加
- newArr.push(adcreativeTemplateListStructAdpermit)
- }
- } else {//不存在ID直接过滤掉即将下线的
- if (outAdcreativeTemplateIdFun(creativeTemplateId)) {
- newArr.push(adcreativeTemplateListStructAdpermit)
- }
- }
- }
- })
- }
- })
- /*****暂时排除激励和banner有问题******/
- if (!siteSet || siteSet.some((i: string) => i === 'SITE_SET_MOMENTS')) {
- newArr = newArr.filter((item: { creativeTemplateId: number }) => ![2107, 2109].includes(item.creativeTemplateId))
- }
- /*****暂时排除出框形态 视频合约广告******/
- if (!siteSet || siteSet.some((i: string) => i === 'SITE_SET_WECHAT')) {
- newArr = newArr.filter((item: { creativeTemplateId: number }) => item.creativeTemplateId !== 1945)
- }
- newArr = newArr.filter((item: { creativeTemplateId: number }) => ![713, 727, 951, 965].includes(item.creativeTemplateId))
- let newArr1: any[] = []
- let newArr2: any[] = []
- newArr?.forEach((arr: { creativeTemplateId: any, creativeTemplateAppellation: string, creativeSampleImage: string, isGeneral?: boolean }) => {
- let arr2 = { label: arr.creativeTemplateAppellation, value: arr.creativeTemplateId, img: arr.creativeSampleImage, ...arr }
- if (newData.every((item: any[]) => item.find(i => i?.adcreativeTemplateListStructAdpermit?.creativeTemplateId === arr.creativeTemplateId))) {
- newArr1.push({ ...arr2, isGeneral: true })
- } else {
- newArr2.push(arr2)
- }
- })
- setAdcreativeTemplateList([...newArr1, ...newArr2])
- let goalTypeData: PULLIN.DataType[] = []
- if (creativeTemplateStyle.includes('视频')) {
- goalTypeData.push({ label: '视频', value: 'video' })
- form.setFieldsValue({ creativeTemplateStyle: 'video' })
- } else if (creativeTemplateStyle.includes('图片')) {
- form.setFieldsValue({ creativeTemplateStyle: 'image' })
- }
- if (creativeTemplateStyle.includes('图片')) {
- goalTypeData.push({ label: '图片', value: 'image' })
- }
- setMarketingGoalTypeList(goalTypeData)
- })
- } else if (deliveryMode === 'DELIVERY_MODE_COMPONENT') { // 组件化创意
- getTemplate()
- }
- }, [deliveryMode, marketingGoal, marketingAssetOuterSpec, marketingCarrierType, siteSet, wechatPosition, value, automaticSiteEnabled])
- useEffect(() => {
- if (!(value && Object.keys(value).length > 0) && adcreativeTemplateList?.length > 0 && marketingGoalTypeList?.length > 0) {
- typeChange(marketingGoalTypeList.some(item => item.value === 'video') ? '视频' : '图片')
- }
- }, [value, adcreativeTemplateList, marketingGoalTypeList])
- const typeChange = (creativeTemplateStyle: string, isAntTemplateId?: boolean) => {
- if (creativeTemplateStyle && adcreativeTemplateList?.length > 0) {
- let adcreativeTemplateIdArr = adcreativeTemplateList?.filter(item => item.creativeTemplateStyle === creativeTemplateStyle)
- if (adcreativeTemplateIdArr?.length > 0) {
- let creativeTemplateId = adcreativeTemplateIdArr[0].creativeTemplateId
- getTemplate(creativeTemplateId, isAntTemplateId)
- form.setFieldsValue({ creativeTemplateId })
- }
- }
- }
- // 获取创意形式详情
- const getTemplate = (id?: any, isAntTemplateId?: boolean) => {
- // CAMPAIGN_TYPE_NORMAL
- if (marketingAssetOuterSpec?.marketingTargetType && deliveryMode) {
- let params: any = {
- marketingGoal,
- marketingTargetType: marketingAssetOuterSpec.marketingTargetType,
- marketingCarrierType,
- deliveryMode,
- creativeTemplateId: id,
- wechatSceneSpecPosition: wechatPosition,
- dynamicCreativeType: deliveryMode === 'DELIVERY_MODE_COMPONENT' ? 'DYNAMIC_CREATIVE_TYPE_PROGRAM' : 'DYNAMIC_CREATIVE_TYPE_COMMON'
- }
- if (automaticSiteEnabled) {
- params.automaticSiteEnabled = automaticSiteEnabled
- } else {
- params.siteSet = siteSet
- }
- getCreativeDetails.run(params).then(res => {
- if (res?.adcreativeTemplateStructAdpermits?.length > 0) {
- let adcreativeTemplateStructAdpermits = res?.adcreativeTemplateStructAdpermits[0]
- templateChange(adcreativeTemplateStructAdpermits, isAntTemplateId)
- } else {
- message.error({
- content: '当前所选营销目的,广告版位下不支持该创意形式。或者无此创意形式权限,请联系相关人员开通白名单',
- duration: 10
- })
- setCreativeComponents({})
- }
- })
- }
- }
- //每次选中创意设置该展示的界面
- const templateChange = (adcreativeTemplateStructAdpermits: any, isAntTemplateId?: boolean) => {
- let creativeComponents = adcreativeTemplateStructAdpermits?.creativeComponents || []
- let creativeTemplateId = adcreativeTemplateStructAdpermits?.creativeTemplateId
- let creativeTemplateAppellation = adcreativeTemplateStructAdpermits?.creativeTemplateAppellation
- let result = processData(creativeComponents);
- console.log(result);
- // console.log(JSON.stringify(result));
- setCreativeComponents(result)
- let newMaterialData = {};
- let newTextData = {};
- Object.keys(result).forEach(key => {
- let data = result[key]
- if ((key === 'image_list' || key === 'short_video' || key === 'video' || key === 'image' || key === 'element_story') && data.required) {
- newMaterialData[key] = data
- } else if (key === 'title' || (data.required && key === 'description')) {
- newTextData[key] = data
- }
- })
- setNewMaterialData(newMaterialData)
- setNewTextData(newTextData)
- if (!(value && Object.keys(value).length > 0) || isAntTemplateId) {
- let values: any = {
- dynamicCreativeName: creativeTemplateAppellation ? '自定义创意' + '_' + creativeTemplateAppellation + '_' + localStorage.getItem('userId') + '_' + randomString(true, 3, 5) : '动态创意' + '_' + localStorage.getItem('userId') + '_' + randomString(true, 3, 5),
- pageSpec: [{
- pageType: 'PAGE_TYPE_WECHAT_CANVAS',
- overrideCanvasHeadOption: 'OPTION_CREATIVE_OVERRIDE_CANVAS'
- }],
- brand: undefined
- }
- Object.keys(result).forEach(key => {
- switch (key) {
- case 'brand':
- let brand = result[key]
- let page_type = brand.children.page_type
- let typeList = ["PAGE_TYPE_WECHAT_OFFICIAL_ACCOUNT_DETAIL", "PAGE_TYPE_H5_PROFILE", "PAGE_TYPE_NOT_USED"]
- let enumeration = (page_type.enumProperty.enumeration as { value: string, description: string }[]).filter((item: { value: string; }) => typeList.includes(item.value))
- values.jumpInfo = {
- pageType: enumeration[0]?.value
- }
- break
- case 'text_link':// 朋友圈文字链
- let textLink = result[key]
- let linkNameType = textLink?.children?.link_name_type
- let linkNameEnumeration = (linkNameType?.enumProperty?.enumeration as { value: string, description: string }[]).map(item => ({ label: item.description, value: item.value }))
- values.textLink = {
- value: {
- linkNameType: linkNameEnumeration?.[0]?.value,
- jumpInfo: {
- pageType: 'PAGE_TYPE_WECHAT_CANVAS'
- }
- }
- }
- values.textLinkShow = true
- break
- case 'action_button':
- let actionButton = result[key]
- let buttonText = actionButton.children.button_text
- let butttonTextEnumeration = (buttonText.enumProperty.enumeration as { value: string }[]).map(item => ({ label: item.value, value: item.value }))
- values.actionButton = {
- value: {
- buttonText: butttonTextEnumeration?.[0]?.value,
- jumpInfo: {
- pageType: 'PAGE_TYPE_WECHAT_CANVAS'
- }
- }
- }
- values.actionButtonShow = true
- break
- }
- })
- if ([1707, 1708].includes(creativeTemplateId)) {
- delete values?.actionButtonShow
- values.cardType = ['not']
- }
- form.setFieldsValue(values)
- setTimeout(() => { setIsUpdate(true) }, 50)
- }
- }
- const handleOk = (values: any) => {
- console.log(values)
- const {
- creativeTemplateStyle,
- brand,
- jumpInfo,
- pageSpec,
- textLinkShow,
- textLink,
- actionButtonShow,
- cardType,
- actionButton,
- showDataShow,
- showData,
- ...surplusValues
- } = values
- let dynamicValues: any = {
- ...surplusValues,
- }
- let creativeComponents: any = {}
- let actionButtonJumpInfo = {
- pageType: undefined
- }
- if (pageSpec?.length > 0) {
- let { pageType } = pageSpec?.[0]
- actionButtonJumpInfo.pageType = pageType
- creativeComponents.mainJumpInfo = pageSpec.map((item: { pageType: string, overrideCanvasHeadOption: string, }) => {
- return {
- value: {
- pageType: item.pageType,
- pageSpec: {
- [pageSpecFieldConVert[item.pageType]]: {
- pageId: null,
- overrideCanvasHeadOption: item.overrideCanvasHeadOption
- }
- }
- }
- }
- })
- }
- // 品牌形象
- if (jumpInfo) {
- let pageType = jumpInfo.pageType
- console.log('pageType-->', pageType)
- let value = {
- jumpInfo
- }
- if (['PAGE_TYPE_H5_PROFILE'].includes(pageType)) {
- value['profileId'] = brand
- } else if (["PAGE_TYPE_NOT_USED"].includes(pageType)) {
- let [brandName, brandImageId] = brand.split('_')
- value['brandName'] = brandName
- value['brandImageId'] = brandImageId
- } else {
- value['brandName'] = null
- value['brandImageId'] = null
- }
- let pageSpecData: any = {}
- if (pageType === 'PAGE_TYPE_H5_PROFILE') {
- pageSpecData[pageSpecFieldConVert[pageType]] = {
- pageId: null
- }
- } else if (pageType === 'PAGE_TYPE_H5') {
- pageSpecData[pageSpecFieldConVert[pageType]] = {
- pageUrl: null,
- mpaH5WildcardUrl: null
- }
- } else if (pageType === 'PAGE_TYPE_WECHAT_OFFICIAL_ACCOUNT_DETAIL') {
- pageSpecData[pageSpecFieldConVert[pageType]] = {
- appId: null
- }
- }
- value.jumpInfo = {
- ...value.jumpInfo,
- pageSpec: pageSpecData
- }
- let length = pageSpec.length
- creativeComponents.brand = Array(length).fill('').map(() => ({ value }))
- }
- // 朋友圈文字链
- if (textLinkShow) {
- creativeComponents.textLink = [textLink]
- }
- // 行动按钮
- if (actionButton && Object.keys(actionButton).length > 0) {
- let newActionButton = [actionButton]
- if (!actionButton.value?.jumpInfo) {
- newActionButton = [{
- ...actionButton,
- value: {
- ...actionButton.value,
- jumpInfo: actionButtonJumpInfo
- }
- }]
- }
- creativeComponents.actionButton = newActionButton
- }
- // 数据外显
- if (showDataShow) {
- creativeComponents.showData = [showData]
- }
- dynamicValues.creativeComponents = creativeComponents
- console.log(dynamicValues)
- setMaterialData(newMaterialData)
- setTextData(newTextData)
- onChange?.(dynamicValues)
- }
- useEffect(() => {
- if (value && Object.keys(value).length > 0 && oldCreativeTemplateStyle && adcreativeTemplateList?.length > 0) {
- getTemplate(value.creativeTemplateId)
- const {
- creativeComponents: {
- brand,
- textLink,
- actionButton,
- showData,
- mainJumpInfo,
- },
- ...surplusValues
- } = JSON.parse(JSON.stringify(value))
- let dynamicValues: any = {
- ...surplusValues
- }
- // 卡片广告
- let isCardDynamic = dynamicValues?.creativeTemplateId && [1707, 1708].includes(dynamicValues.creativeTemplateId)
- let cardType: string[] = []
- // 529 闪屏视频 没有品牌 要单独处理
- if (brand && brand?.length > 0) {
- let { jumpInfo, brandName, brandImageId, profileId } = brand[0].value
- if (jumpInfo) {
- let { pageType } = jumpInfo
- dynamicValues.jumpInfo = { pageType }
- }
- if (brandName && brandImageId) {
- dynamicValues.brand = brandName + '_' + brandImageId
- } else if (profileId) {
- dynamicValues.brand = profileId
- }
- }
- if (mainJumpInfo && mainJumpInfo?.length > 0) {
- dynamicValues.pageSpec = mainJumpInfo.map((item: any) => {
- let { pageSpec } = item.value
- let key = Object.keys(pageSpec)[0]
- let pageSpecValue = pageSpec[key]
- return { ...pageSpecValue, pageType: pageSpecFieldConVertUn[key] }
- })
- }
- // 文字链
- if (textLink && textLink?.length > 0) {
- dynamicValues = {
- ...dynamicValues,
- textLinkShow: true,
- textLink: textLink[0]
- }
- }
- // 行动按钮
- if (actionButton && actionButton?.length > 0) {
- dynamicValues = {
- ...dynamicValues,
- actionButtonShow: true,
- actionButton: actionButton[0]
- }
- if (isCardDynamic) {
- cardType.push('action_button')
- delete dynamicValues.actionButtonShow
- }
- }
- // 数据外显
- if (showData && showData?.length > 0) {
- dynamicValues = {
- ...dynamicValues,
- showDataShow: true,
- showData: showData[0]
- }
- }
- if (cardType.length === 0 && isCardDynamic) {
- cardType = ['not']
- }
- dynamicValues.cardType = cardType
- dynamicValues.creativeTemplateStyle = oldCreativeTemplateStyle === '视频' ? 'video' : 'image'
- form.setFieldsValue({ ...dynamicValues })
- }
- }, [value, oldCreativeTemplateStyle, adcreativeTemplateList])
- return <Modal
- title={<strong style={{ fontSize: 20 }}>创意基本信息</strong>}
- visible={visible}
- onCancel={onClose}
- footer={null}
- width={900}
- className={`modalResetCss`}
- bodyStyle={{ padding: '0 0 40px', position: 'relative', borderRadius: '0 0 8px 8px' }}
- maskClosable={false}
- >
- <Form
- form={form}
- name="newDynamic"
- labelAlign='left'
- layout="vertical"
- colon={false}
- style={{ backgroundColor: '#f1f4fc', maxHeight: 650, overflow: 'hidden', overflowY: 'auto', padding: '0 10px 10px', borderRadius: '0 0 8px 8px' }}
- scrollToFirstError={{
- behavior: 'smooth',
- block: 'center'
- }}
- onFinishFailed={({ errorFields }) => {
- message.error(errorFields?.[0]?.errors?.[0])
- }}
- onFinish={handleOk}
- initialValues={{
- deliveryMode: 'DELIVERY_MODE_CUSTOMIZE',
- configuredStatus: 'AD_STATUS_SUSPEND'
- }}
- >
- <Spin spinning={getCreativeTemplateList.loading || getCreativeDetails.loading}>
- <DispatchDynamic.Provider value={{ form, adgroups, value, creativeComponents, setCreativeComponents, isUpdate, setIsUpdate }}>
- <Space direction="vertical" style={{ width: '100%' }}>
- {/* 创意形式 */}
- <Card
- title={<strong style={{ fontSize: 18 }}>创意形式</strong>}
- className="cardResetCss"
- >
- <Form.Item name="deliveryMode" label={<strong>投放模式</strong>} rules={[{ required: true, message: '请选择投放模式!' }]}>
- <Radio.Group onChange={() => setTimeout(() => { setIsUpdate(true) }, 50)}>
- {Object.keys(DELIVERY_MODE_ENUM).map(key => <Radio value={key} key={key}>{DELIVERY_MODE_ENUM[key]}</Radio>)}
- </Radio.Group>
- </Form.Item>
- {deliveryMode === 'DELIVERY_MODE_CUSTOMIZE' && <>
- <Form.Item name="creativeTemplateStyle" label={<strong>创意形式类型</strong>} rules={[{ required: true, message: '请选择营销目的!' }]}>
- <New1Radio data={marketingGoalTypeList} onChange={(e) => { typeChange(e === 'video' ? '视频' : '图片', true); }} />
- </Form.Item>
- <Form.Item name="creativeTemplateId" label={<strong>创意形式</strong>} rules={[{ required: true, message: '请选择营销目的!' }]}>
- <New2Radio
- data={adcreativeTemplateList.filter(item => creativeTemplateStyle === 'video' ? item.creativeTemplateStyle === '视频' : item.creativeTemplateStyle === '图片')}
- onChange={(id) => { getTemplate(id, true); }}
- />
- </Form.Item>
- </>}
- </Card>
- {Object.keys(creativeComponents).length > 0 && <>
- {/* 创意内容 */}
- <CreativeTemplateContent automaticSiteEnabled={automaticSiteEnabled}/>
- {/* 营销组件 */}
- <CreativeConversionAssistant automaticSiteEnabled={automaticSiteEnabled} />
- {/* 创意设置 */}
- <CreativeTemplateSetup />
- </>}
- </Space>
- </DispatchDynamic.Provider>
- </Spin>
- <Form.Item className="submit_pull">
- <Space>
- <Button onClick={onClose}>取消</Button>
- <Button type="primary" htmlType="submit" className="modalResetCss">
- 确定
- </Button>
- </Space>
- </Form.Item>
- </Form>
- </Modal>
- }
- export default React.memo(NewDynamic)
|