Parcourir la source

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

wjx il y a 10 mois
Parent
commit
57eae5f8bc
27 fichiers modifiés avec 715 ajouts et 225 suppressions
  1. 46 0
      src/pages/launchSystemNew/account/components/openV3All.tsx
  2. 23 1
      src/pages/launchSystemNew/account/game/tableConfig.tsx
  3. 24 2
      src/pages/launchSystemNew/account/novel/tableConfig.tsx
  4. 20 1
      src/pages/launchSystemV3/adqv3/ad/index.tsx
  5. 3 3
      src/pages/launchSystemV3/adqv3/ad/tableConfig.tsx
  6. 26 26
      src/pages/launchSystemV3/components/GoodsModal/index.tsx
  7. 212 68
      src/pages/launchSystemV3/components/PageModal/index.tsx
  8. 5 31
      src/pages/launchSystemV3/components/PageModal/tableConfig.tsx
  9. 16 0
      src/pages/launchSystemV3/tencentAdPutIn/const.ts
  10. 2 2
      src/pages/launchSystemV3/tencentAdPutIn/create/Ad/adgroupsAdSetting.tsx
  11. 7 7
      src/pages/launchSystemV3/tencentAdPutIn/create/Ad/adgroupsSitSet.tsx
  12. 7 14
      src/pages/launchSystemV3/tencentAdPutIn/create/Ad/newCreateAd.tsx
  13. 2 1
      src/pages/launchSystemV3/tencentAdPutIn/create/Dynamic/creativeTemplateContent.tsx
  14. 2 2
      src/pages/launchSystemV3/tencentAdPutIn/create/Dynamic/creativeTemplateSetup.tsx
  15. 5 5
      src/pages/launchSystemV3/tencentAdPutIn/create/Dynamic/index.tsx
  16. 4 4
      src/pages/launchSystemV3/tencentAdPutIn/create/Dynamic/newDynamic.tsx
  17. 1 1
      src/pages/launchSystemV3/tencentAdPutIn/create/MaterialText/index.tsx
  18. 67 38
      src/pages/launchSystemV3/tencentAdPutIn/create/MaterialText/newText.tsx
  19. 2 1
      src/pages/launchSystemV3/tencentAdPutIn/create/PageList/index.tsx
  20. 99 0
      src/pages/launchSystemV3/tencentAdPutIn/create/addDynamic.tsx
  21. 7 2
      src/pages/launchSystemV3/tencentAdPutIn/create/index.less
  22. 54 11
      src/pages/launchSystemV3/tencentAdPutIn/create/index.tsx
  23. 0 1
      src/pages/launchSystemV3/tencentAdPutIn/create/tableConfig.tsx
  24. 18 2
      src/pages/launchSystemV3/tencentAdPutIn/index.less
  25. 9 0
      src/pages/launchSystemV3/tencentAdPutIn/typings.d.ts
  26. 31 2
      src/services/adqV3/global.ts
  27. 23 0
      src/services/launchAdq/adq.ts

+ 46 - 0
src/pages/launchSystemNew/account/components/openV3All.tsx

@@ -0,0 +1,46 @@
+import { useAjax } from "@/Hook/useAjax"
+import { authSyncApi, openAllV3Api } from "@/services/launchAdq/adq"
+import { LoadingOutlined, SyncOutlined } from "@ant-design/icons"
+import { Button, Space, Tooltip, message } from "antd"
+import React from "react"
+
+
+interface Props {
+    accountId: any
+    onChange?: () => void
+}
+const OpenV3All: React.FC<Props> = ({ accountId, onChange }) => {
+
+    /*************************************/
+    const openAllV3a = useAjax((params) => openAllV3Api(params), { formatResult: true })
+    const authSync = useAjax((params) => authSyncApi(params), { formatResult: true })
+    /*************************************/
+
+    const openAllV3 = () => {
+        openAllV3a.run(accountId).then(res => {
+            if (res?.data) {
+                message.success('开启成功')
+                onChange?.()
+            }
+        })
+    }
+    const asyncAllV3 = () => {
+        authSync.run({ accountId }).then(res => {
+            if (res?.data) {
+                message.success('刷新成功')
+                onChange?.()
+            }
+        })
+    }
+
+    return <Space>
+        <Tooltip title="广告业务单元广告主账号同步">
+            <Button size="small" style={{ color: "#0eb83a" }} onClick={openAllV3}>{openAllV3a.loading ? <LoadingOutlined /> : <span>全3.0</span>}</Button>
+        </Tooltip>
+        <Tooltip title="广告业务单元广告主账号全量转3.0">
+            <Button size="small" style={{ color: "#ea5506" }} onClick={asyncAllV3} loading={authSync.loading} icon={<SyncOutlined />}></Button>
+        </Tooltip>
+    </Space>
+}
+
+export default React.memo(OpenV3All)

+ 23 - 1
src/pages/launchSystemNew/account/game/tableConfig.tsx

@@ -5,6 +5,7 @@ import React from "react"
 import DivideIntoGroups from "./divideIntoGroups"
 import './index.less'
 import OpenV3 from "../components/openV3"
+import OpenV3All from "../components/openV3All"
 export function columnsMp(
     edit: (params: any) => void,
     setOpenServer: (data: any) => void,
@@ -45,6 +46,26 @@ export function columnsMp(
                 return <span>{a == 0 ? '微信' : 'QQ'}</span>
             }
         },
