wjx 10 månader sedan
förälder
incheckning
a7247f3e4b

+ 23 - 8
src/pages/launchSystemV3/tencentAdPutIn/create/Material/addMaterial.tsx

@@ -1,4 +1,4 @@
-import { MinusCircleOutlined, PlusOutlined } from "@ant-design/icons"
+import { DeleteOutlined, PlusOutlined } from "@ant-design/icons"
 import { Button, Card, Dropdown, Form, Menu, Modal, Popconfirm, Space, message } from "antd"
 import React, { useEffect, useState } from "react"
 import styles from './index.less'
@@ -27,6 +27,7 @@ const AddMaterial: React.FC<Props> = ({ creativeTemplateId, materialData, delive
 
     const [form] = Form.useForm();
     const dynamicGroup = Form.useWatch('dynamicGroup', form)
+    const mediaType = Form.useWatch('mediaType', form)
 
     const [materialConfig, setMaterialConfig] = useState<{
         adcreativeTemplateId?: number,
@@ -104,7 +105,14 @@ const AddMaterial: React.FC<Props> = ({ creativeTemplateId, materialData, delive
         const { mediaType, dynamicGroup } = values
         if (mediaType === 1 && dynamicGroup.length < adLength) {
             message.error({
-                content: `创意组分配规则选择创意组平均分配到广告时,创意组总数必须大于等于广告总数。当前广告总数:${adLength},创意组总数:${dynamicGroup.length}`,
+                content: `创意组分配规则选择“平均分配到广告”时,创意组总数必须大于等于广告总数。当前广告总数:${adLength},创意组总数:${dynamicGroup.length}`,
+                duration: 8
+            })
+            return
+        }
+        if (mediaType === 2 && dynamicGroup.length > adLength) {
+            message.error({
+                content: `创意组分配规则选择“顺序分配到广告”时,创意组总数必须小于等于广告总数。当前广告总数:${adLength},创意组总数:${dynamicGroup.length}`,
                 duration: 8
             })
             return
@@ -186,8 +194,15 @@ const AddMaterial: React.FC<Props> = ({ creativeTemplateId, materialData, delive
             }}
         >
             <Card className="cardResetCss" style={{ marginBottom: 10 }}>
-                <Form.Item name="mediaType" label={<strong>创意组分配规则</strong>} style={{ marginBottom: 0 }} rules={[{ required: true, message: '请选择营销目的!' }]}>
-                    <New1Radio data={[{ label: '全账号复用', value: 0 }, { label: '创意组平均分配到广告', value: 1 }]} />
+                <Form.Item name="mediaType" label={<strong>创意组分配规则</strong>} style={{ marginBottom: 0 }} rules={[{ required: true, message: '请选择创意组分配规则!' }]}>
+                    <New1Radio 
+                        data={[{ label: '全账号复用', value: 0 }, { label: '平均分配到广告', value: 1 }, { label: '顺序分配到广告', value: 2 }]}
+                        onChange={(e) => {
+                            if (e === 2 && dynamicGroup?.length > adLength) {
+                                form.setFieldsValue({ dynamicGroup: dynamicGroup.slice(0, adLength) })
+                            }
+                        }}
+                    />
                 </Form.Item>
             </Card>
             <Form.List name="dynamicGroup">
@@ -248,6 +263,7 @@ const AddMaterial: React.FC<Props> = ({ creativeTemplateId, materialData, delive
                             className="cardResetCss"
                             key={field.key}
                             style={{ width: ([641, 642, 643, 720, 721, 722, 1529, 618].includes(creativeTemplateId) || dynamicGroup?.length === 1) ? '100%' : 'calc(50% - 5px)' }}
+                            extra={fields?.length > 1 && <DeleteOutlined className={styles.clear} onClick={() => remove(field.name)} style={{ color: 'red' }} />}
                         >
                             <Space size={30} style={{ width: '100%' }} className={styles.space}>
                                 {deliveryMode === 'DELIVERY_MODE_CUSTOMIZE' ? Object.keys(materialData)?.map(key => {
@@ -372,14 +388,13 @@ const AddMaterial: React.FC<Props> = ({ creativeTemplateId, materialData, delive
                                 }) : <div>
                                     11111111111111
                                 </div>}
-                                {fields?.length > 1 && <MinusCircleOutlined className={styles.clear} onClick={() => remove(field.name)} style={{ marginBottom: 24, color: 'red' }} />}
                             </Space>
                         </Card>))}
                     </div>
-
-                    <Form.Item style={{ marginBottom: 0, marginTop: 10 }}>
+                    
+                    {!(mediaType === 2 && dynamicGroup?.length >= adLength) && <Form.Item style={{ marginBottom: 0, marginTop: 10 }}>
                         <Button type="dashed" style={{ color: '#1890ff' }} onClick={() => add()} block icon={<PlusOutlined />}>添加创意组</Button>
-                    </Form.Item>
+                    </Form.Item>}
                 </>)}
             </Form.List>
             <Form.Item className="submit_pull">

+ 1 - 1
src/pages/launchSystemV3/tencentAdPutIn/create/Material/index.tsx

@@ -54,7 +54,7 @@ const Material: React.FC<{ adData?: any[] }> = ({ adData }) => {
             <div className={style.detail_body}>
                 {(dynamicMaterialDTos && Object.keys(dynamicMaterialDTos).length > 0) ?
                     <>
-                        <Title level={5} style={{ fontSize: 12 }}>{mediaType === 0 ? '全账号复用' : mediaType === 1 ? '创意组平均分配到广告' : null}</Title>
+                        <Title level={5} style={{ fontSize: 12 }}>{mediaType === 0 ? '全账号复用' : mediaType === 1 ? '平均分配到广告' : mediaType === 2 ? '顺序分配到广告' : null}</Title>
                         <div className={style.detail_body_m}>
                             {dynamicMaterialDTos.dynamicGroup.map((item: any, index: number) => {
                                 return <div key={index} style={{ width: deliveryMode === 'DELIVERY_MODE_CUSTOMIZE' ? [641, 642, 643].includes(creativeTemplateId) ? '100%' : [720, 721, 722, 1529, 618].includes(creativeTemplateId) ? '50%' : '25%' : '100%' }}>

+ 31 - 35
src/pages/launchSystemV3/tencentAdPutIn/create/MaterialText/newText.tsx

@@ -4,7 +4,7 @@ import { txtLength } from "@/utils/utils"
 import { Button, Card, Form, Modal, Popconfirm, Space, message } from "antd"
 import React, { useEffect, useState } from "react"
 import { TextTypeList } from "../../const"
-import { MinusCircleOutlined, PlusOutlined } from "@ant-design/icons"
+import { DeleteOutlined, PlusOutlined } from "@ant-design/icons"
 
 
 interface Props {
@@ -135,44 +135,40 @@ const NewText: React.FC<Props> = ({ visible, onClose, onChange, value, textData,
                         <Card
                             title={type === 1 ? <strong style={{ fontSize: 14 }}>创意组{num + 1}</strong> : type === 0 ? null : <strong style={{ fontSize: 14 }}>文案组{num + 1}</strong>}
                             className="cardResetCss"
-                            style={{ marginTop: 10 }}
+                            style={{ marginTop: 10, width: '100%' }}
                             key={key}
+                            extra={([3, 2].includes(type) && textDto?.length > 1) && <Popconfirm
+                                title="你确定删除当前文案组?"
+                                onConfirm={() => remove(name)}
+                            >
+                                <DeleteOutlined style={{ color: 'red' }} />
+                            </Popconfirm>}
                         >
-                            <div style={{ display: 'flex', width: '100%', alignItems: 'center', columnGap: 10 }}>
-                                <div style={{ display: 'inline-flex', flexWrap: 'wrap', gap: 10 }}>
-                                    {textList.map(item => {
-                                        return <Form.Item
-                                            {...restField}
-                                            label={<strong>{item.label}</strong>}
-                                            name={[name, item.value]}
-                                            key={key}
-                                            style={{ marginBottom: 0 }}
-                                            rules={[{
-                                                required: item.required, message: '请输入正确的' + item.label, validator: (rule, value) => {
-                                                    if (!value) {
-                                                        return Promise.reject()
-                                                    } else if (!value.match(RegExp(item.restriction.textRestriction.textPattern))) {
-                                                        return Promise.reject()
-                                                    } else if (txtLength(value) > item.restriction.textRestriction.maxLength) {
-                                                        return Promise.reject()
-                                                    }
-                                                    return Promise.resolve()
+                            <div style={{ display: 'inline-flex', flexWrap: 'wrap', gap: 10, width: '100%' }}>
+                                {textList.map(item => {
+                                    return <Form.Item
+                                        {...restField}
+                                        label={<strong>{item.label}</strong>}
+                                        name={[name, item.value]}
+                                        key={key}
+                                        style={{ marginBottom: 0, width: '100%' }}
+                                        rules={[{
+                                            required: item.required, message: '请输入正确的' + item.label, validator: (rule, value) => {
+                                                if (!value) {
+                                                    return Promise.reject()
+                                                } else if (!value.match(RegExp(item.restriction.textRestriction.textPattern))) {
+                                                    return Promise.reject()
+                                                } else if (txtLength(value) > item.restriction.textRestriction.maxLength) {
+                                                    return Promise.reject()
                                                 }
-                                            }]}
-                                        >
-                                            <TextAideInput placeholder={'请输入' + item.label} style={{ width: 450 }} maxTextLength={item.restriction.textRestriction.maxLength} />
-                                        </Form.Item>
-                                    })}
-                                </div>
-
-                                {([3, 2].includes(type) && textDto?.length > 1) && <Popconfirm
-                                    title="你确定删除当前文案组?"
-                                    onConfirm={() => remove(name)}
-                                >
-                                    <MinusCircleOutlined style={{ marginLeft: 20, color: 'red' }} />
-                                </Popconfirm>}
+                                                return Promise.resolve()
+                                            }
+                                        }]}
+                                    >
+                                        <TextAideInput placeholder={'请输入' + item.label} style={{ width: 450 }} maxTextLength={item.restriction.textRestriction.maxLength} />
+                                    </Form.Item>
+                                })}
                             </div>
-
                         </Card>
                     ))}
                     {[3, 2].includes(type) && !(type === 2 && textDto.length >= dynamicMaterialDTos.dynamicGroup.length) && <Form.Item style={{ marginTop: 10, marginBottom: 0 }}>

+ 38 - 5
src/pages/launchSystemV3/tencentAdPutIn/create/addDynamic.tsx

@@ -128,15 +128,23 @@ const AddDynamic: React.FC<PULLIN.NewAddDynamic> = ({ visible, onChange, onClose
 
         // 创意组平均分配到广告逻辑
         let averageAdDynamicList: any[] = []
-        if (mediaType === 1 && newDynamicGroup.length) {
+        if ((mediaType === 1 || mediaType === 2) && newDynamicGroup.length) {
             let adLength = adData.length
-            if (adLength > dynamicGroupLength) {
-                message.error(`创意组分配规则选择创意组平均分配到广告时,创意组总数必须大于等于广告总数。当前创意组数量:${dynamicGroupLength},广告数量:${adLength}`)
-                return
+            if (mediaType === 1) {
+                if (adLength > dynamicGroupLength) {
+                    message.error(`创意组分配规则选择“平均分配到广告”时,创意组总数必须大于等于广告总数。当前创意组数量:${dynamicGroupLength},广告数量:${adLength}`)
+                    return
+                }
+                averageAdDynamicList = distributeArray(newDynamicGroup, adLength)
+            } else if (mediaType === 2) {
+                if (adLength < dynamicGroupLength) {
+                    message.error(`创意组分配规则选择“顺序分配到广告”时,创意组总数必须小于等于广告总数。当前创意组数量:${dynamicGroupLength},广告数量:${adLength}`)
+                    return
+                }
             }
-            averageAdDynamicList = distributeArray(newDynamicGroup, adLength)
         }
 
+        let accountIndex1 = 0
         adData.forEach((ad, index) => {
             let item = accountCreateLogs.find(a => a.accountId === ad.accountId) as PULLIN.AccountCreateLogsProps
             let averageAdDynamic = averageAdDynamicList?.[index]
@@ -190,6 +198,31 @@ const AddDynamic: React.FC<PULLIN.NewAddDynamic> = ({ visible, onChange, onClose
                             })
                         }
                     })
+                } else if (mediaType === 2) {
+                    data.forEach((item) => {
+                        const { averageAdDynamic, ...ad } = item
+                        if (textType === 3) {
+                            cartesianProduct(textDto, [newDynamicGroup[accountIndex1 % newDynamicGroup.length]]).forEach((taad: any) => {
+                                let [textValue, aad, index] = taad
+                                newData.push({
+                                    ...ad,
+                                    id: ad.id + '_' + index,
+                                    dynamicGroup: aad,
+                                    textDto: textValue,
+                                    rowSpan: textDto.length
+                                })
+                            })
+                        } else {
+                            let { textDto, ...dynamicGroup } = newDynamicGroup[accountIndex1 % newDynamicGroup.length]
+                            newData.push({
+                                ...ad,
+                                dynamicGroup,
+                                textDto,
+                                rowSpan: 1
+                            })
+                        }
+                        accountIndex1 += 1
+                    })
                 } else {
                     newData = cartesianProduct(data, newDynamicGroup.length > 0 ? newDynamicGroup : [{}]).map((item, index) => {
                         let [d1, group] = item

+ 37 - 11
src/pages/launchSystemV3/tencentAdPutIn/create/index.tsx

@@ -209,8 +209,6 @@ const Create: React.FC = () => {
 
 
     const preview = () => {
-        console.log('addelivery------>', addelivery)
-        console.log('accountCreateLogs------>', accountCreateLogs)
         if (accountCreateLogs?.length === 0) {
             message.error('请先选择媒体账户')
             return
@@ -281,9 +279,8 @@ const Create: React.FC = () => {
 
         // 创意组平均分配到广告逻辑
         let averageAdDynamicList: any[] = []
-        if (mediaType === 1 && newDynamicGroup.length) {
+        if ((mediaType === 1 || mediaType === 2) && newDynamicGroup.length) {
             let adLength = 0
-            let isReturn = false
             accountCreateLogs.forEach(item => {
                 let productList: any[] = []
                 if (['MARKETING_TARGET_TYPE_FICTION'].includes(marketingAssetOuterSpec?.marketingTargetType)) { // 小说
@@ -292,17 +289,21 @@ const Create: React.FC = () => {
                     productList = item?.wechatChannelList || []
                 }
                 adLength += productList.length * targeting.length
+            })
+            if (mediaType === 1) {
                 if (adLength > dynamicGroupLength) {
-                    isReturn = true
+                    message.error(`创意组分配规则选择“平均分配到广告”时,创意组总数必须大于等于广告总数。当前创意组数量:${dynamicGroupLength},广告数量:${adLength}`)
+                    return
                 }
                 averageAdDynamicList = distributeArray(newDynamicGroup, adLength)
-            })
-            if (isReturn) {
-                message.error(`创意组分配规则选择创意组平均分配到广告时,创意组总数必须大于等于广告总数。当前创意组数量:${dynamicGroupLength},广告数量:${adLength}`)
-                return
+            } else if (mediaType === 2) {
+                if (adLength < dynamicGroupLength) {
+                    message.error(`创意组分配规则选择“顺序分配到广告”时,创意组总数必须小于等于广告总数。当前创意组数量:${dynamicGroupLength},广告数量:${adLength}`)
+                    return
+                }
             }
         }
-        let accountIndex = 0
+        let accountIndex = 0, accountIndex1 = 0
         accountCreateLogs.forEach(item => {
             let productList: any[] = []
             if (['MARKETING_TARGET_TYPE_FICTION'].includes(marketingAssetOuterSpec?.marketingTargetType)) { // 小说
@@ -382,7 +383,32 @@ const Create: React.FC = () => {
                             })
                         }
                     })
-                } else {
+                } else if (mediaType === 2) {
+                    data.forEach((item) => {
+                        const { averageAdDynamic, ...ad } = item
+                        if (textType === 3) {
+                            cartesianProduct(textDto, [newDynamicGroup[accountIndex1 % newDynamicGroup.length]]).forEach((taad: any) => {
+                                let [textValue, aad, index] = taad
+                                newData.push({
+                                    ...ad,
+                                    id: ad.id + '_' + index,
+                                    dynamicGroup: aad,
+                                    textDto: textValue,
+                                    rowSpan: textDto.length
+                                })
+                            })
+                        } else {
+                            let { textDto, ...dynamicGroup } = newDynamicGroup[accountIndex1 % newDynamicGroup.length]
+                            newData.push({
+                                ...ad,
+                                dynamicGroup,
+                                textDto,
+                                rowSpan: 1
+                            })
+                        }
+                        accountIndex1 += 1
+                    })
+                } else { // 全账号复用创意组 所有广告一样的创意组
                     newData = cartesianProduct(data, newDynamicGroup.length > 0 ? newDynamicGroup : [{}]).map((item, index) => {
                         let [d1, group] = item
                         return {

+ 50 - 3
src/pages/launchSystemV3/tencentAdPutIn/create/tableConfig.tsx

@@ -3,6 +3,7 @@ import React from "react"
 import { OPTIMIZATIONGOAL_ENUM } from "../const";
 const { Text, Title } = Typography;
 import style from './index.less'
+import VideoNews from "@/pages/launchSystemNew/components/newsModal/videoNews";
 
 const columns = (): TableProps<any>['columns'] => {
 
@@ -100,14 +101,37 @@ const columns = (): TableProps<any>['columns'] => {
                     title: '创意素材',
                     dataIndex: 'dynamicGroup',
                     key: 'dynamicGroup',
-                    width: 200,
+                    width: 210,
                     render: (_, b) => {
                         let deliveryMode = b?.dynamicDto?.deliveryMode
                         let dynamicGroup = b?.dynamicGroup
                         if (dynamicGroup && Object.keys(dynamicGroup).length) {
                             let keys = Object.keys(dynamicGroup)
                             if (deliveryMode === "DELIVERY_MODE_CUSTOMIZE") {
-                                return <Text style={{ fontSize: 12, color: '#1890ff' }}>已选{(keys.includes('video_id') || keys.includes('short_video1')) ? '1个视频,0张图片' : keys.includes('image_id') ? '0个视频,1张图片' : (keys.includes('image_list') || keys.includes('element_story') ? '1个组图, 0个视频' : '')}</Text>
+                                // return <Text style={{ fontSize: 12, color: '#1890ff' }}>已选{(keys.includes('video_id') || keys.includes('short_video1')) ? '1个视频,0张图片' : keys.includes('image_id') ? '0个视频,1张图片' : (keys.includes('image_list') || keys.includes('element_story') ? '1个组图, 0个视频' : '')}</Text>
+                                return <>
+                                    <div className={style.detail_body_m}>
+                                        {(keys.includes('video_id') || keys.includes('short_video1')) ? <>
+                                            <Title style={{ fontSize: 12, color: '#1890ff', marginBottom: 0, width: '100%' }}>已选1个视频,0张图片</Title>
+                                            <div className={style.video}>
+                                                <VideoNews src={dynamicGroup?.video_id?.url || dynamicGroup?.short_video1?.url} />
+                                                {dynamicGroup?.cover_id && <div className={style.cover_image} style={{ marginLeft: 4 }}>
+                                                    <img src={dynamicGroup?.cover_id?.url} />
+                                                </div>}
+                                            </div>
+                                        </> : keys.includes('image_id') ? <>
+                                            <Title style={{ fontSize: 12, color: '#1890ff', marginBottom: 0, width: '100%' }}>已选0个视频,1张图片</Title>
+                                            <div className={style.cover_image}>
+                                                <img src={dynamicGroup?.image_id?.url} />
+                                            </div>
+                                        </> : (keys.includes('image_list') || keys.includes('element_story')) ? <>
+                                            <Title style={{ fontSize: 12, color: '#1890ff', marginBottom: 0, width: '100%' }}>已选1个组图, 0个视频</Title>
+                                            {dynamicGroup?.[keys.includes('image_list') ? 'image_list' : 'element_story']?.map((item: { url: string | undefined; }, index: undefined) => <div className={style.cover_image} key={index} style={{ width: 30, height: 24, minWidth: 32 }}>
+                                                <img src={item?.url} />
+                                            </div>)}
+                                        </> : null}
+                                    </div>
+                                </>
                             } else {
                                 return <Text style={{ fontSize: 12 }}>开发中</Text>
                             }
@@ -213,7 +237,30 @@ export const columnsAddDynamic = (): TableProps<any>['columns'] => {
                         if (dynamicGroup && Object.keys(dynamicGroup).length) {
                             let keys = Object.keys(dynamicGroup)
                             if (deliveryMode === "DELIVERY_MODE_CUSTOMIZE") {
-                                return <Text style={{ fontSize: 12, color: '#1890ff' }}>已选{(keys.includes('video_id') || keys.includes('short_video1')) ? '1个视频,0张图片' : keys.includes('image_id') ? '0个视频,1张图片' : (keys.includes('image_list') || keys.includes('element_story') ? '1个组图, 0个视频' : '')}</Text>
+                                // return <Text style={{ fontSize: 12, color: '#1890ff' }}>已选{(keys.includes('video_id') || keys.includes('short_video1')) ? '1个视频,0张图片' : keys.includes('image_id') ? '0个视频,1张图片' : (keys.includes('image_list') || keys.includes('element_story') ? '1个组图, 0个视频' : '')}</Text>
+                                return <>
+                                    <div className={style.detail_body_m}>
+                                        {(keys.includes('video_id') || keys.includes('short_video1')) ? <>
+                                            <Title style={{ fontSize: 12, color: '#1890ff', marginBottom: 0, width: '100%' }}>已选1个视频,0张图片</Title>
+                                            <div className={style.video}>
+                                                <VideoNews src={dynamicGroup?.video_id?.url || dynamicGroup?.short_video1?.url} />
+                                                {dynamicGroup?.cover_id && <div className={style.cover_image} style={{ marginLeft: 4 }}>
+                                                    <img src={dynamicGroup?.cover_id?.url} />
+                                                </div>}
+                                            </div>
+                                        </> : keys.includes('image_id') ? <>
+                                            <Title style={{ fontSize: 12, color: '#1890ff', marginBottom: 0, width: '100%' }}>已选0个视频,1张图片</Title>
+                                            <div className={style.cover_image}>
+                                                <img src={dynamicGroup?.image_id?.url} />
+                                            </div>
+                                        </> : (keys.includes('image_list') || keys.includes('element_story')) ? <>
+                                            <Title style={{ fontSize: 12, color: '#1890ff', marginBottom: 0, width: '100%' }}>已选1个组图, 0个视频</Title>
+                                            {dynamicGroup?.[keys.includes('image_list') ? 'image_list' : 'element_story']?.map((item: { url: string | undefined; }, index: undefined) => <div className={style.cover_image} key={index} style={{ width: 30, height: 24, minWidth: 32 }}>
+                                                <img src={item?.url} />
+                                            </div>)}
+                                        </> : null}
+                                    </div>
+                                </>
                             } else {
                                 return <Text style={{ fontSize: 12 }}>开发中</Text>
                             }

+ 1 - 0
src/pages/launchSystemV3/tencentAdPutIn/index.less

@@ -77,6 +77,7 @@
         border-radius: var(--boder) var(--boder) 0 0;
     }
 
+    .ant-card-extra,
     .ant-card-head-title {
         padding: 8px 0;
     }

+ 1 - 1
src/pages/launchSystemV3/tencentAdPutIn/typings.d.ts

@@ -18,7 +18,7 @@ declare namespace PULLIN {
         dynamic: any,
         dynamicMaterialDTos: any
         dynamicCreativesTextDTOS: any,
-        mediaType: 0 | 1
+        mediaType: 0 | 1 | 2
     }
     interface DispatchAddelivery {
         addelivery: AddeliveryProps,