wjx 3 maanden geleden
bovenliggende
commit
6871399cdf

+ 34 - 5
src/pages/launchSystemV3/adqv3/creative/index.tsx

@@ -12,6 +12,7 @@ import HandleLog from "./handleLog"
 import moment from "moment"
 import RetriaModal from "./retriaModal"
 import ReplacePage from "./replacePage"
+import ReplaceGfPage from "./replaceGfPage"
 
 /** 审核结果 */
 export const AD_STATUS = {
@@ -33,6 +34,7 @@ const Creative: React.FC<ADQV3.CreativeProps> = ({ queryForm, setQueryForm, user
     const [logVisible, setLogVisible] = useState<boolean>(false)
     const [handleType, setHandleType] = useState<number>(1)
     const [replaceVisible, setReplaceVisible] = useState<boolean>(false)
+    const [replaceGfVisible, setReplaceGfVisible] = useState<boolean>(false)
 
     const getDynamicCreativeV3List = useAjax((params) => getDynamicCreativeV3ListApi(params), { formatResult: true })
     const delBatchCreative = useAjax((params) => delBatchCreativeApi(params))
@@ -240,7 +242,7 @@ const Creative: React.FC<ADQV3.CreativeProps> = ({ queryForm, setQueryForm, user
                     options={[
                         { label: '基本操作', value: 1 },
                         { label: '复审操作', value: 2 },
-                        // { label: '落地页替换', value: 3 },
+                        { label: '落地页替换', value: 3 },
                     ]}
                 />
                 {handleType === 1 ? <>
@@ -261,7 +263,15 @@ const Creative: React.FC<ADQV3.CreativeProps> = ({ queryForm, setQueryForm, user
                 </> : <Button
                     type='primary'
                     disabled={selectedRows.length === 0}
-                    onClick={() => { setReplaceVisible(true) }}
+                    onClick={() => {
+                        if (selectedRows?.[0]?.creativeComponents?.mainJumpInfo?.[0]?.value?.pageType === "WECHAT_CANVAS") { // 原生推广页
+                            setReplaceVisible(true)
+                        } else if (selectedRows?.[0]?.creativeComponents?.mainJumpInfo?.[0]?.value?.pageType === "OFFICIAL") { // 官方落地页
+                            setReplaceGfVisible(true)
+                        } else {
+                            message.error('暂不支持该类型落地页替换')
+                        }
+                    }}
                 >修改落地页</Button>}
 
                 <Button type='dashed' onClick={() => { setLogVisible(true) }}>操作记录</Button>
@@ -275,7 +285,12 @@ const Creative: React.FC<ADQV3.CreativeProps> = ({ queryForm, setQueryForm, user
                             const pageType: string | undefined = mainJumpInfo?.[0]?.value?.pageType
                             const pageLength: number | undefined = mainJumpInfo?.length
                             return {
-                                disabled: record.isDeleted || record.deliveryMode !== deliveryMode || record.creativeTemplateId !== creativeTemplateId || record?.creativeComponents?.mainJumpInfo?.[0]?.value?.pageType !== pageType || pageLength !== record?.creativeComponents?.mainJumpInfo?.length
+                                disabled: record.isDeleted ||
+                                    record.deliveryMode !== deliveryMode ||
+                                    record.creativeTemplateId !== creativeTemplateId ||
+                                    record?.creativeComponents?.mainJumpInfo?.[0]?.value?.pageType !== pageType ||
+                                    pageLength !== record?.creativeComponents?.mainJumpInfo?.length ||
+                                    (mainJumpInfo?.[0]?.value?.pageType === "WECHAT_CANVAS" && record?.creativeComponents?.mainJumpInfo?.[0]?.value?.pageType === "WECHAT_CANVAS" && record?.creativeComponents?.mainJumpInfo?.[0]?.value?.pageSpec?.wechatCanvasSpec?.overrideCanvasHeadOption !== mainJumpInfo?.[0]?.value?.pageSpec?.wechatCanvasSpec?.overrideCanvasHeadOption)
                             }
                         } else {
                             return { disabled: record.isDeleted }
@@ -304,7 +319,8 @@ const Creative: React.FC<ADQV3.CreativeProps> = ({ queryForm, setQueryForm, user
                                         item.deliveryMode === firstData.deliveryMode &&
                                         item.creativeTemplateId === firstData.creativeTemplateId &&
                                         item?.creativeComponents?.mainJumpInfo?.[0]?.value?.pageType === firstData?.creativeComponents?.mainJumpInfo?.[0]?.value?.pageType &&
-                                        firstData?.creativeComponents?.mainJumpInfo?.length === item?.creativeComponents?.mainJumpInfo?.length;
+                                        firstData?.creativeComponents?.mainJumpInfo?.length === item?.creativeComponents?.mainJumpInfo?.length &&
+                                        (firstData?.creativeComponents?.mainJumpInfo?.[0]?.value?.pageType === "WECHAT_CANVAS" && item?.creativeComponents?.mainJumpInfo?.[0]?.value?.pageType === "WECHAT_CANVAS" && item?.creativeComponents?.mainJumpInfo?.[0]?.value?.pageSpec?.wechatCanvasSpec?.overrideCanvasHeadOption === firstData?.creativeComponents?.mainJumpInfo?.[0]?.value?.pageSpec?.wechatCanvasSpec?.overrideCanvasHeadOption);
                                     if (isValid) {
                                         newSelectAccData.push({ ...item });
                                     }
@@ -385,7 +401,7 @@ const Creative: React.FC<ADQV3.CreativeProps> = ({ queryForm, setQueryForm, user
             userId={userId}
         />}
 
-        {/* 修改落地页 */}
+        {/* 修改原生落地页 */}
         {replaceVisible && <ReplacePage
             selectedRows={selectedRows}
             visible={replaceVisible}
@@ -397,6 +413,19 @@ const Creative: React.FC<ADQV3.CreativeProps> = ({ queryForm, setQueryForm, user
                 setSelectedRows([])
             }}
         />}
+
+        {/* 修改官方落地页 */}
+        {replaceGfVisible && <ReplaceGfPage
+            selectedRows={selectedRows}
+            visible={replaceGfVisible}
+            onClose={() => {
+                setReplaceGfVisible(false)
+            }}
+            onChange={() => {
+                setReplaceGfVisible(false)
+                setSelectedRows([])
+            }}
+        />}
     </>
 }
 

+ 310 - 0
src/pages/launchSystemV3/adqv3/creative/replaceGfPage.tsx

@@ -0,0 +1,310 @@
+import React, { useEffect, useState } from "react"
+import '../../tencentAdPutIn/index.less'
+import style from '../../components/GoodsModal/index.less'
+import { Button, Checkbox, Input, message, Modal, Select, Space, Table, Typography } from "antd"
+import { batchUpdateDownloadApi, getAdgroupDetailApi } from "@/services/launchAdq/adqv3";
+import { useAjax } from "@/Hook/useAjax";
+import { getAdqLandingPageOfficialListApi, getWXDownPageAuthInfoListApi } from "@/services/adqV3/global";
+import { CheckOutlined, CloseOutlined, SyncOutlined } from "@ant-design/icons";
+import columns from "../../components/PageModal/tableConfig";
+const { Title, Text } = Typography;
+
+interface ReplacePageProps {
+    selectedRows: any[];
+    visible?: boolean;
+    onClose?: () => void;
+    onChange?: () => void;
+}
+
+/**
+ * 替换官方落地页
+ * @returns 
+ */
+const ReplaceGfPage: React.FC<ReplacePageProps> = ({ selectedRows, visible, onChange, onClose }) => {
+
+    /*********************************************/
+    const { deliveryMode, creativeTemplateId, creativeComponents: { mainJumpInfo } } = selectedRows[0]
+    const pageLength: number | undefined = mainJumpInfo?.length
+    const [data, setData] = useState<{ adgroupId: number, accountId: number, dynamicCreativeId: number, pageLength: number, pageList: any[] }[]>(selectedRows.map(item => {
+        return { adgroupId: item.adgroupId, accountId: item.accountId, dynamicCreativeId: item.dynamicCreativeId, pageList: [], pageLength: item.creativeComponents.mainJumpInfo.length }
+    }))
+    const [queryForm, setQueryForm] = useState<{ accountId?: number, pageName?: string, ownerUid?: number, pageSize: number, pageNum: number, isSqDownPage: boolean }>({ pageNum: 1, pageSize: 20, isSqDownPage: false })
+    const [loading, setLoading] = useState<boolean>(false)
+    const [loading1, setLoading1] = useState<boolean>(false)
+    const [wXDownPageAuthInfo, setWXDownPageAuthInfo] = useState<any>({})
+    const [selectAdz, setSelectAdz] = useState<number>(1)   // 选择创意
+    const [selectData, setSelectData] = useState<any>(selectedRows[0])   // 选择创意
+    const [tableData, setTableData] = useState<any>({})
+    const [adDataInfo, setAdDataInfo] = useState<any>({})
+
+    const batchUpdateDownload = useAjax((params) => batchUpdateDownloadApi(params))
+    const getAdqLandingPageOfficialList = useAjax((params) => getAdqLandingPageOfficialListApi(params))
+    /*********************************************/
+
+    useEffect(() => {
+        if (selectedRows?.length > 0) {
+            setLoading(true)
+            const accountDataList = [...new Set(selectedRows.map(item => item.accountId))]
+            const infoAjax = accountDataList.map(accountId => getWXDownPageAuthInfoListApi(accountId))
+            const newData: any = {}
+            Promise.all(infoAjax).then(res => {
+                res?.forEach((item, index) => {
+                    newData[accountDataList[index]] = item?.data || []
+                })
+                setWXDownPageAuthInfo(newData)
+                setLoading(false)
+            }).catch(() => setLoading(false))
+
+            const adIdDataList = [...new Set(selectedRows.map(item => item.adgroupId + '_' + item.accountId))]
+            const adInfoAjax = adIdDataList.map(item => {
+                const [adgroupId, accountId] = item.split('_')
+                return getAdgroupDetailApi({ adgroupId: Number(adgroupId), accountId: Number(accountId) })
+            })
+
+            const newAdData: any = {}
+            Promise.all(adInfoAjax).then(res => {
+                res?.forEach((item, index) => {
+                    const [adgroupId] = adIdDataList[index].split('_')
+                    newAdData[adgroupId] = item?.data || []
+                })
+                setAdDataInfo(newAdData)
+                setLoading1(false)
+            }).catch(() => setLoading1(false))
+        }
+    }, [])
+
+    useEffect(() => {
+        if (selectData && selectData.accountId && Object.keys(adDataInfo).length) {
+            getList()
+        }
+    }, [queryForm, selectData, adDataInfo])
+
+    const getList = () => {
+        const { marketingGoal, marketingTargetType, marketingCarrierType, siteSet, accountId } = adDataInfo[selectData.adgroupId]
+        const params: any = {
+            ...queryForm,
+            accountId,
+            pageStatus: 'NORMAL',
+            marketingGoal,
+            marketingTargetType,
+            marketingCarrierType,
+            siteSet: siteSet ? siteSet : ["SITE_SET_CHANNELS", "SITE_SET_MOMENTS", "SITE_SET_WECHAT", "SITE_SET_WECHAT_PLUGIN", "SITE_SET_KANDIAN", "SITE_SET_QQ_MUSIC_GAME", "SITE_SET_TENCENT_NEWS", "SITE_SET_TENCENT_VIDEO", "SITE_SET_MOBILE_UNION"],
+            pageType: 'PAGE_TYPE_OFFICIAL',
+            creativeTemplateId: creativeTemplateId || 311
+        }
+        if (params.isSqDownPage) {
+            if (!params?.ownerUid) {
+                setTableData({ total: 0, records: [] })
+                return
+            }
+        } else {
+            delete params?.ownerUid
+        }
+        delete params.isSqDownPage
+        getAdqLandingPageOfficialList.run(params).then(res => {
+            setTableData(res || {})
+        })
+    }
+
+    const handleOk = () => {
+        console.log(data)
+        if (data.every(item => item.pageList.length === item.pageLength)) {
+            batchUpdateDownload.run(data.map(item => {
+                return {
+                    accountId: item.accountId,
+                    dynamicCreativeId: item.dynamicCreativeId,
+                    pageId: item.pageList.map((ite: any) => ite.pageId)
+                }
+            })).then(res => {
+                if (res) {
+                    message.success('替换成功,结果记录查看')
+                    onChange?.()
+                }
+            })
+        } else {
+            message.error('请为每个创意选择对应的落地页数量')
+        }
+    }
+
+    /** 设置选中广告主 */
+    const handleSelectAdz = (value: number) => {
+        if (value === selectAdz) {
+            return
+        }
+        const accountId = selectedRows[value - 1].accountId
+        setSelectData(selectedRows[value - 1])
+        setQueryForm({ ...queryForm, pageNum: 1, accountId, ownerUid: wXDownPageAuthInfo[accountId]?.[0]?.accountId })
+        setSelectAdz(value)
+    }
+
+    return <Modal
+        title={<strong>替换官方落地页</strong>}
+        open={visible}
+        onCancel={onClose}
+        onOk={handleOk}
+        width={1100}
+        className={`${style.SelectPackage} modalResetCss`}
+        bodyStyle={{ padding: '0 10px 0 10px' }}
+        confirmLoading={batchUpdateDownload?.loading}
+    >
+        <div className={style.content}>
+            <div className={style.left} style={{ width: 200 }}>
+                <h4 className={style.title}>创意</h4>
+                <div className={style.accountIdList}>
+                    {data?.map((item, index) => (
+                        <div key={item?.accountId + '_' + item.dynamicCreativeId} onClick={() => { if (!loading && !loading1) handleSelectAdz(index + 1) }} className={`${style.accItem} ${selectAdz === index + 1 && style.select} `}>
+                            {item.dynamicCreativeId}({item?.accountId})
+                            {data[index].pageList?.length === pageLength && <CheckOutlined style={{ color: '#1890ff' }} />}
+                        </div>
+                    ))}
+                </div>
+            </div>
+            <div className={style.right}>
+                <Space style={{ marginBottom: 10 }}>
+                    <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: 210 }}
+                        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}({item.accountId})</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={batchUpdateDownload?.loading} onClick={() => { batchUpdateDownload?.refresh() }}><span style={{ fontSize: 12 }}>刷新</span></Button>
+                </Space>
+
+                <Table
+                    columns={columns(2)}
+                    dataSource={tableData?.records}
+                    size="small"
+                    loading={getAdqLandingPageOfficialList?.loading || loading || loading1}
+                    scroll={{ y: 400 }}
+                    bordered
+                    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: ([910].includes(creativeTemplateId) || deliveryMode === "DELIVERY_MODE_COMPONENT") ? 'checkbox' : 'radio',
+                        getCheckboxProps: (record: any) => {
+                            let { disableCode } = record
+                            if (disableCode !== 0) {
+                                return {
+                                    disabled: true
+                                }
+                            }
+                            // 组件化创意
+                            if (deliveryMode === "DELIVERY_MODE_COMPONENT") {
+                                if (data[selectAdz - 1]?.pageList?.length >= mainJumpInfo?.length) {
+                                    return {
+                                        disabled: data[selectAdz - 1]?.pageList?.some((item: any) => item?.pageId === record?.pageId) ? false : true
+                                    }
+                                } else {
+                                    return {
+                                        disabled: false
+                                    }
+                                }
+                            }
+                            return {
+                                disabled: false
+                            }
+                        },
+                        selectedRowKeys: data[selectAdz - 1]?.pageList?.map((item: any) => item?.pageId),
+                        hideSelectAll: deliveryMode === "DELIVERY_MODE_COMPONENT",
+                        onSelect: (record: any, selected: boolean) => {
+                            let newData = JSON.parse(JSON.stringify(data))
+                            if (([910].includes(creativeTemplateId) || deliveryMode === "DELIVERY_MODE_COMPONENT")) {
+                                let selectedRows = newData?.[selectAdz - 1]?.['pageList'] || []
+                                if (selected) {
+                                    selectedRows.push({ ...record })
+                                    newData[selectAdz - 1]['pageList'] = selectedRows
+                                } else {
+                                    newData[selectAdz - 1]['pageList'] = selectedRows.filter((item: { pageId: number }) => item.pageId !== record.pageId)
+                                }
+                            } else {
+                                newData[selectAdz - 1]['pageList'] = [record]
+                            }
+                            setData([...newData])
+                        },
+                        onSelectAll: (selected: boolean, _: any[], changeRows: { pageId: number }[]) => {
+                            let newData = JSON.parse(JSON.stringify(data))
+                            let selectedRows = newData?.[selectAdz - 1]?.['pageList'] || []
+                            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)
+                                    }
+                                })
+                                newData[selectAdz - 1]['pageList'] = newSelectAccData
+                            } else {
+                                newData[selectAdz - 1]['pageList'] = selectedRows.filter((item: { pageId: number }) => {
+                                    let index = changeRows.findIndex((ite: { pageId: number }) => ite.pageId === item.pageId)
+                                    if (index !== -1) {
+                                        return false
+                                    } else {
+                                        return true
+                                    }
+                                })
+                            }
+                            setData([...newData])
+                        }
+                    }}
+                />
+            </div>
+            <div className={style.center}>
+                <Title level={5}>已选:{data[selectAdz - 1]?.pageList?.length || 0}/{data[selectAdz-1].pageLength}</Title>
+                <div className={style.select_content} style={{ height: 416 }}>
+                    {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: { adgroupId: number, accountId: number, dynamicCreativeId: number, pageLength: number, pageList: any[] }[] = 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>
+}
+
+export default React.memo(ReplaceGfPage)

+ 223 - 23
src/pages/launchSystemV3/adqv3/creative/replacePage.tsx

@@ -1,11 +1,13 @@
-import { Button, Checkbox, Input, Modal, Select, Space } from "antd";
+import { Button, Checkbox, Input, message, Modal, Select, Space, Table, Typography } from "antd";
 import React, { useEffect, useState } from "react"
 import '../../tencentAdPutIn/index.less'
 import style from '../../components/GoodsModal/index.less'
 import { getAdqLandingPageListApi, getWXDownPageAuthInfoListApi } from "@/services/adqV3/global"
-import { getAdqV3AdListApi } from "@/services/launchAdq/adqv3";
+import { batchUpdateDownloadApi, getAdgroupDetailApi } from "@/services/launchAdq/adqv3";
 import { useAjax } from "@/Hook/useAjax";
-import { SyncOutlined } from "@ant-design/icons";
+import { CheckOutlined, CloseOutlined, SyncOutlined } from "@ant-design/icons";
+import columns from "../../components/PageModal/tableConfig";
+const { Title, Text } = Typography;
 
 interface ReplacePageProps {
     selectedRows: any[];
@@ -21,21 +23,29 @@ const ReplacePage: React.FC<ReplacePageProps> = ({ selectedRows, visible, onChan
 
     /***********************************************/
     const { deliveryMode, creativeTemplateId, creativeComponents: { mainJumpInfo } } = selectedRows[0]
-    const pageType: string | undefined = mainJumpInfo?.[0]?.value?.pageType
     const pageLength: number | undefined = mainJumpInfo?.length
+    const overrideCanvasHeadOption = mainJumpInfo?.[0]?.value?.pageSpec?.wechatCanvasSpec?.overrideCanvasHeadOption
+    const [data, setData] = useState<{ adgroupId: number, accountId: number, dynamicCreativeId: number, pageLength: number, pageList: any[] }[]>(selectedRows.map(item => {
+        return { adgroupId: item.adgroupId, accountId: item.accountId, dynamicCreativeId: item.dynamicCreativeId, pageList: [], pageLength: item.creativeComponents.mainJumpInfo.length }
+    }))
 
     const [selectAdz, setSelectAdz] = useState<number>(1)   // 选择创意
     const [selectData, setSelectData] = useState<any>(selectedRows[0])   // 选择创意
     const [loading, setLoading] = useState<boolean>(false)
+    const [loading1, setLoading1] = useState<boolean>(false)
     const [wXDownPageAuthInfo, setWXDownPageAuthInfo] = useState<any>({})
+    const [adDataInfo, setAdDataInfo] = useState<any>({})
     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 [tableData, setTableData] = useState<any>({})
 
     const getAdqLandingPageList = useAjax((params) => getAdqLandingPageListApi(params))
+    const batchUpdateDownload = useAjax((params) => batchUpdateDownloadApi(params))
     /***********************************************/
 
     useEffect(() => {
         if (selectedRows?.length > 0) {
             setLoading(true)
+            setLoading1(true)
             const accountDataList = [...new Set(selectedRows.map(item => item.accountId))]
             const infoAjax = accountDataList.map(accountId => getWXDownPageAuthInfoListApi(accountId))
             const newData: any = {}
@@ -46,30 +56,69 @@ const ReplacePage: React.FC<ReplacePageProps> = ({ selectedRows, visible, onChan
                 setWXDownPageAuthInfo(newData)
                 setLoading(false)
             }).catch(() => setLoading(false))
-            const adIdDataList = [...new Set(selectedRows.map(item => item.adgroupId))]
-            const adInfoAjax = adIdDataList.map(item => getAdqV3AdListApi({ adgroupIdList: [item], pageNum: 1, pageSize: 1 } as ADQV3.GetAdListProps))
+            const adIdDataList = [...new Set(selectedRows.map(item => item.adgroupId + '_' + item.accountId))]
+            const adInfoAjax = adIdDataList.map(item => {
+                const [adgroupId, accountId] = item.split('_')
+                return getAdgroupDetailApi({ adgroupId: Number(adgroupId), accountId: Number(accountId) })
+            })
+
+            const newAdData: any = {}
             Promise.all(adInfoAjax).then(res => {
-                // res?.forEach((item, index) => {
-                //     selectedRows[index].pageList = item?.data?.list || []
-                // })
-                // setSelectData(selectedRows[0])
-                setLoading(false)
-            }).catch(() => setLoading(false))
+                res?.forEach((item, index) => {
+                    const [adgroupId] = adIdDataList[index].split('_')
+                    newAdData[adgroupId] = item?.data || []
+                })
+                setAdDataInfo(newAdData)
+                setLoading1(false)
+            }).catch(() => setLoading1(false))
         }
     }, [])
 
     useEffect(() => {
-        if (selectData) {
+        if (selectData && selectData.accountId && Object.keys(adDataInfo).length) {
             getList()
         }
-    }, [queryForm, selectData])
+    }, [queryForm, selectData, adDataInfo])
 
     const getList = async () => {
-
+        const { marketingGoal, marketingTargetType, marketingCarrierType, siteSet, accountId } = adDataInfo[selectData.adgroupId]
+        let params: any = { ...queryForm, accountId, 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
+        getAdqLandingPageList.run(params).then(res => {
+            setTableData(res || {})
+        })
     }
 
     const handleOk = () => {
-
+        console.log(data)
+        if (data.every(item => item.pageList.length === item.pageLength)) {
+            batchUpdateDownload.run(data.map(item => {
+                return {
+                    accountId: item.accountId,
+                    dynamicCreativeId: item.dynamicCreativeId,
+                    pageId: item.pageList.map((ite: any) => ite.pageId)
+                }
+            })).then(res => {
+                if (res) {
+                    message.success('替换成功,结果记录查看')
+                    onChange?.()
+                }
+            })
+        } else {
+            message.error('请为每个创意选择对应的落地页数量')
+        }
     }
 
     /** 设置选中广告主 */
@@ -84,22 +133,23 @@ const ReplacePage: React.FC<ReplacePageProps> = ({ selectedRows, visible, onChan
     }
 
     return <Modal
-        title={<strong>替换落地页</strong>}
+        title={<strong>替换原生落地页</strong>}
         open={visible}
         onCancel={onClose}
         onOk={handleOk}
         width={1100}
         className={`${style.SelectPackage} modalResetCss`}
         bodyStyle={{ padding: '0 10px 0 10px' }}
+        confirmLoading={batchUpdateDownload?.loading}
     >
         <div className={style.content}>
-            <div className={style.left} style={{ width: 180 }}>
+            <div className={style.left} style={{ width: 200 }}>
                 <h4 className={style.title}>创意</h4>
                 <div className={style.accountIdList}>
-                    {selectedRows?.map((item, index) => (
-                        <div key={item?.accountId + '_' + item.dynamicCreativeId} onClick={() => { if (!loading) handleSelectAdz(index + 1) }} className={`${style.accItem} ${selectAdz === index + 1 && style.select} `}>
+                    {data?.map((item, index) => (
+                        <div key={item?.accountId + '_' + item.dynamicCreativeId} onClick={() => { if (!loading && !loading1) handleSelectAdz(index + 1) }} className={`${style.accItem} ${selectAdz === index + 1 && style.select} `}>
                             {item.dynamicCreativeId}({item?.accountId})
-                            {/* {data[index].pageList?.length > 0 && <CheckOutlined style={{ color: '#1890ff' }} />} */}
+                            {data[index].pageList?.length === pageLength && <CheckOutlined style={{ color: '#1890ff' }} />}
                         </div>
                     ))}
                 </div>
@@ -115,7 +165,7 @@ const ReplacePage: React.FC<ReplacePageProps> = ({ selectedRows, visible, onChan
                     <Checkbox
                         onChange={(e) => {
                             if (e.target.checked && wXDownPageAuthInfo && Object.keys(wXDownPageAuthInfo).length) {
-                                setQueryForm({ ...queryForm, pageNum: 1, ownerUid: wXDownPageAuthInfo[selectedRows[selectAdz - 1].accountId]?.[0]?.accountId, isSqDownPage: true })
+                                setQueryForm({ ...queryForm, pageNum: 1, ownerUid: wXDownPageAuthInfo[data[selectAdz - 1].accountId]?.[0]?.accountId, isSqDownPage: true })
                             } else {
                                 setQueryForm({ ...queryForm, pageNum: 1, ownerUid: undefined, isSqDownPage: false })
                             }
@@ -136,13 +186,163 @@ const ReplacePage: React.FC<ReplacePageProps> = ({ selectedRows, visible, onChan
                         value={queryForm?.ownerUid}
                         dropdownMatchSelectWidth={false}
                     >
-                        {wXDownPageAuthInfo?.[selectedRows[selectAdz - 1].accountId]?.map((item: { accountId: number; accountName: string }) => {
+                        {wXDownPageAuthInfo?.[data[selectAdz - 1].accountId]?.map((item: { accountId: number; accountName: string }) => {
                             return <Select.Option value={item.accountId} key={item.accountId}>{item.accountName}({item.accountId})</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={getAdqLandingPageList?.loading} onClick={() => { getAdqLandingPageList?.refresh() }}><span style={{ fontSize: 12 }}>刷新</span></Button>
                 </Space>
+                <Table
+                    columns={columns()}
+                    dataSource={tableData?.records}
+                    size="small"
+                    loading={getAdqLandingPageList?.loading || loading || loading1}
+                    scroll={{ y: 400 }}
+                    bordered
+                    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: ([910].includes(creativeTemplateId) || deliveryMode === "DELIVERY_MODE_COMPONENT") ? 'checkbox' : 'radio',
+                        getCheckboxProps: (record: any) => {
+                            let { canvasType, pageElementsSpecList } = record
+                            let topData = pageElementsSpecList[0]
+                            if ([910].includes(creativeTemplateId) && canvasType === 'COMMON_PAGE') {
+                                return {
+                                    disabled: true
+                                }
+                            }
+                            // 组件化创意
+                            if (deliveryMode === "DELIVERY_MODE_COMPONENT") {
+                                if (data[selectAdz - 1]?.pageList?.length >= mainJumpInfo?.length) {
+                                    return {
+                                        disabled: data[selectAdz - 1]?.pageList?.some((item: any) => item?.pageId === record?.pageId) ? false : true
+                                    }
+                                } else {
+                                    return {
+                                        disabled: false
+                                    }
+                                }
+                            }
+                            /**
+                             * 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),
+                        hideSelectAll: deliveryMode === "DELIVERY_MODE_COMPONENT",
+                        onSelect: (record: any, selected: boolean) => {
+                            let newData = JSON.parse(JSON.stringify(data))
+                            if (([910].includes(creativeTemplateId) || deliveryMode === "DELIVERY_MODE_COMPONENT")) {
+                                let selectedRows = newData?.[selectAdz - 1]?.['pageList'] || []
+                                if (selected) {
+                                    selectedRows.push({ ...record })
+                                    newData[selectAdz - 1]['pageList'] = selectedRows
+                                } else {
+                                    newData[selectAdz - 1]['pageList'] = selectedRows.filter((item: { pageId: number }) => item.pageId !== record.pageId)
+                                }
+                            } else {
+                                newData[selectAdz - 1]['pageList'] = [record]
+                            }
+                            setData([...newData])
+                        },
+                        onSelectAll: (selected: boolean, _: any[], changeRows: { pageId: number }[]) => {
+                            let newData = JSON.parse(JSON.stringify(data))
+                            let selectedRows = newData?.[selectAdz - 1]?.['pageList'] || []
+                            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)
+                                    }
+                                })
+                                newData[selectAdz - 1]['pageList'] = newSelectAccData
+                            } else {
+                                newData[selectAdz - 1]['pageList'] = selectedRows.filter((item: { pageId: number }) => {
+                                    let index = changeRows.findIndex((ite: { pageId: number }) => ite.pageId === item.pageId)
+                                    if (index !== -1) {
+                                        return false
+                                    } else {
+                                        return true
+                                    }
+                                })
+                            }
+                            setData([...newData])
+                        }
+                    }}
+                />
+            </div>
+            <div className={style.center}>
+                <Title level={5}>已选:{data[selectAdz - 1]?.pageList?.length || 0}/{data[selectAdz - 1].pageLength}</Title>
+                <div className={style.select_content} style={{ height: 416 }}>
+                    {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: { adgroupId: number, accountId: number, dynamicCreativeId: number, pageLength: number, pageList: any[] }[] = 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>

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

@@ -22,6 +22,10 @@ declare namespace ADQV3 {
         beginDate?: string,
         endDate?: string
     };
+    type GetAdgroupDetailProps = {
+        accountId: number,
+        adgroupId: number
+    };
     type AccountAdgroupMapsProps = {
         accountAdgroupMaps: string[]
     };
@@ -42,6 +46,11 @@ declare namespace ADQV3 {
         adgroupId?: number;
         accountId?: number
     }
+    interface BatchUpdateDownloadProps {
+        accountId: number,
+        dynamicCreativeId: number,
+        pageId: number[]
+    }
     interface ModifyAdTimeBatchProps extends AccountAdgroupMapsProps {
         beginDate: string,
         endDate: string,

+ 1 - 1
src/pages/launchSystemV3/components/PageModal/indexOfficial.tsx

@@ -68,7 +68,7 @@ const PageOfficialModal: React.FC<Props> = (props) => {
 
     // 获取落地页列表
     const getList = () => {
-        let params: any = {
+        const params: any = {
             ...queryForm,
             pageStatus: 'NORMAL',
             marketingGoal,

+ 39 - 1
src/pages/launchSystemV3/tencenTasset/accountAssetSharing/subAccount.tsx

@@ -24,6 +24,7 @@ const SubAccount: React.FC<Props> = ({ data, visible, onClose }) => {
     const [queryForm, setQueryForm] = useState<{ accountids?: string[] }>()
     const [visibleS, setVisibleS] = useState<boolean>(false)
     const [dataSource, setDataSource] = useState<any[]>([])
+    const [selectedRows, setSelectedRows] = useState<any[]>([])
 
     const getAccountAssetsGroupAccountList = useAjax((params) => getAccountAssetsGroupAccountListApi(params))
     const revokeAuthAccountAssetsGroup = useAjax((params) => revokeAuthAccountAssetsGroupApi(params))
@@ -55,6 +56,7 @@ const SubAccount: React.FC<Props> = ({ data, visible, onClose }) => {
             hide()
             if (res) {
                 message.success('取消成功')
+                setSelectedRows([])
                 getList()
             }
         }).catch(() => hide())
@@ -64,7 +66,7 @@ const SubAccount: React.FC<Props> = ({ data, visible, onClose }) => {
         title={<span><strong>{data.authMainAccountId} 授权子账户</strong><span style={{ fontSize: 12 }}>(主体:{data.corporationName})</span></span>}
         open={visible}
         className="modalResetCss"
-        width={660}
+        width={720}
         onCancel={onClose}
         footer={null}
     >
@@ -87,6 +89,7 @@ const SubAccount: React.FC<Props> = ({ data, visible, onClose }) => {
                 />
                 <Button type="primary" icon={<SearchOutlined />} onClick={() => getList()}>搜索</Button>
                 <Button type="primary" icon={<PlusOutlined />} onClick={() => { setVisibleS(true) }}>子账户授权</Button>
+                <Button type="primary" danger disabled={selectedRows.length === 0} onClick={() => { del(selectedRows.map(item => item.accountId)) }}>取消授权</Button>
             </div>
 
             <Table
@@ -97,6 +100,41 @@ const SubAccount: React.FC<Props> = ({ data, visible, onClose }) => {
                 scroll={{ y: 600 }}
                 bordered
                 rowKey={'id'}
+                rowSelection={data.authType !== 'conversion' ? {
+                    selectedRowKeys: selectedRows.map(item => item.id),
+                    onSelect: (record: { id: number }, selected: boolean) => {
+                        if (selected) {
+                            selectedRows.push({ ...record })
+                            setSelectedRows([...selectedRows])
+                        } else {
+                            let newSelectAccData = selectedRows.filter((item: { id: number }) => item.id !== record.id)
+                            setSelectedRows([...newSelectAccData])
+                        }
+                    },
+                    onSelectAll: (selected: boolean, selectedRowss: { id: number }[], changeRows: { id: number }[]) => {
+                        if (selected) {
+                            let newSelectAccData = [...selectedRows]
+                            changeRows.forEach((item: { id: number }) => {
+                                let index = newSelectAccData.findIndex((ite: { id: number }) => ite.id === item.id)
+                                if (index === -1) {
+                                    let data: any = { ...item }
+                                    newSelectAccData.push(data)
+                                }
+                            })
+                            setSelectedRows([...newSelectAccData])
+                        } else {
+                            let newSelectAccData = selectedRows.filter((item: { id: number }) => {
+                                let index = changeRows.findIndex((ite: { id: number }) => ite.id === item.id)
+                                if (index !== -1) {
+                                    return false
+                                } else {
+                                    return true
+                                }
+                            })
+                            setSelectedRows([...newSelectAccData])
+                        }
+                    }
+                } : undefined}
             />
         </Space>
 

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

@@ -13,6 +13,17 @@ export async function getAdqV3AdListApi(data: ADQV3.GetAdListProps) {
     });
 }
 
+/**
+ * 广告详情
+ * @param param0 
+ * @returns 
+ */
+export async function getAdgroupDetailApi({ accountId, adgroupId }: ADQV3.GetAdgroupDetailProps) {
+    return request(api + `/adq/adgroup/detail/${accountId}/${adgroupId}`, {
+        method: 'GET'
+    });
+}
+
 /**
  * 同步
  * @param data 
@@ -61,6 +72,18 @@ export async function getDynamicCreativeV3ListApi(data: ADQV3.GetDynamicCreative
     });
 }
 
+/**
+ * 修改落地页
+ * @param data 
+ * @returns 
+ */
+export async function batchUpdateDownloadApi(data: ADQV3.BatchUpdateDownloadProps[]) {
+    return request(api + '/adq/dynamicCreative/batchUpdateDownload', {
+        method: 'POST',
+        data
+    });
+}
+
 /**
  * 修改时间
  * @param data