فهرست منبع

Merge branch 'develop' of http://git.zanxiangnet.com/wjx/ad-manage

wjx 6 ماه پیش
والد
کامیت
19259be943

+ 3 - 3
src/pages/launchSystemV3/components/New1Radio/index.less

@@ -7,7 +7,7 @@
 
     >div {
         height: 28px;
-        padding: 0 20px;
+        padding: 0 16px;
         box-sizing: border-box;
         border-radius: 999px;
         align-items: center;
@@ -26,7 +26,7 @@
 
         >div {
             position: absolute;
-            left: 12px;
+            left: 6px;
             content: '';
             width: 16px;
             height: 16px;
@@ -42,7 +42,7 @@
             }
 
             >span {
-                transform: translateX(8px);
+                transform: translateX(9px);
                 font-weight: 600;
             }
         }

+ 9 - 7
src/pages/launchSystemV3/material/cloudNew/const.ts

@@ -27,11 +27,13 @@ export const updateTreeData = (list: DataNode[], key: React.Key, children: DataN
 
 /** 选择素材 展示字段 */
 export const showFieldList = [
-    { label: '创建时间', value: 'material.create_time' },
-    { label: '消耗', value: 'material_data_day.cost' },
-    { label: '点击率', value: 'material_data_day.ctr' },
-    { label: '目标转化率', value: 'material_data_day.conversions_rate' },
-    { label: '创意关联数', value: 'material_data_day.adgroup_count' },
-    { label: '创意关联数', value: 'material_data_day.dynamic_creative_count' },
-    { label: '备注', value: 'description' }
+    { label: '创建时间', value: 'material.create_time', field: 'create_time' },
+    { label: '下单次数', value: 'material_data_day.order_pv', field: 'order_pv' },
+    { label: '下单成本', value: 'material_data_day.order_cost', field: 'order_cost' },
+    { label: '消耗', value: 'material_data_day.cost', field: 'cost' },
+    { label: '点击率', value: 'material_data_day.ctr', field: 'ctr' },
+    { label: '目标转化率', value: 'material_data_day.conversions_rate', field: 'conversions_rate' },
+    { label: '创意关联数', value: 'material_data_day.adgroup_count', field: 'adgroup_count' },
+    { label: '创意关联数', value: 'material_data_day.dynamic_creative_count', field: 'dynamic_creative_count' },
+    { label: '备注', value: 'description', field: 'description' }
 ]

+ 11 - 5
src/pages/launchSystemV3/material/cloudNew/selectCloudNew.tsx

@@ -40,7 +40,7 @@ const SelectCloudNew: React.FC<CLOUDNEW.SelectCloudNewProps> = ({ visible, defau
     const [searchParams, setSearchParams] = useState<Partial<CLOUDNEW.GetMaterialDataListProps>>({})
     const [uploadVisible, setUploadVisible] = useState<boolean>(false)
     const [showField, setShowField] = useLocalStorageState<string[]>('show-field', ['material.create_time', 'material_data_day.cost', 'material_data_day.ctr', 'material_data_day.conversions_rate', 'material_data_day.dynamic_creative_count']);
-    const [sortData, setSortData] = useLocalStorageState<{ sortField: string, sortType: boolean }>('sort-data', { sortField: 'material.create_time', sortType: false });
+    const [sortData, setSortData] = useLocalStorageState<{ sortField: string | undefined, sortType: boolean }>('sort-data', { sortField: undefined, sortType: false });
 
     const getMaterialDataList = useAjax((params) => getMaterialDataListApi(params))
     /************************************/
@@ -52,8 +52,12 @@ const SelectCloudNew: React.FC<CLOUDNEW.SelectCloudNewProps> = ({ visible, defau
     }, [sliderImgContent])
 
     useEffect(() => {
-        getMaterialDataList.run({ ...sortData, ...searchParams, ...defaultParams, ...queryParams })
-    }, [queryParams, defaultParams, searchParams, sortData])
+        let params = { ...searchParams, ...defaultParams, ...queryParams }
+        if (sortData?.sortField) {
+            params = { ...params, ...sortData }
+        }
+        getMaterialDataList.run(params)
+    }, [queryParams, defaultParams, searchParams, sortData, showField])
 
     // 根据内容宽度计算列数
     useEffect(() => {
@@ -189,7 +193,7 @@ const SelectCloudNew: React.FC<CLOUDNEW.SelectCloudNewProps> = ({ visible, defau
                                 >全选</Checkbox>
                                 <span>已选 <span style={{ color: '#1890FF' }}>{checkedFolderList?.length || 0}</span>/{num} 个素材</span>
                                 {checkedFolderList.length > 0 && <a style={{ color: 'red' }} onClick={() => setCheckedFolderList([])}>清除所有</a>}
-                                <Text>「排序-{showFieldList.find(item => item.value === sortData.sortField)?.label}-{sortData.sortType ? '正序' : '倒序'}」</Text>
+                                {sortData?.sortField && <Text>「排序-{showFieldList.find(item => item.value === sortData.sortField)?.label}-{sortData.sortType ? '正序' : '倒序'}」</Text>}
                             </div>
                             <div className={style.left_bts}>
                                 <Popover
@@ -218,6 +222,7 @@ const SelectCloudNew: React.FC<CLOUDNEW.SelectCloudNewProps> = ({ visible, defau
                                                             message.warn('最少选择1个指标')
                                                             return
                                                         }
+                                                        setSortData({ ...sortData, sortField: undefined })
                                                         setShowField(value as any)
                                                     }}
                                                 />
@@ -231,8 +236,9 @@ const SelectCloudNew: React.FC<CLOUDNEW.SelectCloudNewProps> = ({ visible, defau
                                                         filterOption={(input, option) =>
                                                             (option?.label as any)?.toLowerCase().indexOf(input.toLowerCase()) >= 0
                                                         }
-                                                        options={showFieldList.filter(item => item.value !== 'description')}
+                                                        options={showFieldList.filter(item => showField.includes(item.value) && item.value !== 'description')}
                                                         value={sortData.sortField}
+                                                        allowClear
                                                         onChange={(value) => {
                                                             setSortData({ ...sortData, sortField: value as any })
                                                         }}

+ 9 - 3
src/pages/launchSystemV3/material/cloudNew/selectSearch.tsx

@@ -33,6 +33,9 @@ const SelectSearch: React.FC<Props> = ({ onSearch }) => {
             } else if ('uploadTime' === key && value?.length === 2) {
                 params.uploadTimeMin = moment(value?.[0]).format('YYYY-MM-DD')
                 params.uploadTimeMax = moment(value?.[1]).format('YYYY-MM-DD')
+            } else if ('dataTime' === key && value?.length === 2) {
+                params.dataTimeMin = moment(value?.[0]).format('YYYY-MM-DD')
+                params.dataTimeMax = moment(value?.[1]).format('YYYY-MM-DD')
             } else {
                 params[key] = value
             }
@@ -85,6 +88,9 @@ const SelectSearch: React.FC<Props> = ({ onSearch }) => {
                         options={getUserAll?.data?.map((item: { nickname: any; userId: any }) => ({ label: item.nickname, value: item.userId }))}
                     />
                 </Form.Item></Col>
+                <Col><Form.Item name={'minCost'}>
+                    <InputNumber style={{ width: 80 }} placeholder="最小消耗" />
+                </Form.Item></Col>
                 <Col><Form.Item name={'accountIds'}>
                     <Input.TextArea rows={1} style={{ width: 190 }} allowClear placeholder="广告账号(多个逗号、换行等隔开)" />
                 </Form.Item></Col>
@@ -97,9 +103,6 @@ const SelectSearch: React.FC<Props> = ({ onSearch }) => {
                 <Col><Form.Item name={'tencentMaterialId'}>
                     <Input.TextArea rows={1} style={{ width: 190 }} allowClear placeholder="腾讯素材ID(多个逗号、换行等隔开)" />
                 </Form.Item></Col>
-                <Col><Form.Item name={'minCost'}>
-                    <InputNumber style={{ width: 80 }} placeholder="最小消耗" />
-                </Form.Item></Col>
                 <Col><Form.Item name={'useStatus'}>
                     <Select
                         placeholder="使用情况"
@@ -114,6 +117,9 @@ const SelectSearch: React.FC<Props> = ({ onSearch }) => {
                 <Col><Form.Item name={'uploadTime'}>
                     <DatePicker.RangePicker style={{ width: 260 }} placeholder={['上传时间开始', '上传时间结束']} />
                 </Form.Item></Col>
+                <Col><Form.Item name={'dataTime'}>
+                    <DatePicker.RangePicker style={{ width: 260 }} placeholder={['数据时间开始', '数据时间结束']} />
+                </Form.Item></Col>
                 <Col><Form.Item>
                     <Space>
                         <Button onClick={() => form.resetFields()}>重置</Button>

+ 60 - 2
src/pages/launchSystemV3/tencenTasset/wechatCanvasPage/index.tsx

@@ -1,7 +1,7 @@
-import { Button, Card, Input, Select, Table } from "antd"
+import { Button, Card, Input, message, Popconfirm, Select, Table } from "antd"
 import React, { useEffect, useState } from "react"
 import '../../tencentAdPutIn/index.less'
-import { getAdqLandingPageListApi, getWXDownPageAuthInfoListApi } from "@/services/adqV3/global";
+import { delPageApi, getAdqLandingPageListApi, getWXDownPageAuthInfoListApi } from "@/services/adqV3/global";
 import { useAjax } from "@/Hook/useAjax";
 import { useModel } from "umi";
 import { SearchOutlined } from "@ant-design/icons";
@@ -28,9 +28,11 @@ const WechatCanvasPage: React.FC = () => {
     const [queryParamsNew, setQueryParamsNew] = useState<AjaxProps>({ pageNum: 1, pageSize: 20 })
     const [visible, setVisible] = useState<boolean>(false)
     const [pageData, setPageData] = useState<any>()
+    const [selectedRows, setSelectedRows] = useState<any[]>([])
 
     const getAdqLandingPageList = useAjax((params) => getAdqLandingPageListApi(params))
     const getWXDownPageAuthInfoList = useAjax((params) => getWXDownPageAuthInfoListApi(params))
+    const delPage = useAjax((params) => delPageApi(params))
     /********************************/
 
     useEffect(() => {
@@ -60,6 +62,16 @@ const WechatCanvasPage: React.FC = () => {
         setPageData(data)
     }
 
+    const handleDel = () => {
+        delPage.run({ accountId: queryParamsNew.accountId, pageIds: selectedRows.map(item => item.pageId) }).then(res => {
+            if (res?.length === 0) {
+                message.success('删除成功,结果可能会延迟几分钟返回')
+                getAdqLandingPageList.refresh()
+                setSelectedRows([])
+            }
+        })
+    }
+
     return <Card
         className="cardResetCss"
         title={<div className="flexStart" style={{ gap: 8 }}>
@@ -104,6 +116,12 @@ const WechatCanvasPage: React.FC = () => {
             </>}
 
             <Button type="primary" icon={<SearchOutlined />} loading={getAdqLandingPageList.loading} onClick={() => getAdqLandingPageList.refresh()}>刷新</Button>
+            <Popconfirm
+                title="确定删除?"
+                onConfirm={() => handleDel?.()}
+            >
+                <Button danger loading={delPage.loading} disabled={selectedRows.length === 0 || !!queryParamsNew?.ownerUid}>删除</Button>
+            </Popconfirm>
         </div>}
     >
         <Table
@@ -124,6 +142,46 @@ const WechatCanvasPage: React.FC = () => {
                 const { current, pageSize } = pagination
                 setQueryParamsNew({ ...queryParamsNew, pageNum: current as number, pageSize: pageSize as number || 20 })
             }}
+            rowSelection={{
+                selectedRowKeys: selectedRows.map(item => item.pageId),
+                getCheckboxProps: (record: any) => {
+                    return {
+                        disabled: !!queryParamsNew?.ownerUid || record?.canvasType === 'COMMON_PAGE'
+                    }
+                },
+                onSelect: (record: { pageId: number }, selected: boolean) => {
+                    if (selected) {
+                        selectedRows.push({ ...record })
+                        setSelectedRows([...selectedRows])
+                    } else {
+                        let newSelectAccData = selectedRows.filter((item: { pageId: number }) => item.pageId !== record.pageId)
+                        setSelectedRows([...newSelectAccData])
+                    }
+                },
+                onSelectAll: (selected: boolean, selectedRowss: { pageId: number }[], changeRows: { pageId: number }[]) => {
+                    if (selected) {
+                        let newSelectAccData = [...selectedRows]
+                        changeRows.forEach((item: { pageId: number }) => {
+                            let index = newSelectAccData.findIndex((ite: { pageId: number }) => ite.pageId === item.pageId)
+                            if (index === -1) {
+                                let data: any = { ...item }
+                                newSelectAccData.push(data)
+                            }
+                        })
+                        setSelectedRows([...newSelectAccData])
+                    } else {
+                        let newSelectAccData = selectedRows.filter((item: { pageId: number }) => {
+                            let index = changeRows.findIndex((ite: { pageId: number }) => ite.pageId === item.pageId)
+                            if (index !== -1) {
+                                return false
+                            } else {
+                                return true
+                            }
+                        })
+                        setSelectedRows([...newSelectAccData])
+                    }
+                }
+            }}
         />
 
         {visible && <CopyPage

+ 10 - 9
src/pages/launchSystemV3/tencentAdPutIn/create/Dynamic/SelectBarrage.tsx

@@ -5,8 +5,8 @@ import React, { useEffect, useState } from "react"
 
 interface Props {
     arrayProperty: { maxNumber: number, minNumber: number }
-    value?: { text: string, id: number }[]
-    onChange?: (value?: { text: string, id: number }[]) => void
+    value?: { text: string }[]
+    onChange?: (value?: { text: string }[]) => void
     putInType?: 'NOVEL' | 'GAME'
 }
 
@@ -18,7 +18,7 @@ interface Props {
 const SelectBarrage: React.FC<Props> = ({ arrayProperty, value = [], onChange, putInType }) => {
 
     /****************************************/
-    const [barrageList, setBarrageList] = useState<{ text: string, id: number }[]>([])
+    const [barrageList, setBarrageList] = useState<string[]>([])
 
     const getBarrageRecommendList = useAjax((params) => getBarrageRecommendListApi(params))
     /****************************************/
@@ -26,14 +26,16 @@ const SelectBarrage: React.FC<Props> = ({ arrayProperty, value = [], onChange, p
     useEffect(() => {
         getBarrageRecommendList.run({ taskType: putInType }).then(res => {
             if (res?.list?.length) {
-                setBarrageList(res?.list || [])
+                const setBarrage = new Set(res?.list.map((item: { text: string }) => item.text))
+                const arrayBarrage = [...setBarrage]
+                setBarrageList(arrayBarrage as string[])
             } else {
                 setBarrageList([])
             }
         })
     }, [putInType])
 
-    let barrageValue = value?.map(item => item.id)
+    let barrageValue = value?.map(item => item.text)
     return <div
         style={{
             border: '1px solid #d9d9d9',
@@ -47,19 +49,18 @@ const SelectBarrage: React.FC<Props> = ({ arrayProperty, value = [], onChange, p
         <Select
             showSearch
             placeholder="请选择弹幕"
-            onChange={(_, options) => {
-                onChange?.(options?.length > 0 ? options.map((item: { text: any; value: any }) => ({ text: item.text, id: item.value })) : [])
+            onChange={(e) => {
+                onChange?.(e?.length > 0 ? e.map(item => ({ text: item })) : [])
             }}
             value={barrageValue}
             mode="multiple"
             filterOption={(input, option) =>
                 ((option?.label ?? '') as any).toLowerCase().includes(input.toLowerCase())
             }
-            allowClear
             loading={getBarrageRecommendList.loading}
             bordered={false}
         >
-            {barrageList.map((item: { text: string, id: number }) => <Select.Option key={item.id} value={item.id} text={item.text} disabled={barrageValue?.length > arrayProperty.maxNumber && !barrageValue.includes(item.id)}>{item.text}</Select.Option>)}
+            {barrageList.map((item: string, index: number) => <Select.Option key={index} value={item} disabled={barrageValue?.length > arrayProperty.maxNumber && !barrageValue.includes(item)}>{item}</Select.Option>)}
         </Select>
         <div
             style={{

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

@@ -294,7 +294,7 @@ 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 }, { label: '顺序分配到广告', value: 2 }]}
+                        data={[{ label: '全广告复用', value: 0 }, { label: '平均分配到广告', value: 1 }, { label: '顺序分配到广告', value: 2 }, { label: '账号下平均分配到广告', value: 3 }]}
                         onChange={(e) => {
                             if (e === 2 && dynamicGroup?.length > adLength) {
                                 form.setFieldsValue({ dynamicGroup: dynamicGroup.slice(0, adLength) })

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

@@ -90,7 +90,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 ? '平均分配到广告' : mediaType === 2 ? '顺序分配到广告' : null}</Title>
+                        <Title level={5} style={{ fontSize: 12 }}>{mediaType === 0 ? '全账号复用' : mediaType === 1 ? '平均分配到广告' : mediaType === 2 ? '顺序分配到广告' : mediaType === 3 ? '账号下平均分配到广告' : null}</Title>
                         <div className={style.detail_body_m}>
                             {dynamicMaterialDTos.dynamicGroup.map((item: any, index: number) => {
                                 if (deliveryMode === 'DELIVERY_MODE_CUSTOMIZE') {

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

@@ -12,7 +12,7 @@ import VideoNews from "@/pages/launchSystemNew/components/newsModal/videoNews"
 interface Props {
     textData: any,
     dynamicMaterialDTos: any,
-    mediaType: 0 | 1 | 2,
+    mediaType: 0 | 1 | 2 | 3,
     deliveryMode?: string,
     value?: any,
     visible?: boolean
@@ -169,7 +169,7 @@ const NewText: React.FC<Props> = ({ visible, onClose, onChange, value, textData,
                         let count = dynamicMaterialDTos.dynamicGroup.length
                         let oldtextDto: PULLIN.TextDtoProps[] = JSON.parse(JSON.stringify(textDto))
                         let length = oldtextDto.length
-                        if (value === 0) {
+                        if (value === 0 || (mediaType === 2 && value === 2)) {
                             oldtextDto = [textDto[0] || {}]
                         } else if (value === 1) {
                             if (count > length) {
@@ -184,7 +184,7 @@ const NewText: React.FC<Props> = ({ visible, onClose, onChange, value, textData,
                         }
                         form.setFieldsValue({ textDto: oldtextDto })
                     }}>
-                        {TextTypeList.filter(item => mediaType !== 1 ? item.value !== 4 : true).map(item => <Radio value={item.value} key={item.value}>{item.label}</Radio>)}
+                        {TextTypeList.filter(item => (mediaType !== 1 && mediaType !== 3) ? item.value !== 4 : true).map(item => <Radio value={item.value} key={item.value}>{item.label}</Radio>)}
                     </Radio.Group>
                 </Form.Item>
             </Card>
@@ -254,7 +254,7 @@ const NewText: React.FC<Props> = ({ visible, onClose, onChange, value, textData,
                             </div>
                         </Card>
                     ))}
-                    {[3, 2, 4].includes(type) && !(type === 2 && textDto.length >= dynamicMaterialDTos.dynamicGroup.length) && <Form.Item style={{ marginTop: 10, marginBottom: 0 }}>
+                    {[3, 2, 4].includes(type) && !(mediaType === 2 && type === 2) && !(type === 2 && textDto.length >= dynamicMaterialDTos.dynamicGroup.length) && <Form.Item style={{ marginTop: 10, marginBottom: 0 }}>
                         <Button type="primary" onClick={() => add(newText)} block icon={<PlusOutlined />} disabled={type === 3 && textDto.length >= 30}>
                             新增
                         </Button>

+ 131 - 102
src/pages/launchSystemV3/tencentAdPutIn/create/addDynamic.tsx

@@ -174,11 +174,10 @@ const AddDynamic: React.FC<PULLIN.NewAddDynamic> = ({ visible, onChange, onClose
 
         let newTableData: any = {}, newDynamicCount = 0
 
-        let textType = dynamicCreativesTextDTOS.type
-        let textDto = dynamicCreativesTextDTOS?.dynamicCreativesTextDetailDTOList || []
-        let textDtoLenth = textDto.length
-        let dynamicGroupLength = dynamicMaterialDTos?.dynamicGroup?.length || 0
-
+        const textType = dynamicCreativesTextDTOS.type
+        const textDto = dynamicCreativesTextDTOS?.dynamicCreativesTextDetailDTOList || []
+        const textDtoLenth = textDto.length
+        const dynamicGroupLength = dynamicMaterialDTos?.dynamicGroup?.length || 0
         let newDynamicGroup: any = []
         if (![910].includes(dynamic.creativeTemplateId)) {
             newDynamicGroup = dynamicMaterialDTos?.dynamicGroup || []
@@ -189,7 +188,7 @@ const AddDynamic: React.FC<PULLIN.NewAddDynamic> = ({ visible, onChange, onClose
                     newDynamicGroup = newDynamicGroup.map((item: any, index: number) => ({ ...item, textDto: textDto?.[index] }))
                 } else if (textType === 2) {
                     newDynamicGroup = newDynamicGroup.map((item: any, index: number) => ({ ...item, textDto: textDto?.[index % textDtoLenth] }))
-                } else if ((textType === 3 && mediaType === 0) || (textType === 4 && mediaType === 1)) {
+                } else if ((textType === 3 && mediaType === 0) || (textType === 4 && mediaType === 1) || (textType === 4 && mediaType === 3)) {
                     newDynamicGroup = cartesianProduct(newDynamicGroup, textDto || [{}]).map((item) => {
                         let [dynamicGroup, textDtoData] = item
                         return {
@@ -203,7 +202,7 @@ const AddDynamic: React.FC<PULLIN.NewAddDynamic> = ({ visible, onChange, onClose
 
         // 创意组平均分配到广告逻辑
         let averageAdDynamicList: any[] = []
-        if ((mediaType === 1 || mediaType === 2) && newDynamicGroup.length) {
+        if ((mediaType === 1 || mediaType === 2 || mediaType === 3) && newDynamicGroup.length) {
             let adLength = adData.length
             if (mediaType === 1) {
                 if (textType === 4) {
@@ -224,6 +223,18 @@ const AddDynamic: React.FC<PULLIN.NewAddDynamic> = ({ visible, onChange, onClose
                     message.error(`创意组分配规则选择“顺序分配到广告”时,创意组总数必须小于等于广告总数。当前创意组数量:${dynamicGroupLength},广告数量:${adLength}`)
                     return
                 }
+            } else if (mediaType === 3) {
+                const dynamicDataLength = textType === 4 ? newDynamicGroup.length : dynamicGroupLength
+                if (Object.keys(adDataGroup).some(key => {
+                    const adLength = adDataGroup[key as any].length
+                    if (adLength > dynamicDataLength) {
+                        message.error(`创意组分配规则选择“账号下平均分配到广告”时,创意组总数必须大于等于每个账号广告总数。当前创意组数量:${dynamicDataLength},当前账号(${key})下广告数量:${adLength}`)
+                        return true
+                    }
+                    return false
+                })) {
+                    return
+                }
             }
         }
         // 落地页平均分配判断数量
@@ -283,110 +294,128 @@ const AddDynamic: React.FC<PULLIN.NewAddDynamic> = ({ visible, onChange, onClose
                 newDynamicCount += item.pageList.length
             })
         } else {
-            adData.forEach((ad, index) => {
-                let item = accountCreateLogs.find(a => a.accountId === ad.accountId) as PULLIN.AccountCreateLogsProps
-                let averageAdDynamic = averageAdDynamicList?.[index]
-                let data = [{
-                    id: ad.adgroupId + '_' + index,
-                    pageListDto: item.pageList,                   // 落地页
-                    adgroupsDto: ad,
-                    dynamicDto: dynamic,                          // 创意信息
-                    averageAdDynamic,
-                    rowSpan: (mediaType === 1 && textType !== 4) ? averageAdDynamic.length : ([910].includes(dynamic.creativeTemplateId) ? item.pageList?.length : (textType === 3 ? textDtoLenth * dynamicGroupLength : dynamicGroupLength)) || 1
-                }]
-
-                let newData: any[] = []
-                if ([910].includes(dynamic.creativeTemplateId)) {
-                    newData = cartesianProduct(data, item.pageList).map((item, index) => {
-                        let [d1, pageList, num] = item
-                        return {
-                            ...d1,
-                            id: d1.id + '_' + index,
-                            pageListDto: [pageList],
-                            dynamicDto: {
-                                ...d1.dynamicDto,
-                                dynamicCreativeName: d1.dynamicDto.dynamicCreativeName + num
+            const handleDynamic = (adData: any[], averageAdDynamicList: any[]) => {
+                adData.forEach((ad, index) => {
+                    let item = accountCreateLogs.find(a => a.accountId === ad.accountId) as PULLIN.AccountCreateLogsProps
+                    let averageAdDynamic = averageAdDynamicList?.[index]
+                    let data = [{
+                        id: ad.adgroupId + '_' + index,
+                        pageListDto: item.pageList,                   // 落地页
+                        adgroupsDto: ad,
+                        dynamicDto: dynamic,                          // 创意信息
+                        averageAdDynamic,
+                        rowSpan: ((mediaType === 1 || mediaType === 3) && textType !== 4) ? averageAdDynamic.length : ([910].includes(dynamic.creativeTemplateId) ? item.pageList?.length : (textType === 3 ? textDtoLenth * dynamicGroupLength : dynamicGroupLength)) || 1
+                    }]
+    
+                    let newData: any[] = []
+                    if ([910].includes(dynamic.creativeTemplateId)) {
+                        newData = cartesianProduct(data, item.pageList).map((item, index) => {
+                            let [d1, pageList, num] = item
+                            return {
+                                ...d1,
+                                id: d1.id + '_' + index,
+                                pageListDto: [pageList],
+                                dynamicDto: {
+                                    ...d1.dynamicDto,
+                                    dynamicCreativeName: d1.dynamicDto.dynamicCreativeName + num
+                                }
                             }
-                        }
-                    })
-                } else {
-                    if (mediaType === 1) {
-                        data.forEach(item => {
-                            const { averageAdDynamic, ...ad } = item
-                            if (textType === 3) {
-                                let rowSpan = textDtoLenth * averageAdDynamic.length
-                                cartesianProduct(textDto, averageAdDynamic).forEach((taad: any, index) => {
-                                    let [textValue, aad] = taad
-                                    newData.push({
-                                        ...ad,
-                                        id: ad.id + '_' + index,
-                                        dynamicGroup: aad,
-                                        textDto: textValue,
-                                        rowSpan
+                        })
+                    } else {
+                        if (mediaType === 1 || mediaType === 3) {
+                            data.forEach(item => {
+                                const { averageAdDynamic, ...ad } = item
+                                if (textType === 3) {
+                                    let rowSpan = textDtoLenth * averageAdDynamic.length
+                                    cartesianProduct(textDto, averageAdDynamic).forEach((taad: any, index) => {
+                                        let [textValue, aad] = taad
+                                        newData.push({
+                                            ...ad,
+                                            id: ad.id + '_' + index,
+                                            dynamicGroup: aad,
+                                            textDto: textValue,
+                                            rowSpan
+                                        })
                                     })
-                                })
-                            } else if (textType === 4) {
-                                averageAdDynamic.forEach((aad: any, index: number) => {
-                                    newData.push({
-                                        ...ad,
-                                        id: ad.id + '_' + index,
-                                        dynamicGroup: aad,
-                                        textDto: aad?.textDto,
-                                        rowSpan: index === 0 ? averageAdDynamic.length : 0,
-                                        isRowSpan: true
+                                } else if (textType === 4) {
+                                    averageAdDynamic.forEach((aad: any, index: number) => {
+                                        newData.push({
+                                            ...ad,
+                                            id: ad.id + '_' + index,
+                                            dynamicGroup: aad,
+                                            textDto: aad?.textDto,
+                                            rowSpan: index === 0 ? averageAdDynamic.length : 0,
+                                            isRowSpan: true
+                                        })
                                     })
-                                })
-                            } else {
-                                averageAdDynamic.forEach((aad: any, index: number) => {
-                                    newData.push({
-                                        ...ad,
-                                        id: ad.id + '_' + index,
-                                        dynamicGroup: aad,
-                                        textDto: aad?.textDto
+                                } else {
+                                    averageAdDynamic.forEach((aad: any, index: number) => {
+                                        newData.push({
+                                            ...ad,
+                                            id: ad.id + '_' + index,
+                                            dynamicGroup: aad,
+                                            textDto: textType === 2 ? textDto?.[index % textDtoLenth] : aad?.textDto
+                                        })
                                     })
-                                })
-                            }
-                        })
-                    } 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
+                                }
+                            })
+                        } 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: nowTextDto, ...dynamicGroup } = newDynamicGroup[accountIndex1 % newDynamicGroup.length]
                                     newData.push({
                                         ...ad,
-                                        id: ad.id + '_' + index,
-                                        dynamicGroup: aad,
-                                        textDto: textValue,
-                                        rowSpan: textDto.length
+                                        dynamicGroup,
+                                        textDto: textType === 2 ? textDto?.[0] : nowTextDto,
+                                        rowSpan: 1
                                     })
-                                })
-                            } else {
-                                let { textDto, ...dynamicGroup } = newDynamicGroup[accountIndex1 % newDynamicGroup.length]
-                                newData.push({
-                                    ...ad,
-                                    dynamicGroup,
-                                    textDto,
-                                    rowSpan: 1
-                                })
-                            }
-                            accountIndex1 += 1
-                        })
+                                }
+                                accountIndex1 += 1
+                            })
+                        } else {
+                            newData = cartesianProduct(data, newDynamicGroup.length > 0 ? newDynamicGroup : [{}]).map((item, index) => {
+                                let [d1, group] = item
+                                return {
+                                    ...d1,
+                                    id: d1.id + '_' + index,
+                                    dynamicGroup: group,
+                                    textDto: (group as any)?.textDto
+                                }
+                            })
+                        }
+                    }
+                    newDynamicCount += newData.length
+                    newTableData[ad.adgroupId] = newData
+                })
+            }
+            if (mediaType === 3) {
+                Object.keys(adDataGroup).forEach(key => {
+                    const newAdData = adDataGroup[key as any]
+                    const adLength = newAdData.length
+                    if (textType === 4) {
+                        averageAdDynamicList = splitArrayIntoRandomChunks(newDynamicGroup, adLength)
                     } else {
-                        newData = cartesianProduct(data, newDynamicGroup.length > 0 ? newDynamicGroup : [{}]).map((item, index) => {
-                            let [d1, group] = item
-                            return {
-                                ...d1,
-                                id: d1.id + '_' + index,
-                                dynamicGroup: group,
-                                textDto: (group as any)?.textDto
-                            }
-                        })
+                        averageAdDynamicList = distributeArray(newDynamicGroup, adLength)
                     }
-                }
-                newDynamicCount += newData.length
-                newTableData[ad.adgroupId] = newData
-            })
+                    handleDynamic(newAdData, averageAdDynamicList)
+                })
+            } else {
+                handleDynamic(adData, averageAdDynamicList)
+            }
+            
+            
         }
 
         setDynamicCount(newDynamicCount)

+ 48 - 16
src/pages/launchSystemV3/tencentAdPutIn/create/index.tsx

@@ -397,10 +397,10 @@ const Create: React.FC = () => {
 
         let newTableData: any = {}
         let newAdCount = 0, newdynamicCount = 0
-        let textType = dynamicCreativesTextDTOS.type
-        let textDto = dynamicCreativesTextDTOS?.dynamicCreativesTextDetailDTOList || []
-        let textDtoLenth = textDto.length
-        let dynamicGroupLength = dynamicMaterialDTos?.dynamicGroup?.length || 0
+        const textType = dynamicCreativesTextDTOS.type
+        const textDto = dynamicCreativesTextDTOS?.dynamicCreativesTextDetailDTOList || []
+        const textDtoLenth = textDto.length
+        const dynamicGroupLength = dynamicMaterialDTos?.dynamicGroup?.length || 0
         let newDynamicGroup: any = []
         if (![910].includes(dynamic.creativeTemplateId)) {
             newDynamicGroup = dynamicMaterialDTos?.dynamicGroup || []
@@ -411,7 +411,7 @@ const Create: React.FC = () => {
                     newDynamicGroup = newDynamicGroup.map((item: any, index: number) => ({ ...item, textDto: textDto?.[index] }))
                 } else if (textType === 2) {
                     newDynamicGroup = newDynamicGroup.map((item: any, index: number) => ({ ...item, textDto: textDto?.[index % textDtoLenth] }))
-                } else if ((textType === 3 && mediaType === 0) || (textType === 4 && mediaType === 1)) {
+                } else if ((textType === 3 && mediaType === 0) || (textType === 4 && mediaType === 1) || (textType === 4 && mediaType === 3)) {
                     newDynamicGroup = cartesianProduct(newDynamicGroup, textDto || [{}]).map((item) => {
                         let [dynamicGroup, textDtoData] = item
                         return {
@@ -424,7 +424,7 @@ const Create: React.FC = () => {
         }
         // 创意组平均分配到广告逻辑
         let averageAdDynamicList: any[] = []
-        if ((mediaType === 1 || mediaType === 2) && newDynamicGroup.length) {
+        if ((mediaType === 1 || mediaType === 2 || mediaType === 3) && newDynamicGroup.length) {
             let adLength = 0
             accountCreateLogs.forEach(item => {
                 let productList: any[] = []
@@ -440,7 +440,7 @@ const Create: React.FC = () => {
             if (mediaType === 1) {
                 if (textType === 4) {
                     if (adLength > newDynamicGroup.length) {
-                        message.error(`创意组分配规则选择“平均分配到广告”时,创意组总数必须大于等于广告总数。当前创意组数量:${dynamicGroupLength},广告数量:${adLength}`)
+                        message.error(`创意组分配规则选择“平均分配到广告”时,创意组总数必须大于等于广告总数。当前创意组数量:${newDynamicGroup.length},广告数量:${adLength}`)
                         return
                     }
                     averageAdDynamicList = splitArrayIntoRandomChunks(newDynamicGroup, adLength)
@@ -456,6 +456,26 @@ const Create: React.FC = () => {
                     message.error(`创意组分配规则选择“顺序分配到广告”时,创意组总数必须小于等于广告总数。当前创意组数量:${dynamicGroupLength},广告数量:${adLength}`)
                     return
                 }
+            } else if (mediaType === 3) {
+                const dynamicDataLength = textType === 4 ? newDynamicGroup.length : dynamicGroupLength
+                if (accountCreateLogs.some(item => {
+                    let productList: any[] = []
+                    if (['MARKETING_TARGET_TYPE_FICTION', 'MARKETING_TARGET_TYPE_SHORT_DRAMA'].includes(marketingAssetOuterSpec?.marketingTargetType)) { // 小说 短剧
+                        productList = item?.productList || []
+                    } else if (['MARKETING_TARGET_TYPE_WECHAT_OFFICIAL_ACCOUNT'].includes(marketingAssetOuterSpec?.marketingTargetType)) { // 公众号
+                        productList = item?.wechatChannelList || []
+                    } else {
+                        productList = [{}]
+                    }
+                    const adLength = productList.length * targeting.length
+                    if (adLength > dynamicDataLength) {
+                        message.error(`创意组分配规则选择“账号下平均分配到广告”时,创意组总数必须大于等于每个账号广告总数。当前创意组数量:${dynamicDataLength},当前账号(${item.accountId})下广告数量:${adLength}`)
+                        return true
+                    }
+                    return false
+                })) {
+                    return
+                }
             }
         }
         if (textType === 1) {
@@ -492,10 +512,18 @@ const Create: React.FC = () => {
             } else if (['MARKETING_TARGET_TYPE_WECHAT_OFFICIAL_ACCOUNT'].includes(marketingAssetOuterSpec?.marketingTargetType)) { // 公众号
                 productList = item?.wechatChannelList || []
             }
-            let data = cartesianProduct(productList, targeting).map(newD => {
+            if (mediaType === 3) {
+                const adLength = productList.length * targeting.length
+                if (textType === 4) {
+                    averageAdDynamicList = splitArrayIntoRandomChunks(newDynamicGroup, adLength)
+                } else {
+                    averageAdDynamicList = distributeArray(newDynamicGroup, adLength)
+                }
+            }
+            let data = cartesianProduct(productList, targeting).map((newD, dindex) => {
                 let [productDto, targetDto, index] = newD
                 let suffix = '_' + item.accountId + '_' + index
-                let averageAdDynamic = averageAdDynamicList?.[accountIndex]
+                let averageAdDynamic = mediaType === 3 ? averageAdDynamicList?.[dindex] : averageAdDynamicList?.[accountIndex]
                 let dat: any = {
                     id: item.accountId + '_' + index,
                     accountId: item.accountId,                    // 账户
@@ -513,7 +541,7 @@ const Create: React.FC = () => {
                     },
                     dynamicDto: dynamic,                          // 创意信息
                     averageAdDynamic,
-                    rowSpan: (mediaType === 1 && textType !== 4) ? averageAdDynamic.length : ([910].includes(dynamic.creativeTemplateId) ? item.pageList?.length : (textType === 3 ? textDtoLenth * dynamicGroupLength : dynamicGroupLength)) || 1
+                    rowSpan: ((mediaType === 1 || mediaType === 3) && textType !== 4) ? averageAdDynamic.length : ([910].includes(dynamic.creativeTemplateId) ? item.pageList?.length : (textType === 3 ? textDtoLenth * dynamicGroupLength : dynamicGroupLength)) || 1
                 }
                 if (marketingCarrierType === 'MARKETING_CARRIER_TYPE_WECHAT_OFFICIAL_ACCOUNT') { // 营销载体
                     dat.marketingCarrierDto = item?.wechatChannelList
@@ -561,7 +589,7 @@ const Create: React.FC = () => {
                     })
                 }
             } else {
-                if (mediaType === 1) {
+                if (mediaType === 1 || mediaType === 3) {
                     data.forEach(item => {
                         const { averageAdDynamic, ...ad } = item
                         if (textType === 3) {
@@ -596,8 +624,12 @@ const Create: React.FC = () => {
                                     ...ad,
                                     id: ad.id + '_' + index,
                                     dynamicGroup: aad,
-                                    textDto: aad?.textDto,
-                                    adLength: data.length
+                                    textDto: textType === 2 ? textDto?.[index % textDtoLenth] : aad?.textDto,
+                                    adLength: data.length,
+                                    ...(mediaType === 3 ? {
+                                        rowSpan: index === 0 ? averageAdDynamic.length : 0,
+                                        isRowSpan: true
+                                    } : {})
                                 })
                             })
                         }
@@ -619,11 +651,11 @@ const Create: React.FC = () => {
                                 })
                             })
                         } else {
-                            let { textDto, ...dynamicGroup } = newDynamicGroup[accountIndex1 % newDynamicGroup.length]
+                            let { textDto: nowTextDto, ...dynamicGroup } = newDynamicGroup[accountIndex1 % newDynamicGroup.length]
                             newData.push({
                                 ...ad,
                                 dynamicGroup,
-                                textDto,
+                                textDto: textType === 2 ? textDto?.[0] : nowTextDto,
                                 rowSpan: 1,
                                 adLength: data.length
                             })
@@ -1068,7 +1100,7 @@ const Create: React.FC = () => {
                             setSubVisible(true)
                         }}>提交创建</Button>
                     </Space>}
-                    items={accountCreateLogs.map(item => ({ label: item.accountId, key: item.accountId })) as any[]}
+                    items={accountCreateLogs.map(item => ({ label: item.accountId, key: item.accountId?.toString() })) as any[]}
                 />
                 {addelivery?.dynamicCreativesTextDTOS?.type === 4 && <Title level={5} style={{ color: 'red', fontSize: 12 }}>因为选择的是“创意组和文案叉乘打乱后分配”模式,会随机打乱,当前预览广告下创意内容会与实际建出来的创意有偏差,请以建出来的为准</Title>}
                 <div className={style.content} style={{ marginTop: 20 }}>

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

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

+ 2 - 1
src/services/adqV3/global.ts

@@ -679,7 +679,8 @@ export async function getGameLibraryAppIdDetailApi(wxGameAppId: number) {
  * @returns 
  */
 export async function getBarrageRecommendListApi(params: { adAccountId?: number, taskType?: 'GAME' | 'NOVEL' }) {
-    return request(api + `/adq/v3/launch/tools//creative/tools/barrage`, {
+    // return request(api + `/adq/v3/launch/tools/creative/tools/barrage`, {
+    return request(api + `/adq/v3/launch/tools/creative/tools/barrageRecommend`, {
         method: 'GET',
         params
     })