+        {
+            title: '是否业务单元账号',
+            dataIndex: 'adUnitAccount',
+            key: 'adUnitAccount',
+            align: 'center',
+            width: 75,
+            render: (a: boolean) => {
+                return <span>{a ? '是' : '否'}</span>
+            }
+        },
+        {
+            title: '业务单元账号ID',
+            dataIndex: 'adUnitAccountId',
+            key: 'adUnitAccountId',
+            align: 'center',
+            width: 75,
+            render: (a: any) => {
+                return <span>{a || '--'}</span>
+            }
+        },
         {
             title: '投手',
             dataIndex: 'putUserInfo',
@@ -195,11 +216,12 @@ export function columnsMp(
             title: '操作',
             dataIndex: 'cz',
             key: 'cz',
-            width: 250,
+            width: 300,
             fixed: 'right',
             render: (a: any, b: any) => {
                 return <Space>
                     {(Object.keys(b)?.includes('addV3') && !b.addV3) && <OpenV3 accountId={b?.accountId} onChange={v3Change} />}
+                    {b?.adUnitAccount && <OpenV3All accountId={b?.accountId} onChange={v3Change} />}
                     <Tooltip title="配置服务商">
                         <Button size="small" style={{ color: "#00bcd4" }} onClick={() => setOpenServer([b])} icon={<SettingOutlined />}></Button>
                     </Tooltip>

+ 24 - 2
src/pages/launchSystemNew/account/novel/tableConfig.tsx

@@ -5,6 +5,7 @@ import React from "react"
 import DivideIntoGroups from "./divideIntoGroups"
 import './index.less'
 import OpenV3 from "../components/openV3"
+import OpenV3All from "../components/openV3All"
 export function columnsMp(
     edit: (params: any) => void,
     setOpenServer: (data: any) => void,
@@ -45,6 +46,26 @@ export function columnsMp(
                 return <span>{a == 0 ? '微信' : 'QQ'}</span>
             }
         },
+        {
+            title: '是否业务单元账号',
+            dataIndex: 'adUnitAccount',
+            key: 'adUnitAccount',
+            align: 'center',
+            width: 75,
+            render: (a: boolean) => {
+                return <span>{a ? '是' : '否'}</span>
+            }
+        },
+        {
+            title: '业务单元账号ID',
+            dataIndex: 'adUnitAccountId',
+            key: 'adUnitAccountId',
+            align: 'center',
+            width: 75,
+            render: (a: any) => {
+                return <span>{a || '--'}</span>
+            }
+        },
         {
             title: '投手',
             dataIndex: 'putUserInfo',
@@ -195,11 +216,12 @@ export function columnsMp(
             title: '操作',
             dataIndex: 'cz',
             key: 'cz',
-            width: 250,
+            width: 300,
             fixed: 'right',
             render: (a: any, b: any) => {
                 return <Space>
-                    {(Object.keys(b)?.includes('addV3') && !b.addV3) && <OpenV3 accountId={b?.accountId} onChange={v3Change} />}
+                    {(Object.keys(b)?.includes('addV3') && !b.addV3 && !b?.adUnitAccount) && <OpenV3 accountId={b?.accountId} onChange={v3Change} />}
+                    {b?.adUnitAccount && <OpenV3All accountId={b?.accountId} onChange={v3Change} />}
                     <Tooltip title="配置服务商">
                         <Button size="small" style={{ color: "#00bcd4" }} onClick={() => setOpenServer([b])} icon={<SettingOutlined />}></Button>
                     </Tooltip>

+ 20 - 1
src/pages/launchSystemV3/adqv3/ad/index.tsx

@@ -1,5 +1,5 @@
 import { useAjax } from "@/Hook/useAjax";
-import { PauseCircleOutlined, PlayCircleOutlined, QuestionCircleOutlined, TransactionOutlined } from "@ant-design/icons";
+import { PauseCircleOutlined, PlayCircleOutlined, PlusOutlined, QuestionCircleOutlined, TransactionOutlined } from "@ant-design/icons";
 import { Button, Checkbox, Col, Input, Row, Select, Space, Tooltip, message } from "antd"
 import React, { useCallback, useEffect, useState } from "react"
 import { ADGROUP_STATUS } from "../const";
@@ -8,6 +8,7 @@ import tableConfig from "./tableConfig";
 import { txAdConfig } from "../config";
 import UpdateAd from "./updateAd";
 import TableData from "@/pages/launchSystemNew/components/TableData";
+import AddDynamic from "../../tencentAdPutIn/create/addDynamic";
 
 
 const Ad: React.FC<ADQV3.AdProps> = ({ userId, creativeHandle }) => {
@@ -17,6 +18,7 @@ const Ad: React.FC<ADQV3.AdProps> = ({ userId, creativeHandle }) => {
     const [isClearSelect, setIsClearSelect] = useState(true)
     const [selectedRows, setSelectedRows] = useState<any[]>([])
     const [update, setUpdate] = useState<{ visible: boolean }>({ visible: false })
+    const [addDynamicVisible, setAddDynamicVisible] = useState<boolean>(false)
 
     const syncBatch = useAjax((params) => syncBatchApi(params))
     const modifyStatusBatch = useAjax((params) => modifyStatusBatchApi(params))
@@ -66,6 +68,10 @@ const Ad: React.FC<ADQV3.AdProps> = ({ userId, creativeHandle }) => {
         })
     }
 
+    // 添加创意
+    const addDynamic = () => {
+        setAddDynamicVisible(true)
+    }
 
     return <div>
         <Row gutter={[6, 6]} align='middle' style={{ marginBottom: 15 }}>
@@ -227,6 +233,7 @@ const Ad: React.FC<ADQV3.AdProps> = ({ userId, creativeHandle }) => {
                     <Col><Button type='primary' style={{ background: '#67c23a', borderColor: '#67c23a' }} loading={modifyStatusBatch.loading} icon={<PlayCircleOutlined />} disabled={selectedRows.length === 0} onClick={() => adStatus(true)}>启动</Button></Col>
                     <Col><Button type='primary' style={{ background: '#e6a23c', borderColor: '#e6a23c' }} loading={modifyStatusBatch.loading} icon={<PauseCircleOutlined />} disabled={selectedRows.length === 0} onClick={() => adStatus(false)}>暂停</Button></Col>
                     <Col><Button type='primary' icon={<TransactionOutlined />} disabled={selectedRows.length === 0} onClick={() => setUpdate({ visible: true })}>修改出价</Button></Col>
+                    {/* <Col><Button type='primary' icon={<PlusOutlined />} disabled={selectedRows.length === 0} onClick={addDynamic}>添加创意</Button></Col> */}
                 </Row>
             </Space>}
             rowSelection={{
@@ -285,6 +292,18 @@ const Ad: React.FC<ADQV3.AdProps> = ({ userId, creativeHandle }) => {
             }}
             onClose={() => { setUpdate({ visible: false }) }}
         />}
+
+        {/* 新增创意 */}
+        {addDynamicVisible && <AddDynamic
+            adData={selectedRows}
+            visible={addDynamicVisible}
+            onClose={() => {
+                setAddDynamicVisible(false)
+            }}
+            onChange={() => {
+
+            }}
+        />}
     </div>
 }
 

+ 3 - 3
src/pages/launchSystemV3/adqv3/ad/tableConfig.tsx

@@ -1,4 +1,4 @@
-import { BidModeEnum, BidStrategyEnum, OptimizationGoalEnum } from '@/services/launchAdq/enum'
+import { BidStrategyEnum } from '@/services/launchAdq/enum'
 import React from 'react'
 import { Badge, Space } from 'antd'
 import '../index.less'
@@ -6,8 +6,8 @@ import { copy } from '@/utils/utils'
 import { ADGROUP_STATUS } from '../const'
 import SwitchStatus from './switchStatus'
 import TimeSeriesLook from '@/pages/launchSystemNew/adq/ad/timeSeriesLook'
-import BoxOther from '../creative/boxOther'
 import CreativePreview from '../../adMonitorListV3/CreativePreview'
+import { BID_MODE_ENUM, OPTIMIZATIONGOAL_ENUM } from '../../tencentAdPutIn/const'
 function tableConfig(onChange: () => void, creativeHandle?: (id: number) => void): any {
     return [
         {
@@ -123,7 +123,7 @@ function tableConfig(onChange: () => void, creativeHandle?: (id: number) => void
             width: 140,
             ellipsis: true,
             render: (a: string, b: { bidMode: string, optimizationGoal: string }) => {
-                return `${BidModeEnum[b?.bidMode]} ${a}元/${b?.bidMode === 'BID_MODE_CPM' ? '千次曝光' : b?.bidMode === 'BID_MODE_CPC' ? '点击' : OptimizationGoalEnum[b?.optimizationGoal]}`
+                return `${BID_MODE_ENUM[b?.bidMode]} ${a}元/${b?.bidMode === 'BID_MODE_CPM' ? '千次曝光' : b?.bidMode === 'BID_MODE_CPC' ? '点击' : OPTIMIZATIONGOAL_ENUM[b?.optimizationGoal]}`
             }
         },
         {

+ 26 - 26
src/pages/launchSystemV3/components/GoodsModal/index.tsx

@@ -4,7 +4,7 @@ import { Button, Input, message, Modal, Space, Table, Tooltip, Typography } from
 import React, { useEffect, useState } from "react"
 import style from './index.less'
 import columns from './tableConfig'
-import { getmarketingAssetContentApi, synMarketingAssetContentApi } from "@/services/adqV3/global"
+import { getByRemotemarketingAssetContentApi } from "@/services/adqV3/global"
 const { Title, Text } = Typography;
 
 /**
@@ -29,17 +29,17 @@ const GoodsModal: React.FC<Props> = (props) => {
         pageNum: number,
         pageSize: number,
         accountId?: number
-    }>({ pageNum: 1, pageSize: 50 })
+    }>({ pageNum: 1, pageSize: 10 })
 
-    const getmarketingAssetContent = useAjax((params) => getmarketingAssetContentApi(params))
-    const synMarketingAssetContent = useAjax((params) => synMarketingAssetContentApi(params))
+    const getByRemotemarketingAssetContent = useAjax((params) => getByRemotemarketingAssetContentApi(params))
+    // const synMarketingAssetContent = useAjax((params) => synMarketingAssetContentApi(params))
     /************************/
 
     useEffect(() => {
         if (data?.length > 0) {
-            getList({ accountId: data[selectAdz - 1].accountId, pageNum: 1, pageSize: 50 })
+            getList({ accountId: data[selectAdz - 1].accountId, pageNum: 1, pageSize: 10 })
         } else {
-            getmarketingAssetContent.data && getmarketingAssetContent.mutate({ records: [] })
+            getByRemotemarketingAssetContent.data && getByRemotemarketingAssetContent.mutate({ records: [] })
         }
     }, [selectAdz])
 
@@ -52,7 +52,7 @@ const GoodsModal: React.FC<Props> = (props) => {
         accountId?: number
     }) => {
         setQueryForm(data)
-        getmarketingAssetContent.run(data)
+        getByRemotemarketingAssetContent.run(data)
     }
 
     const handleOk = () => {
@@ -60,13 +60,13 @@ const GoodsModal: React.FC<Props> = (props) => {
     }
 
     // 同步小说
-    const synGoodsList = () => {
-        synMarketingAssetContent.run({ accountId: data[selectAdz - 1].accountId }).then(res => {
-            if (res) {
-                message.success('同步成功,结果可能几分钟后展示,请勿重复点击同步')
-            }
-        })
-    }
+    // const synGoodsList = () => {
+    //     synMarketingAssetContent.run({ accountId: data[selectAdz - 1].accountId }).then(res => {
+    //         if (res) {
+    //             message.success('同步成功,结果可能几分钟后展示,请勿重复点击同步')
+    //         }
+    //     })
+    // }
 
     /** 设置选中广告主 */
     const handleSelectAdz = (value: number) => {
@@ -98,7 +98,7 @@ const GoodsModal: React.FC<Props> = (props) => {
             message.success('设置成功');
         });
         let dataAjax = newData?.filter(item => item.accountId !== data[selectAdz - 1].accountId)?.map(item => item?.accountId).map(accountId => {
-            return getmarketingAssetContentApi({ pageNum: 1, pageSize: 100, accountId: accountId, marketingAssetNameList })
+            return getByRemotemarketingAssetContentApi({ pageNum: 1, pageSize: 5, accountId: accountId, marketingAssetNameList })
         })
         Promise.all(dataAjax).then(res => {
             if (res?.length > 0) {
@@ -127,7 +127,7 @@ const GoodsModal: React.FC<Props> = (props) => {
     return <Modal
         title={<Space>
             <strong>产品库</strong>
-            <Button size="small" style={{ padding: 0 }} onClick={() => { synGoodsList() }} type="link" loading={synMarketingAssetContent?.loading}>同步小说</Button>
+            {/* <Button size="small" style={{ padding: 0 }} onClick={() => { synGoodsList() }} type="link" loading={synMarketingAssetContent?.loading}>同步小说</Button> */}
         </Space>}
         visible={visible}
         onCancel={() => { onClose && onClose() }}
@@ -151,9 +151,9 @@ const GoodsModal: React.FC<Props> = (props) => {
             </div>
             <div className={style.right}>
                 <Space style={{ marginBottom: 10 }} align="end" size={0}>
-                    <Input allowClear placeholder="请输入商品名称" value={queryForm.marketingAssetName} onChange={(e) => getList({ ...queryForm, marketingAssetName: e.target.value, pageNum: 1 })} />
-                    <Button icon={<SyncOutlined />} type='link' loading={getmarketingAssetContent?.loading} onClick={() => { getList({ ...queryForm, accountId: data[selectAdz - 1].accountId }) }}>刷新</Button>
-                    {data?.length > 1 && <Button disabled={!data[selectAdz - 1]['productList']?.length} onClick={setOnekey} type="link" loading={getmarketingAssetContent.loading}>
+                    <Input.Search enterButton allowClear placeholder="请输入商品名称" onSearch={(value) => getList({ ...queryForm, marketingAssetName: value, pageNum: 1 })} />
+                    <Button icon={<SyncOutlined />} type='link' loading={getByRemotemarketingAssetContent?.loading} onClick={() => { getList({ ...queryForm, accountId: data[selectAdz - 1].accountId }) }}>刷新</Button>
+                    {data?.length > 1 && <Button disabled={!data[selectAdz - 1]['productList']?.length} onClick={setOnekey} type="link" loading={getByRemotemarketingAssetContent.loading}>
                         <Space>
                             <span>一键设置</span>
                             <Tooltip color="#FFF" overlayInnerStyle={{ color: '#000' }} title="设置其它账号有相同名称的商品为那个账号的商品(注意需要用户商品称相同,否则不设置)">
@@ -165,16 +165,16 @@ const GoodsModal: React.FC<Props> = (props) => {
                 </Space>
                 <Table
                     columns={columns()}
-                    dataSource={getmarketingAssetContent.data?.records}
+                    dataSource={getByRemotemarketingAssetContent.data?.records}
                     size="small"
-                    loading={getmarketingAssetContent?.loading}
+                    loading={getByRemotemarketingAssetContent?.loading}
                     scroll={{ y: 400 }}
                     bordered
                     pagination={{
                         defaultPageSize: 100,
-                        current: getmarketingAssetContent.data?.current || 1,
-                        pageSize: getmarketingAssetContent.data?.size || 50,
-                        total: getmarketingAssetContent.data?.total || 0
+                        current: getByRemotemarketingAssetContent.data?.current || 1,
+                        pageSize: getByRemotemarketingAssetContent.data?.size || 10,
+                        total: getByRemotemarketingAssetContent.data?.total || 0
                     }}
                     rowKey={'marketingAssetId'}
                     rowSelection={{
@@ -184,7 +184,7 @@ const GoodsModal: React.FC<Props> = (props) => {
                     }}
                     onChange={(pagination) => {
                         const { current, pageSize } = pagination
-                        getList({ ...queryForm, pageNum: current || 1, pageSize: pageSize || 50 })
+                        getList({ ...queryForm, pageNum: current || 1, pageSize: pageSize || 10 })
                     }}
                 />
             </div>
@@ -197,7 +197,7 @@ const GoodsModal: React.FC<Props> = (props) => {
                             let newData: PULLIN.AccountCreateLogsProps[] = JSON.parse(JSON.stringify(data))
                             newData[selectAdz - 1].productList = newData[selectAdz - 1]?.productList?.filter((i: any) => i?.marketingAssetId !== item.marketingAssetId)
                             setData(newData)
-                        }}/>
+                        }} />
                     </div>)}
                 </div>
             </div>

+ 212 - 68
src/pages/launchSystemV3/components/PageModal/index.tsx

@@ -1,13 +1,13 @@
 
-import Tables from "@/components/Tables"
 import { useAjax } from "@/Hook/useAjax"
-import { CheckOutlined, QuestionCircleOutlined, SyncOutlined } from "@ant-design/icons"
-import { Button, Input, message, Modal, Space, Tooltip } from "antd"
+import { CheckOutlined, CloseOutlined, SyncOutlined } from "@ant-design/icons"
+import { Button, Checkbox, Input, message, Modal, Select, Space, Table, Typography } from "antd"
 import React, { useEffect, useState } from "react"
 import style from '../GoodsModal/index.less'
 import columns from "./tableConfig"
-import { getAdqLandingPageListApi, putAdqLandingPageApi } from "@/services/adqV3/global"
-
+import { getAdqLandingPageListApi, getWXDownPageAuthInfoListApi } from "@/services/adqV3/global"
+import { OPTION_ENUM } from "../../tencentAdPutIn/const"
+const { Title, Text } = Typography;
 
 /**
  * 获取adq落地页
@@ -18,17 +18,30 @@ interface Props {
     onClose?: () => void,
     onChange?: (data: PULLIN.AccountCreateLogsProps[]) => void,
     adgroups: any
+    dynamic: any
     data: PULLIN.AccountCreateLogsProps[]
 }
 const PageModal: React.FC<Props> = (props) => {
 
     /*************************/
-    const { visible, onClose, data: data1, adgroups, onChange } = props
+    const { visible, onClose, data: data1, adgroups, onChange, dynamic } = props
     const { marketingGoal, marketingAssetOuterSpec: { marketingTargetType }, marketingCarrierType, siteSet } = adgroups
+    const { creativeTemplateId, creativeComponents: { mainJumpInfo } } = dynamic
+    let overrideCanvasHeadOption = ''
+    if (mainJumpInfo && mainJumpInfo?.length > 0) {
+        mainJumpInfo.forEach((item: any) => {
+            let { pageSpec } = item.value
+            let key = Object.keys(pageSpec)[0]
+            let pageSpecValue = pageSpec[key]
+            overrideCanvasHeadOption = pageSpecValue.overrideCanvasHeadOption
+        })
+    }
     const [selectAdz, setSelectAdz] = useState<number>(1)   // 选择广告主
     const [data, setData] = useState<PULLIN.AccountCreateLogsProps[]>(data1 || [])
-    const [queryForm, setQueryForm] = useState<{ accountId?: number, pageName?: string, pageSize: number, pageNum: number }>({ pageNum: 1, pageSize: 20 })
+    const [queryForm, setQueryForm] = useState<{ accountId?: number, pageName?: string, ownerUid?: number, pageSize: number, pageNum: number, isSqDownPage: boolean, isCanvasType?: boolean }>({ pageNum: 1, pageSize: 20, isSqDownPage: false })
     const [loading, setLoading] = useState<boolean>(false)
+    const [wXDownPageAuthInfo, setWXDownPageAuthInfo] = useState<any>({})
+    const [tableData, setTableData] = useState<any>({})
 
     const listAjax = useAjax((params) => getAdqLandingPageListApi(params))
     /*************************/
@@ -37,17 +50,49 @@ const PageModal: React.FC<Props> = (props) => {
         if (data?.length > 0) {
             setQueryForm({ ...queryForm, pageNum: 1, accountId: data[selectAdz - 1].accountId })
         }
-    }, [selectAdz])
+    }, [])
+
+    useEffect(() => {
+        if (data?.length > 0) {
+            setLoading(true)
+            let accountDataList = data.map(item => item.accountId)
+            let infoAjax = accountDataList.map(accountId => getWXDownPageAuthInfoListApi(accountId))
+            let newData: any = {}
+            Promise.all(infoAjax).then(res => {
+                res?.forEach((item, index) => {
+                    newData[accountDataList[index]] = item?.data || []
+                })
+                setWXDownPageAuthInfo(newData)
+                setLoading(false)
+            }).catch(() => setLoading(false))
+        }
+    }, [])
 
     useEffect(() => {
         if (queryForm?.accountId) {
             getList()
         }
-    }, [queryForm, marketingGoal, marketingTargetType, marketingCarrierType, siteSet])
+    }, [queryForm, marketingGoal, marketingTargetType, marketingCarrierType, siteSet, mainJumpInfo])
 
     // 获取落地页列表
     const getList = () => {
-        listAjax.run({ ...queryForm, pageStatus: 'NORMAL', marketingGoal, marketingTargetType, marketingCarrierType, siteSet })
+        let params: any = { ...queryForm, pageStatus: 'NORMAL', marketingGoal, marketingTargetType, marketingCarrierType, siteSet }
+        if (params.isSqDownPage) {
+            if (!params?.ownerUid) {
+                setTableData({ total: 0, records: [] })
+                return
+            }
+        } else {
+            delete params?.ownerUid
+        }
+        if (params?.isCanvasType) {
+            params.canvasType = 'CANVAS_TYPE_COMMON_PAGE'
+        }
+        delete params?.isCanvasType
+        delete params.isSqDownPage
+        listAjax.run(params).then(res => {
+            setTableData(res || {})
+        })
     }
 
     const handleOk = () => {
@@ -63,61 +108,53 @@ const PageModal: React.FC<Props> = (props) => {
         if (value === selectAdz) {
             return
         }
+        let accountId = data[value - 1].accountId
+        setQueryForm({ ...queryForm, pageNum: 1, accountId, ownerUid: wXDownPageAuthInfo[accountId]?.[0]?.accountId })
         setSelectAdz(value)
     }
 
     /** 表格选折 */
-    const onChangeTable = (selectedRowKeys: React.Key[], selectedRows: any) => {
+    const onChangeTable = (_: React.Key[], selectedRows: any) => {
         let newData = JSON.parse(JSON.stringify(data))
         newData[selectAdz - 1]['pageList'] = selectedRows
         setData([...newData])
     }
 
-    /** 同步落地页 */
-    const synPageList = () => {
-        setLoading(true)
-        putAdqLandingPageApi({ accountIdList: data?.map(item => item.accountId), isUsePool: false }).then(res => {
-            message.success('同步成功,结果可能需要几分钟返回,请手动点击下面刷新按钮')
-            setLoading(false)
-            listAjax.refresh()
-        }).catch(() => setLoading(false))
-    }
-
     /** 一键设置 */
-    const setOnekey = () => {
-        let pageName: string = data[selectAdz - 1]['pageList']?.[0]?.pageName
-        let newData: PULLIN.AccountCreateLogsProps[] = JSON.parse(JSON.stringify(data))
-        const hide = message.loading(`正在设置...`, 0, () => {
-            message.success('设置成功');
-        });
-        let ajax = newData?.filter(item => item.accountId !== data[selectAdz - 1].accountId)?.map(item => {
-            return getAdqLandingPageListApi({ pageName, accountId: item.accountId, pageNum: 1, pageSize: 20, pageStatus: 'NORMAL' })
-        })
-        Promise.all(ajax).then(res => {
-            if (res && Array.isArray(res)) {
-                res.forEach((item: any) => {
-                    let records = item?.data?.records
-                    if (Array.isArray(records) && records?.length > 0) {
-                        let record = records[0]
-                        newData = newData.map(item => {
-                            if (item.accountId.toString() === record.accountId.toString()) {
-                                return { ...item, pageList: [{ ...record, id: record.pageId }] }
-                            }
-                            return item
-                        })
-                    }
-                })
-                setData(newData)
-            }
-            message.success('设置完成');
-            hide()
-        })
-    }
+    // const setOnekey = () => {
+    //     let pageName: string = data[selectAdz - 1]['pageList']?.[0]?.pageName
+    //     let newData: PULLIN.AccountCreateLogsProps[] = JSON.parse(JSON.stringify(data))
+    //     const hide = message.loading(`正在设置...`, 0, () => {
+    //         message.success('设置成功');
+    //     });
+    //     let ajax = newData?.filter(item => item.accountId !== data[selectAdz - 1].accountId)?.map(item => {
+    //         return getAdqLandingPageListApi({ pageName, accountId: item.accountId, pageNum: 1, pageSize: 20, pageStatus: 'NORMAL' })
+    //     })
+    //     Promise.all(ajax).then(res => {
+    //         if (res && Array.isArray(res)) {
+    //             res.forEach((item: any) => {
+    //                 let records = item?.data?.records
+    //                 if (Array.isArray(records) && records?.length > 0) {
+    //                     let record = records[0]
+    //                     newData = newData.map(item => {
+    //                         if (item.accountId.toString() === record.accountId.toString()) {
+    //                             return { ...item, pageList: [{ ...record, id: record.pageId }] }
+    //                         }
+    //                         return item
+    //                     })
+    //                 }
+    //             })
+    //             setData(newData)
+    //         }
+    //         message.success('设置完成');
+    //         hide()
+    //     })
+    // }
 
     return <Modal
         title={<Space>
             <span>ADQ落地页</span>
-            <Button size="small" onClick={() => { synPageList() }} type="link" loading={loading}>同步落地页</Button>
+            <Text type="warning">{OPTION_ENUM[overrideCanvasHeadOption]}</Text>
         </Space>}
         visible={visible}
         onCancel={() => { onClose && onClose() }}
@@ -131,46 +168,153 @@ const PageModal: React.FC<Props> = (props) => {
             <div className={style.left}>
                 <h4 className={style.title}>媒体账户</h4>
                 {data?.map((item, index) => (
-                    <div key={index} onClick={() => { handleSelectAdz(index + 1, item) }} className={`${style.accItem} ${selectAdz === index + 1 && style.select} `}>
+                    <div key={index} onClick={() => { if (!loading) handleSelectAdz(index + 1, item) }} className={`${style.accItem} ${selectAdz === index + 1 && style.select} `}>
                         {item?.accountId}
                         {data[index].pageList?.length > 0 && <CheckOutlined style={{ color: '#1890ff' }} />}
                     </div>
                 ))}
             </div>
             <div className={style.right}>
-                <Space style={{ marginBottom: 10 }} align="end" size={0}>
-                    <Input value={queryForm?.pageName} allowClear placeholder='请输入落地页名称' onChange={(e) => setQueryForm({ ...queryForm, pageNum: 1, pageName: e.target.value })} />
-                    <Button icon={<SyncOutlined />} type='link' loading={listAjax?.loading} onClick={() => { listAjax?.refresh() }}>刷新</Button>
-                    {data?.length > 1 && <Button disabled={!data[selectAdz - 1]['pageList']?.length} onClick={setOnekey} type="link" loading={listAjax.loading}>
+                <Space style={{ marginBottom: 10 }}>
+                    <Checkbox
+                        onChange={(e) => {
+                            setQueryForm({ ...queryForm, pageNum: 1, isCanvasType: e.target.checked })
+                        }}
+                        checked={queryForm.isCanvasType}
+                    ><span style={{ fontSize: 12 }}>展示外换内组件原生页</span></Checkbox>
+                    <Checkbox
+                        onChange={(e) => {
+                            if (e.target.checked && wXDownPageAuthInfo && Object.keys(wXDownPageAuthInfo).length) {
+                                setQueryForm({ ...queryForm, pageNum: 1, ownerUid: wXDownPageAuthInfo[data[selectAdz - 1].accountId]?.[0]?.accountId, isSqDownPage: true })
+                            } else {
+                                setQueryForm({ ...queryForm, pageNum: 1, ownerUid: undefined, isSqDownPage: false })
+                            }
+                        }}
+                        checked={queryForm.isSqDownPage}
+                    ><span style={{ fontSize: 12 }}>被授权落地页</span></Checkbox>
+                    {queryForm.isSqDownPage && <Select
+                        placeholder='选择原生页授权方信息'
+                        style={{ width: 200 }}
+                        showSearch
+                        filterOption={(input: any, option: any) =>
+                            (option!.children as unknown as string).toLowerCase().includes(input.toLowerCase())
+                        }
+                        allowClear
+                        onChange={(value) => {
+                            setQueryForm({ ...queryForm, pageNum: 1, ownerUid: value })
+                        }}
+                        value={queryForm?.ownerUid}
+                        dropdownMatchSelectWidth={false}
+                    >
+                        {wXDownPageAuthInfo?.[data[selectAdz - 1].accountId]?.map((item: { accountId: number; accountName: string }) => {
+                            return <Select.Option value={item.accountId} key={item.accountId}>{item.accountName}</Select.Option>
+                        })}
+                    </Select>}
+                    <Input value={queryForm?.pageName} style={{ width: 150 }} allowClear placeholder='请输入落地页名称' onChange={(e) => setQueryForm({ ...queryForm, pageNum: 1, pageName: e.target.value })} />
+                    <Button style={{ padding: 0, margin: 0 }} icon={<SyncOutlined />} type='link' loading={listAjax?.loading} onClick={() => { listAjax?.refresh() }}>刷新</Button>
+                    {/* {data?.length > 1 && <Button style={{ padding: 0, margin: 0 }} disabled={!data[selectAdz - 1]['pageList']?.length} onClick={setOnekey} type="link" loading={listAjax.loading}>
                         <Space>
                             <span>一键设置</span>
                             <Tooltip color="#FFF" overlayInnerStyle={{ color: '#000' }} title="设置其它账号有相同名称的落地页为那个账号的落地页(注意需要落地页名称相同,否则不设置)">
                                 <QuestionCircleOutlined />
                             </Tooltip>
                         </Space>
-                    </Button>}
+                    </Button>} */}
                 </Space>
-                <Tables
+                <Table
                     columns={columns()}
-                    dataSource={listAjax?.data?.records?.map((item: any) => ({ ...item, id: item.pageId }))}
+                    dataSource={tableData?.records}
                     size="small"
-                    loading={listAjax?.loading}
+                    loading={listAjax?.loading || loading}
                     scroll={{ y: 300 }}
                     bordered
-                    total={listAjax?.data?.total}
-                    defaultPageSize={20}
-                    current={listAjax?.data?.current}
-                    pageSize={listAjax?.data?.size}
-                    pageChange={(page: number, pageSize?: number) => {
-                        setQueryForm({ ...queryForm, pageNum: page, pageSize: pageSize as number || 20 })
+                    rowKey={'pageId'}
+                    pagination={{
+                        total: tableData?.total,
+                        defaultPageSize: 20,
+                        current: tableData?.current,
+                        pageSize: tableData?.size
+                    }}
+                    onChange={(pagination) => {
+                        const { current, pageSize } = pagination
+                        setQueryForm({ ...queryForm, pageNum: current as number, pageSize: pageSize as number || 20 })
                     }}
+                    /**
+                     * canvasType
+                     * VIDEO
+                     * VIDEO_1280_960  横板1280*960
+                     * VIDEO_1280_720  横板1280*720
+                     * VERTICAL_VIDEO_NEW_916 9:16 视频
+                     * COMMON_PAGE 引用外层素材原生页
+                     * IMAGE
+                     */
                     rowSelection={{
-                        type: 'radio',
-                        selectedRowKeys: data[selectAdz - 1]?.pageList?.map((item: any) => item?.id?.toString()),
+                        type: [910].includes(creativeTemplateId) ? 'checkbox' : 'radio',
+                        getCheckboxProps: (record) => {
+                            let { canvasType, pageElementsSpecList } = record
+                            let topData = pageElementsSpecList[0]
+                            /**
+                             * 641 三图 642 4图 643 6图 311 一图
+                             * 721 素板视频 9:16 -> VERTICAL_VIDEO_NEW_916  720 722 横板视频 -> VIDEO_1280_960
+                             * 618 常规视频 ---> VIDEO
+                             * 1708 1707 ---> false
+                             */
+                            if (overrideCanvasHeadOption === 'OPTION_CREATIVE_OVERRIDE_CANVAS' || [1708, 1707].includes(creativeTemplateId)) {
+                                return {
+                                    disabled: false
+                                }
+                            }
+                            if ([721].includes(creativeTemplateId) && canvasType === 'VERTICAL_VIDEO_NEW_916') {
+                                return {
+                                    disabled: false
+                                }
+                            } else if ([720, 722].includes(creativeTemplateId) && canvasType === 'VIDEO_1280_960') {
+                                return {
+                                    disabled: false
+                                }
+                            } else if ([618].includes(creativeTemplateId) && canvasType === 'VIDEO') {
+                                return {
+                                    disabled: false
+                                }
+                            } else if ([311].includes(creativeTemplateId) && canvasType === "IMAGE" && topData.imageSpec.length === 1) {
+                                return {
+                                    disabled: false
+                                }
+                            } else if ([641].includes(creativeTemplateId) && canvasType === "IMAGE" && topData.imageSpec.length === 3) {
+                                return {
+                                    disabled: false
+                                }
+                            } else if ([642].includes(creativeTemplateId) && canvasType === "IMAGE" && topData.imageSpec.length === 4) {
+                                return {
+                                    disabled: false
+                                }
+                            } else if ([643].includes(creativeTemplateId) && canvasType === "IMAGE" && topData.imageSpec.length === 6) {
+                                return {
+                                    disabled: false
+                                }
+                            }
+                            return {
+                                disabled: true
+                            }
+                        },
+                        selectedRowKeys: data[selectAdz - 1]?.pageList?.map((item: any) => item?.pageId),
                         onChange: onChangeTable
                     }}
                 />
             </div>
+            <div className={style.center}>
+                <Title level={5}>已选:{data[selectAdz - 1]?.pageList?.length || 0}</Title>
+                <div className={style.select_content}>
+                    {data[selectAdz - 1]?.pageList?.map((item: any) => <div key={item.pageId}>
+                        <Text ellipsis={{ tooltip: true }} className={style.marketingAssetName}>{item.pageName}</Text>
+                        <CloseOutlined className={style.close} onClick={() => {
+                            let newData: PULLIN.AccountCreateLogsProps[] = JSON.parse(JSON.stringify(data))
+                            newData[selectAdz - 1].pageList = newData[selectAdz - 1]?.pageList?.filter((i: any) => i?.pageId !== item.pageId)
+                            setData(newData)
+                        }} />
+                    </div>)}
+                </div>
+            </div>
         </div>
 
     </Modal>

+ 5 - 31
src/pages/launchSystemV3/components/PageModal/tableConfig.tsx

@@ -1,7 +1,8 @@
-import { PageStatusEnum, PageTypeEnum, SourceTypeEnum } from "@/services/launchAdq/enum"
-import { Badge } from "antd"
+import { PageStatusEnum } from "@/services/launchAdq/enum"
+import { Badge, TableProps } from "antd"
 import React from "react"
-let columns = () => [
+
+let columns = (): TableProps<any>['columns'] => [
     {
         title: '落地页ID',
         dataIndex: 'pageId',
@@ -18,16 +19,6 @@ let columns = () => [
         key: 'pageName',
         ellipsis: true
     },
-    {
-        title: '落地页类型',
-        dataIndex: 'pageType',
-        key: 'pageType',
-        align: 'center',
-        width: 120,
-        render: (a: string) => {
-            return PageTypeEnum[a]
-        }
-    },
     {
         title: '落地页状态',
         dataIndex: 'pageStatus',
@@ -37,24 +28,7 @@ let columns = () => [
         render: (a: string | number) => {
             return <Badge status={a === 'NORMAL' ? "processing" : "error"} text={PageStatusEnum[a]} />
         }
-    },
-    {
-        title: '配置来源',
-        dataIndex: 'sourceType',
-        key: 'sourceType',
-        align: 'center',
-        width: 130,
-        render: (a: any, b: any) => {
-            return SourceTypeEnum[a]
-        }
-    },
-    {
-        title: '创建时间',
-        dataIndex: 'createdTime',
-        key: 'createdTime',
-        align: 'center',
-        width: 145,
-    },
+    }
 ]
 
 export default columns

+ 16 - 0
src/pages/launchSystemV3/tencentAdPutIn/const.ts

@@ -514,4 +514,20 @@ export enum TEXT_LINK_TYPE_ENUM {
 	CONTACT_BUSINESS = "联系商家",
 	GO_SCAN = "扫一扫",
 	LINK_NAME_TEXT_TEMPLATE = "文字链模版"
+}
+
+/** 创意文案类型 */
+export const TextTypeList = [
+	{ label: '全部相同', value: 0 }, 
+	{ label: '按创意组一一对应', value: 1 },
+	{ label: '按文案顺序分配', value: 2 },
+	{ label: '根据文案叉乘', value: 3 },
+]
+
+/** 创意素材替换原生页顶部素材 */
+export enum OPTION_ENUM {
+	OPTION_CANVAS_OVERRIDE_CREATIVE = '原生页头部素材替换创意素材',
+	OPTION_CREATIVE_OVERRIDE_CANVAS = '创意素材替换原生页顶部素材',
+	OPTION_KEEP_DIFFERENT = '不替换替换原生页顶部素材',
+	OPTION_CREATIVE_OVERRIDE_CANVAS_DYNAMIC = '创意素材替换原生页顶部素材(由下游系统动态替换)'
 }

+ 2 - 2
src/pages/launchSystemV3/tencentAdPutIn/create/Ad/adgroupsAdSetting.tsx

@@ -111,7 +111,7 @@ const AdgroupsAdSetting: React.FC<{ value?: any }> = ({ value }) => {
                 },
                 {
                     required: true, message: '请确保广告名称长度不超过60个字(1个汉字等于2个字符)', validator(_, value) {
-                        if (value && txtLength(value) > 60) {
+                        if (value && txtLength(value) > 50) {
                             return Promise.reject()
                         }
                         return Promise.resolve()
@@ -119,7 +119,7 @@ const AdgroupsAdSetting: React.FC<{ value?: any }> = ({ value }) => {
                 }
             ]}
         >
-            <InputName placeholder='广告名称' style={{ width: 480 }} length={60} />
+            <InputName placeholder='广告名称' style={{ width: 480 }} length={50} />
         </Form.Item>
     </Card>
 }

+ 7 - 7
src/pages/launchSystemV3/tencentAdPutIn/create/Ad/adgroupsSitSet.tsx

@@ -122,7 +122,7 @@ const AdgroupsSitSet: React.FC = () => {
                         </Form.Item>
                     </div>
                     {wechatPositionType === '1' && <div className={style.newSpace_bottom}>
-                        <Form.Item name='wechatPosition'>
+                        <Form.Item name={['sceneSpec', 'wechatPosition']}>
                             <Checkbox.Group options={sceneTagsList?.data?.WECHAT_POSITION?.map((item: { description: any; id: any; }) => ({ label: item.description, value: item.id }))} />
                         </Form.Item>
                     </div>}
@@ -139,7 +139,7 @@ const AdgroupsSitSet: React.FC = () => {
                         </Form.Item>
                     </div>
                     {wechatChannelsSceneType === '1' && <div className={style.newSpace_bottom}>
-                        <Form.Item name='wechatChannelsScene' rules={[{ required: true, message: '请选择!' }]}>
+                        <Form.Item name={['sceneSpec', 'wechatChannelsScene']} rules={[{ required: true, message: '请选择!' }]}>
                             <Checkbox.Group options={sceneTagsList?.data?.WECHAT_CHANNELS_SCENE?.map((item: { description: any; id: any; }) => ({ label: item.description, value: item.id }))} />
                         </Form.Item>
                     </div>}
@@ -169,7 +169,7 @@ const AdgroupsSitSet: React.FC = () => {
                     {wechatSceneType === '1' && <div className={style.newSpace_bottom}>
                         <p style={{ marginBottom: 5 }}><strong style={{ marginRight: 20 }}>公众号媒体类型</strong></p>
                         <Form.Item
-                            name={['wechatScene', 'officialAccountMediaCategory']}
+                            name={['sceneSpec', 'wechatScene', 'officialAccountMediaCategory']}
                             rules={[{ required: true, message: '请选择!' }]}
                             getValueFromEvent={(e: number[]) => {
                                 if (e.length > 1 && !officialAccountMediaCategory?.includes(noLimitOAMC) && noLimitOAMC && e.includes(noLimitOAMC)) {
@@ -190,7 +190,7 @@ const AdgroupsSitSet: React.FC = () => {
                         </Form.Item>
                         <p style={{ marginBottom: 5 }}><strong style={{ marginRight: 20 }}>小程序小游戏流量类型</strong></p>
                         <Form.Item
-                            name={['wechatScene', 'miniProgramAndMiniGame']}
+                            name={['sceneSpec', 'wechatScene', 'miniProgramAndMiniGame']}
                             rules={[{ required: true, message: '请选择!' }]}
                             getValueFromEvent={(e: number[]) => {
                                 if (e.length > 1 && !miniProgramAndMiniGame?.includes(noLimitMPAMG) && noLimitMPAMG && e.includes(noLimitMPAMG)) {
@@ -211,7 +211,7 @@ const AdgroupsSitSet: React.FC = () => {
                         </Form.Item>
                         <p style={{ marginBottom: 5 }}><strong style={{ marginRight: 20 }}>订单详情页消费场景</strong></p>
                         <Form.Item
-                            name={['wechatScene', 'payScene']}
+                            name={['sceneSpec', 'wechatScene', 'payScene']}
                             rules={[{ required: true, message: '请选择!' }]}
                             getValueFromEvent={(e: number[]) => {
                                 if (e.length > 1 && !payScene?.includes(noLimitPS) && noLimitPS && e.includes(noLimitPS)) {
@@ -244,7 +244,7 @@ const AdgroupsSitSet: React.FC = () => {
                         </Form.Item>
                     </div>
                     {tencentNewsType === '1' && <div className={style.newSpace_bottom}>
-                        <Form.Item name='tencentNews' rules={[{ required: true, message: '请选择!' }]}>
+                        <Form.Item name={['sceneSpec', 'tencentNews']} rules={[{ required: true, message: '请选择!' }]}>
                             <Checkbox.Group options={Object.keys(TENCENT_NEWS_ENUM)?.map(key => ({ label: TENCENT_NEWS_ENUM[key], value: key }))} />
                         </Form.Item>
                     </div>}
@@ -261,7 +261,7 @@ const AdgroupsSitSet: React.FC = () => {
                         </Form.Item>
                     </div>
                     {displaySceneType === '1' && <div className={style.newSpace_bottom}>
-                        <Form.Item name='displayScene' rules={[{ required: true, message: '请选择!' }]}>
+                        <Form.Item name={['sceneSpec', 'displayScene']} rules={[{ required: true, message: '请选择!' }]}>
                             <Checkbox.Group options={Object.keys(DISPLAY_SCENE_ENUM)?.map(key => ({ label: DISPLAY_SCENE_ENUM[key], value: key }))} />
                         </Form.Item>
                     </div>}

+ 7 - 14
src/pages/launchSystemV3/tencentAdPutIn/create/Ad/newCreateAd.tsx

@@ -81,20 +81,13 @@ const NewCreateAd: React.FC<Props> = ({ value, visible, onChange, onClose }) =>
                 timeSeries,
                 beginDate,
                 endDate,
-                wechatPosition,
-                wechatChannelsScene,
-                wechatScene,
-                tencentNews,
-                displayScene,
+                sceneSpec,
                 marketingAssetOuterSpec,
                 ...surplusValues
             } = JSON.parse(JSON.stringify(value))
             let adgroupsValues: any = {
                 ...surplusValues,
-                wechatPosition,
-                tencentNews,
-                displayScene,
-                wechatScene,
+                sceneSpec,
                 marketingTargetType: marketingAssetOuterSpec?.marketingTargetType
             }
 
@@ -118,31 +111,31 @@ const NewCreateAd: React.FC<Props> = ({ value, visible, onChange, onClose }) =>
             adgroupsValues.date = [moment(beginDate), moment(endDate)]
 
             // 微信公众号与小程序定投
-            if (wechatPosition?.length > 0) {
+            if (sceneSpec?.wechatPosition?.length > 0) {
                 adgroupsValues.wechatPositionType = '1'
             } else {
                 adgroupsValues.wechatPositionType = '0'
             }
             // 微信视频号定投
-            if (wechatChannelsScene?.length > 0) {
+            if (sceneSpec?.wechatChannelsScene?.length > 0) {
                 adgroupsValues.wechatChannelsSceneType = '1'
             } else {
                 adgroupsValues.wechatChannelsSceneType = '0'
             }
             // 微信公众号与小程序场景
-            if (wechatScene && Object.keys(wechatScene).length > 0) {
+            if (sceneSpec?.wechatScene && Object.keys(sceneSpec.wechatScene).length > 0) {
                 adgroupsValues.wechatSceneType = '1'
             } else {
                 adgroupsValues.wechatSceneType = '0'
             }
             // 腾讯新闻流量场景
-            if (tencentNews && tencentNews?.length > 0) {
+            if (sceneSpec?.tencentNews && sceneSpec.tencentNews?.length > 0) {
                 adgroupsValues.tencentNewsType = '1'
             } else {
                 adgroupsValues.tencentNewsType = '0'
             }
             // 优量汇广告展示场景
-            if (displayScene && displayScene?.length > 0) {
+            if (sceneSpec?.displayScene && sceneSpec.displayScene?.length > 0) {
                 adgroupsValues.displaySceneType = '1'
             } else {
                 adgroupsValues.displaySceneType = '0'

+ 2 - 1
src/pages/launchSystemV3/tencentAdPutIn/create/Dynamic/creativeTemplateContent.tsx

@@ -97,7 +97,8 @@ const CreativeTemplateContent: React.FC<{ automaticSiteEnabled: boolean }> = ({
                                                 name={[name, 'overrideCanvasHeadOption']}
                                                 style={{ marginBottom: 0 }}
                                             >
-                                                <Radio.Group disabled>
+                                                <Radio.Group>
+                                                    <Radio value="OPTION_KEEP_DIFFERENT">不替换原生推广页顶部素材</Radio>
                                                     <Radio value="OPTION_CREATIVE_OVERRIDE_CANVAS">使用外层创意素材替换原生推广页顶部素材</Radio>
                                                 </Radio.Group>
                                             </Form.Item>

+ 2 - 2
src/pages/launchSystemV3/tencentAdPutIn/create/Dynamic/creativeTemplateSetup.tsx

@@ -35,7 +35,7 @@ const CreativeTemplateSetup: React.FC = () => {
                 },
                 {
                     required: true, message: '请确保创意名称长度不超过60个字(1个汉字等于2个字符)', validator(_, value) {
-                        if (value && txtLength(value) > 60) {
+                        if (value && txtLength(value) > 50) {
                             return Promise.reject()
                         }
                         return Promise.resolve()
@@ -43,7 +43,7 @@ const CreativeTemplateSetup: React.FC = () => {
                 }
             ]}
         >
-            <InputName placeholder='请输入创意名称' style={{ width: 480 }} length={60} />
+            <InputName placeholder='请输入创意名称' style={{ width: 480 }} length={50} />
         </Form.Item>
     </Card>
 }

+ 5 - 5
src/pages/launchSystemV3/tencentAdPutIn/create/Dynamic/index.tsx

@@ -18,7 +18,7 @@ const Dynamic: React.FC = () => {
     /***************************************/
     const { addelivery, setAddelivery, setMaterialData, setTextData, clearData, setAccountCreateLogs, accountCreateLogs } = useContext(DispatchAddelivery)!;
     const { adgroups, dynamic: dynamicData } = addelivery;
-    const { marketingGoal, marketingAssetOuterSpec, marketingCarrierType, siteSet, automaticSiteEnabled, wechatPosition } = adgroups
+    const { marketingGoal, marketingAssetOuterSpec, marketingCarrierType, siteSet, automaticSiteEnabled, sceneSpec } = adgroups
     const { deliveryMode, creativeTemplateId, dynamicCreativeName, creativeComponents, configuredStatus } = dynamicData
     const { textLink, actionButton, showData, brand, mainJumpInfo } = creativeComponents || {}
     const [newVisible, setNewVisible] = useState<boolean>(false);
@@ -38,7 +38,7 @@ const Dynamic: React.FC = () => {
                 marketingCarrierType,
                 deliveryMode,
                 creativeTemplateId,
-                wechatSceneSpecPosition: wechatPosition,
+                wechatSceneSpecPosition: sceneSpec?.wechatPosition,
                 dynamicCreativeType: deliveryMode === 'DELIVERY_MODE_COMPONENT' ? 'DYNAMIC_CREATIVE_TYPE_PROGRAM' : 'DYNAMIC_CREATIVE_TYPE_COMMON'
             }
             if (automaticSiteEnabled) {
@@ -72,7 +72,7 @@ const Dynamic: React.FC = () => {
                 }
             })
         }
-    }, [creativeTemplateId, deliveryMode, marketingGoal, marketingAssetOuterSpec, marketingCarrierType, siteSet, wechatPosition, automaticSiteEnabled])
+    }, [creativeTemplateId, deliveryMode, marketingGoal, marketingAssetOuterSpec, marketingCarrierType, siteSet, sceneSpec?.wechatPosition, automaticSiteEnabled])
 
     useEffect(() => {
         if (['PAGE_TYPE_H5_PROFILE'].includes(brand?.[0]?.value?.jumpInfo?.pageType)) {
@@ -152,8 +152,8 @@ const Dynamic: React.FC = () => {
                 } else {
                     setAddelivery({ ...addelivery, dynamic, dynamicMaterialDTos: {}, dynamicCreativesTextDTOS: {} })
                 }
-                let oldPageTypeList = mainJumpInfo?.map((item: { value: { pageType: any } }) => item.value.pageType) || []
-                let newPageTypeList = dynamic?.creativeComponents?.mainJumpInfo.map((item: { value: { pageType: any } }) => item.value.pageType)
+                let oldPageTypeList = mainJumpInfo?.map((item: { value: { pageType: any } }) => item.value) || []
+                let newPageTypeList = dynamic?.creativeComponents?.mainJumpInfo.map((item: { value: { pageType: any } }) => item.value)
                 setNewVisible(false)
                 clearData()
                 if (!arraysHaveSameValues(oldPageTypeList || [], newPageTypeList || [])) {

+ 4 - 4
src/pages/launchSystemV3/tencentAdPutIn/create/Dynamic/newDynamic.tsx

@@ -42,7 +42,7 @@ const NewDynamic: React.FC<Props> = ({ value, visible, onClose, onChange, creati
     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 { marketingGoal, marketingAssetOuterSpec, marketingCarrierType, siteSet, sceneSpec, automaticSiteEnabled } = adgroups
 
     const [newMaterialData, setNewMaterialData] = useState<any>({}) // 素材数据
     const [newTextData, setNewTextData] = useState<any>({})
@@ -58,7 +58,7 @@ const NewDynamic: React.FC<Props> = ({ value, visible, onClose, onChange, creati
                 marketingTargetType: marketingAssetOuterSpec.marketingTargetType,
                 marketingCarrierType,
                 siteSet,
-                wechatSceneSpecPosition: wechatPosition || []
+                wechatSceneSpecPosition: sceneSpec?.wechatPosition || []
             }).then((res: any) => {
                 let newArr: any = []
                 let newData: any[] = []
@@ -129,7 +129,7 @@ const NewDynamic: React.FC<Props> = ({ value, visible, onClose, onChange, creati
         } else if (deliveryMode === 'DELIVERY_MODE_COMPONENT') {  // 组件化创意
             getTemplate()
         }
-    }, [deliveryMode, marketingGoal, marketingAssetOuterSpec, marketingCarrierType, siteSet, wechatPosition, value, automaticSiteEnabled])
+    }, [deliveryMode, marketingGoal, marketingAssetOuterSpec, marketingCarrierType, siteSet, sceneSpec?.wechatPosition, value, automaticSiteEnabled])
 
     useEffect(() => {
         if (!(value && Object.keys(value).length > 0) && adcreativeTemplateList?.length > 0 && marketingGoalTypeList?.length > 0) {
@@ -158,7 +158,7 @@ const NewDynamic: React.FC<Props> = ({ value, visible, onClose, onChange, creati
                 marketingCarrierType,
                 deliveryMode,
                 creativeTemplateId: id,
-                wechatSceneSpecPosition: wechatPosition,
+                wechatSceneSpecPosition: sceneSpec?.wechatPosition,
                 dynamicCreativeType: deliveryMode === 'DELIVERY_MODE_COMPONENT' ? 'DYNAMIC_CREATIVE_TYPE_PROGRAM' : 'DYNAMIC_CREATIVE_TYPE_COMMON'
             }
             if (automaticSiteEnabled) {

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

@@ -38,7 +38,7 @@ const MaterialText: React.FC = () => {
         </div>
         <div className={style.detail}>
             <div className={style.detail_body}>
-                <Title level={5} style={{ fontSize: 12 }}>{dynamicCreativesTextDTOS?.type === 0 ? '全部相同' : dynamicCreativesTextDTOS?.type === 1 ? '按创意顺序分配' : null}</Title>
+                <Title level={5} style={{ fontSize: 12 }}>{dynamicCreativesTextDTOS?.type === 0 ? '全部相同' : dynamicCreativesTextDTOS?.type === 1 ? '按创意组一一对应' : dynamicCreativesTextDTOS?.type === 2 ? '按文案顺序分配' : dynamicCreativesTextDTOS?.type === 3 ? '根据文案叉乘' : null}</Title>
                 {dynamicCreativesTextDTOS?.dynamicCreativesTextDetailDTOList?.map((item: { [x: string]: boolean | React.ReactChild | React.ReactFragment | React.ReactPortal | null | undefined; }, index: number) => {
                     if (item) {
                         let keys = Object.keys(item)

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

@@ -1,8 +1,10 @@
 import New1Radio from "@/pages/launchSystemV3/components/New1Radio"
 import TextAideInput from "@/pages/launchSystemV3/components/TextAideInput"
 import { txtLength } from "@/utils/utils"
-import { Button, Card, Form, Modal, Space, message } from "antd"
+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"
 
 
 interface Props {
@@ -48,13 +50,15 @@ const NewText: React.FC<Props> = ({ visible, onClose, onChange, value, textData,
         console.log('创意文案--->', value)
         if (value && Object.keys(value).length) {
             const { type, dynamicCreativesTextDetailDTOList } = value
-            form.setFieldsValue({ type, textDto: dynamicCreativesTextDetailDTOList.map((item: any) => {
-                let data: any = {}
-                Object.keys(item).forEach(key => {
-                    data[key] = item[key]?.[0]
+            form.setFieldsValue({
+                type, textDto: dynamicCreativesTextDetailDTOList.map((item: any) => {
+                    let data: any = {}
+                    Object.keys(item).forEach(key => {
+                        data[key] = item[key]?.[0]
+                    })
+                    return data
                 })
-                return data
-            }) })
+            })
         }
     }, [value])
 
@@ -73,7 +77,7 @@ const NewText: React.FC<Props> = ({ visible, onClose, onChange, value, textData,
         visible={visible}
         onCancel={onClose}
         footer={null}
-        width={700}
+        width={800}
         className={`modalResetCss`}
         bodyStyle={{ padding: '0 0 40px', position: 'relative', borderRadius: '0 0 8px 8px' }}
         maskClosable={false}
@@ -101,56 +105,81 @@ const NewText: React.FC<Props> = ({ visible, onClose, onChange, value, textData,
             <Card className="cardResetCss" style={{ marginTop: 10 }}>
                 <Form.Item name="type" label={<strong>文案分配规则</strong>} style={{ marginBottom: 0 }} rules={[{ required: true, message: '请选择营销目的!' }]}>
                     <New1Radio
-                        data={[{ label: '全部相同', value: 0 }, { label: '按创意顺序分配', value: 1 }]}
+                        data={TextTypeList}
                         onChange={(value) => {
+                            let count = dynamicMaterialDTos.dynamicGroup.length
+                            let oldtextDto: PULLIN.TextDtoProps[] = JSON.parse(JSON.stringify(textDto))
+                            let length = oldtextDto.length
                             if (value === 0) {
-                                form.setFieldsValue({ textDto: [textDto[0] || {}] })
+                                oldtextDto = [textDto[0] || {}]
                             } else if (value === 1) {
-                                let oldtextDto: PULLIN.TextDtoProps[] = JSON.parse(JSON.stringify(textDto))
-                                oldtextDto = oldtextDto.concat(Array(dynamicMaterialDTos.dynamicGroup.length - oldtextDto.length).fill({}))
-                                form.setFieldsValue({ textDto: oldtextDto })
+                                if (count > length) {
+                                    oldtextDto = oldtextDto.concat(Array(count - length).fill({}))
+                                } else {
+                                    oldtextDto = oldtextDto.slice(0, count)
+                                }
+                            } else if (value === 2) {
+                                if (count < length) {
+                                    oldtextDto = oldtextDto.slice(0, count)
+                                }
                             }
+                            form.setFieldsValue({ textDto: oldtextDto })
                         }}
                     />
                 </Form.Item>
             </Card>
 
             <Form.List name="textDto">
-                {(fields) => (<>
+                {(fields, { add, remove }) => (<>
                     {fields.map(({ key, name, ...restField }, num) => (
                         <Card
-                            title={type === 1 ? <strong style={{ fontSize: 14 }}>创意组{num + 1}</strong> : null}
+                            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 }}
                             key={key}
                         >
-                            <Space style={{ width: '100%' }} direction="vertical" size={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()
+                            <Space style={{ display: 'flex' }} align="baseline">
+                                <Space style={{ width: '100%' }} direction="vertical" size={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()
                                                 }
-                                                return Promise.resolve()
-                                            }
-                                        }]}
-                                    >
-                                        <TextAideInput placeholder={'请输入' + item.label} style={{ width: 450 }} maxTextLength={item.restriction.textRestriction.maxLength} />
-                                    </Form.Item>
-                                })}
+                                            }]}
+                                        >
+                                            <TextAideInput placeholder={'请输入' + item.label} style={{ width: 450 }} maxTextLength={item.restriction.textRestriction.maxLength} />
+                                        </Form.Item>
+                                    })}
+                                </Space>
+                                
+                                {([3,2].includes(type) && textDto?.length > 1) && <Popconfirm
+                                    title="你确定删除当前文案组?"
+                                    onConfirm={() => remove(name)}
+                                >
+                                    <MinusCircleOutlined style={{ marginLeft: 20, color: 'red' }} />
+                                </Popconfirm>}
                             </Space>
+
                         </Card>
                     ))}
+                    {[3,2].includes(type) && !(type === 2 && textDto.length >= dynamicMaterialDTos.dynamicGroup.length) && <Form.Item style={{ marginTop: 10, marginBottom: 0 }}>
+                        <Button type="dashed" onClick={() => add({})} block icon={<PlusOutlined />} disabled={type === 3 && textDto.length >= 5}>
+                            新增
+                        </Button>
+                    </Form.Item>}
                 </>)}
             </Form.List>
             <Form.Item className="submit_pull">

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

@@ -29,7 +29,7 @@ const PageList: React.FC = () => {
                     return <div key={index}>
                         <Title level={5} style={{ fontSize: 12 }}>{item.accountId}</Title>
                         {item?.pageList?.length ?
-                            item?.pageList?.map((page: { pageName: string, id: number }) => <div key={page.id} className={style.text}><Text ellipsis={{ tooltip: true }}>{page['pageName']}</Text></div>) :
+                            item?.pageList?.map((page: { pageName: string, pageId: number }) => <div key={page.pageId} className={style.text}><Text ellipsis={{ tooltip: true }}>{page['pageName']}</Text></div>) :
                             <Empty image={Empty.PRESENTED_IMAGE_SIMPLE} style={{ margin: 0, fontSize: 12 }} imageStyle={{ height: 18 }} />}
                     </div>
                 })}
@@ -42,6 +42,7 @@ const PageList: React.FC = () => {
         {addVisible && <PageModal
             data={accountCreateLogs}
             adgroups={adgroups}
+            dynamic={dynamic}
             visible={addVisible}
             onClose={() => {
                 setAddVisible(false)

+ 99 - 0
src/pages/launchSystemV3/tencentAdPutIn/create/addDynamic.tsx

@@ -0,0 +1,99 @@
+import { Card, Drawer, Space, Spin, Typography } from "antd"
+import React, { useEffect, useState } from "react"
+import '../index.less'
+import style from './index.less'
+import Dynamic from "./Dynamic";
+import Material from "./Material";
+import MaterialText from "./MaterialText";
+import PageList from "./PageList";
+import { DispatchAddelivery } from ".";
+const { Text } = Typography;
+
+/**
+ * 新增创意
+ * @returns 
+ */
+const AddDynamic: React.FC<PULLIN.NewAddDynamic> = ({ visible, onChange, onClose, adData }) => {
+
+    /****************************************/
+    const [addelivery, setAddelivery] = useState<PULLIN.AddeliveryProps>({ adgroups: {}, targeting: [], dynamic: {}, dynamicMaterialDTos: {}, dynamicCreativesTextDTOS: {} })
+    const [wechatVisible, setWechatVisible] = useState<boolean>(false) // 选择微信公众号弹窗控制
+    const [materialData, setMaterialData] = useState<any>({}) // 素材数据
+    const [textData, setTextData] = useState<any>({})
+    const [accountCreateLogs, setAccountCreateLogs] = useState<PULLIN.AccountCreateLogsProps[]>([])  // 账户
+    const [tableData, setTableData] = useState<any>({})
+    /****************************************/
+
+    useEffect(() => {
+
+    }, [])
+
+    const clearData = () => {
+        setTableData({})
+    }
+
+    return <Drawer
+        title={<strong>添加创意</strong>}
+        visible={visible}
+        width={1450}
+        onClose={onClose}
+        bodyStyle={{ backgroundColor: '#f1f4fc', padding: 10 }}
+    >
+        <Space direction="vertical" style={{ width: '100%' }}>
+            <Spin spinning={false}>
+
+                <Text type="danger" style={{ marginBottom: 5 }}>选择的广告必须与当前已选广告的营销目的、营销载体、推广内容、广告版位一致</Text>
+                <Card
+                    size="small"
+                    title={<div className={style.cardTitle}>配置区</div>}
+                    className={style.createAd}
+                >
+                    <div className={style.settingsBody}>
+                        <div className={style.settingsBody_content}>
+                            <DispatchAddelivery.Provider
+                                value={{
+                                    addelivery,
+                                    setAddelivery,
+                                    accountCreateLogs,
+                                    setAccountCreateLogs,
+                                    materialData,
+                                    setMaterialData,
+                                    textData,
+                                    setTextData,
+                                    clearData
+                                }}>
+                                <div className={style.settingsBody_content_right}>
+                                    <div className={`${style.settingsBody_content_row} ${style.row1}`}>
+                                        <div className={style.title}>
+                                            <span>广告信息</span>
+                                        </div>
+                                        <div className={style.detail}>
+                                            <div className={style.detail_body}>
+
+                                            </div>
+                                            <div className={style.detail_footer}>
+
+                                            </div>
+                                        </div>
+                                    </div>
+                                    {/* 创意 */}
+                                    <Dynamic />
+                                    {/* 创意素材 */}
+                                    <Material />
+                                </div>
+                                <div className={style.settingsBody_content_left}>
+                                    {/* 创意文案 */}
+                                    <MaterialText />
+                                    {/* 落地页 */}
+                                    <PageList />
+                                </div>
+                            </DispatchAddelivery.Provider>
+                        </div>
+                    </div>
+                </Card>
+            </Spin>
+        </Space>
+    </Drawer>
+}
+
+export default React.memo(AddDynamic)

+ 7 - 2
src/pages/launchSystemV3/tencentAdPutIn/create/index.less

@@ -16,7 +16,9 @@
     --w5: 216px;
 
     .settingsBody_content {
-        min-width: 1200px;
+        min-width: 1400px;
+        overflow: hidden;
+        overflow-y: auto;
         border: 1px solid #f0f0f0;
         border-left: none;
         display: flex;
@@ -37,10 +39,13 @@
         .row2,
         .row3 {
             width: 20%;
+            min-width: 238px;
         }
 
         .row4 {
-            width: 40%;
+            // width: 40%;
+            flex: 1;
+            overflow: hidden;
         }
     }
 

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

@@ -189,6 +189,10 @@ const Create: React.FC = () => {
             } else if (['MARKETING_TARGET_TYPE_WECHAT_OFFICIAL_ACCOUNT'].includes(marketingAssetOuterSpec?.marketingTargetType)) { // 公众号
                 productList = item?.wechatChannelList || []
             }
+            let textType = dynamicCreativesTextDTOS.type
+            let textDto = dynamicCreativesTextDTOS?.dynamicCreativesTextDetailDTOList || []
+            let textDtoLenth = textDto.length
+            let dynamicGroupLength = dynamicMaterialDTos?.dynamicGroup?.length || 0
             let data = cartesianProduct(productList, targeting).map(newD => {
                 let [productDto, targetDto, index] = newD
                 let suffix = '_' + item.accountId + '_' + index
@@ -207,30 +211,66 @@ const Create: React.FC = () => {
                         adgroupName: adgroups.adgroupName + suffix
                     },
                     dynamicDto: dynamic,                          // 创意信息
-                    rowSpan: dynamicMaterialDTos?.dynamicGroup?.length || 1
+                    rowSpan: ([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
                 }
                 return dat
             })
+
             newAdCount += data.length
-            let newData = cartesianProduct(data, dynamicMaterialDTos.dynamicGroup || [{}]).map((item, index) => {
-                let [d1, group] = item
-                return {
-                    ...d1,
-                    id: d1.id + '_' + index,
-                    dynamicGroup: group,
-                    textDto: dynamicCreativesTextDTOS?.dynamicCreativesTextDetailDTOList?.[index % dynamicMaterialDTos.dynamicGroup?.length],                     // 创意文案
+            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 {
+                let newDynamicGroup: any = dynamicMaterialDTos?.dynamicGroup || []
+                if (newDynamicGroup.length > 0 && [0, 1, 2, 3].includes(textType)) {
+                    if (textType === 0) {
+                        newDynamicGroup = newDynamicGroup.map((item: any) => ({ ...item, textDto: textDto?.[0] }))
+                    } else if (textType === 1) {
+                        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) {
+                        newDynamicGroup = cartesianProduct(newDynamicGroup, textDto || [{}]).map((item) => {
+                            let [dynamicGroup, textDtoData] = item
+                            return {
+                                ...dynamicGroup as any,
+                                textDto: textDtoData
+                            }
+                        })
+                    }
                 }
-            })
-            newdynamicCount = newdynamicCount + newData.length
+                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 = newdynamicCount + newData.length
             newTableData[item.accountId] = newData
         })
         setAdCount(newAdCount)
         setDynamicCount(newdynamicCount)
         setActiveKey(accountCreateLogs?.[0].accountId?.toString())
+        console.log('newTableData-->', newTableData)
         setTableData(newTableData)
     }
 
@@ -351,7 +391,7 @@ const Create: React.FC = () => {
     }
 
     return <Space direction="vertical" style={{ width: '100%' }}>
-        <Spin spinning={false}>
+        <Spin spinning={createAdgroupTask.loading}>
             <Card
                 size="small"
                 title={
@@ -559,6 +599,9 @@ const Create: React.FC = () => {
                         bordered
                         scroll={{ x: 1200 }}
                         rowKey={'id'}
+                        pagination={{
+                            defaultPageSize: 50
+                        }}
                     // rowSelection={{
                     //     selectedRowKeys: tableSelect?.map((item: any) => item?.myId.toString()),
                     //     onChange: (selectedRowKeys: React.Key[], selectedRows: any) => {

+ 0 - 1
src/pages/launchSystemV3/tencentAdPutIn/create/tableConfig.tsx

@@ -123,7 +123,6 @@ const columns = (): TableProps<any>['columns'] => {
                     key: 'textDto',
                     width: 200,
                     render: (value, b) => {
-                        console.log('textDto-->', value)
                         let deliveryMode = b?.dynamicDto?.deliveryMode
                         if (value && Object.keys(value).length) {
                             if (deliveryMode === "DELIVERY_MODE_CUSTOMIZE") {

+ 18 - 2
src/pages/launchSystemV3/tencentAdPutIn/index.less

@@ -45,9 +45,25 @@
         border-radius: var(--boder) !important;
     }
 
+    .ant-input-group {
+        .ant-input-affix-wrapper:not(:last-child) {
+            border-top-right-radius: 0 !important;
+            border-bottom-right-radius: 0 !important;
+            .ant-input {
+                border-top-right-radius: 0 !important;
+                border-bottom-right-radius: 0 !important;
+            }
+        }
+        .ant-btn {
+            border-radius: 0 6px 6px 0 !important;
+            height: 32px;
+            padding: 4px 15px;
+        }
+    }
+
     .ant-table-tbody td {
         font-size: 12px;
-        font-family: PingFang SC,Microsoft YaHei UI,Microsoft YaHei,Helvetica Neue,Helvetica,Hiragino Sans GB,Arial,sans-serif;
+        font-family: PingFang SC, Microsoft YaHei UI, Microsoft YaHei, Helvetica Neue, Helvetica, Hiragino Sans GB, Arial, sans-serif;
     }
 }
 
@@ -103,7 +119,7 @@
     text-align: right;
 }
 
-.targetingSelect .ant-drawer-body{
+.targetingSelect .ant-drawer-body {
     height: 100%;
     overflow: hidden;
     padding: 8px;

+ 9 - 0
src/pages/launchSystemV3/tencentAdPutIn/typings.d.ts

@@ -122,4 +122,13 @@ declare namespace PULLIN {
             }
         }
     }
+    /**
+     * 当前广告新增创意
+     */
+    type NewAddDynamic = {
+        adData: any,
+        visible?: boolean,
+        onClose?: () => void,
+        onChange?: () => void
+    }
 }

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

@@ -46,6 +46,25 @@ export async function getmarketingAssetContentApi(data: {
     });
 }
 
+/**
+ * 远程小说接口
+ * @param data 
+ * @returns 
+ */
+export async function getByRemotemarketingAssetContentApi(data: {
+    marketingAssetType?: string,
+    marketingAssetName?: string,
+    accountId: number,
+    pageNum: number,
+    pageSize: number,
+    marketingAssetNameList: string[]
+}) {
+    return request(api + `/adq/v3/marketingAssets/marketingAssetContent/getByRemote`, {
+        method: 'POST',
+        data,
+    });
+}
+
 /**
  * 同步小说
  * @param data
@@ -148,7 +167,16 @@ export async function getTextApi(params: { maxTextLength: number, adAccountId: n
 
 }
 
-
+/**
+ * 获取原生页授权方信息
+ * @param accountId 
+ * @returns 
+ */
+export async function getWXDownPageAuthInfoListApi(accountId: number) {
+    return request(api + `/adq/v3/marketingAssets/listWXDownPageAuthInfo/${accountId}`, {
+        method: 'GET'
+    });
+}
 
 /**
  * 获取ADQ落地页列表
@@ -164,13 +192,14 @@ export async function getAdqLandingPageListApi(params: {
     pageType?: string;
     pageTemplateId?: string;
     pageStatus?: string;
+    ownerUid?: number;
 }) {
     Object.keys(params).forEach(key => {
         if (!params[key]) {
             delete params[key]
         }
     })
-    return request(api + '/adq/v3/marketingAssets/listWXDownPage', {
+    return request(api + '/adq/v3/marketingAssets/listWXDownPageToRemote', {
         method: 'POST',
         data: params,
     });

+ 23 - 0
src/services/launchAdq/adq.ts

@@ -476,3 +476,26 @@ export async function openV3Api(accountId: string) {
     method: 'PUT'
   });
 }
+
+/**
+ * 全开启3.0
+ * @param accountId 
+ * @returns 
+ */
+export async function openAllV3Api(accountId: string) {
+  return request(api + `/adq/adAccount/adUnit/addV3/${accountId}`, {
+    method: 'PUT'
+  });
+}
+
+/**
+ * 广告业务单元广告主账号全量转3.0
+ * @param accountId 
+ * @returns 
+ */
+export async function authSyncApi(params: { accountId: number }) {
+  return request(api + `/adq/adAccount/adUnit/auth/sync`, {
+    method: 'PATCH',
+    params
+  });
+}