Bläddra i källkod

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

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

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

@@ -13,6 +13,7 @@ import { arraysHaveSameValues } from "@/utils/utils";
 import { MARKETING_CARRIER_TYPE_ENUM, MARKETING_GOAL_ENUM, MARKETING_TARGET_TYPE_ENUM, SITE_SET_ENUM } from "../../tencentAdPutIn/const";
 import { MARKETING_CARRIER_TYPE_ENUM, MARKETING_GOAL_ENUM, MARKETING_TARGET_TYPE_ENUM, SITE_SET_ENUM } from "../../tencentAdPutIn/const";
 import Log from "../components/log";
 import Log from "../components/log";
 import '../../tencentAdPutIn/index.less'
 import '../../tencentAdPutIn/index.less'
+import UserTactics from "../../tencentAdPutIn/create/TacticsS/userTactics";
 const { Text } = Typography;
 const { Text } = Typography;
 
 
 const Ad: React.FC<ADQV3.AdProps> = ({ userId, creativeHandle }) => {
 const Ad: React.FC<ADQV3.AdProps> = ({ userId, creativeHandle }) => {
@@ -21,9 +22,10 @@ const Ad: React.FC<ADQV3.AdProps> = ({ userId, creativeHandle }) => {
     const [queryFrom, set_queryFrom] = useState<ADQV3.GetAdListProps>({ pageNum: 1, pageSize: 20, useType: 1 })
     const [queryFrom, set_queryFrom] = useState<ADQV3.GetAdListProps>({ pageNum: 1, pageSize: 20, useType: 1 })
     const [isClearSelect, setIsClearSelect] = useState(true)
     const [isClearSelect, setIsClearSelect] = useState(true)
     const [selectedRows, setSelectedRows] = useState<any[]>([])
     const [selectedRows, setSelectedRows] = useState<any[]>([])
+    const [tactics, setTactics] = useState<any>()
     const [update, setUpdate] = useState<{ visible: boolean }>({ visible: false })
     const [update, setUpdate] = useState<{ visible: boolean }>({ visible: false })
     const [addDynamicVisible, setAddDynamicVisible] = useState<boolean>(false)
     const [addDynamicVisible, setAddDynamicVisible] = useState<boolean>(false)
-    const [handleType, setHandleType] = useState<number>(2)
+    const [handleType, setHandleType] = useState<number>(1)
     const [czjlShow, setCzjlShow] = useState(false)
     const [czjlShow, setCzjlShow] = useState(false)
 
 
     const syncBatch = useAjax((params) => syncBatchApi(params))
     const syncBatch = useAjax((params) => syncBatchApi(params))
@@ -253,6 +255,14 @@ const Ad: React.FC<ADQV3.AdProps> = ({ userId, creativeHandle }) => {
                         <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' 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={<TransactionOutlined />} disabled={selectedRows.length === 0} onClick={() => setUpdate({ visible: true })}>修改出价</Button></Col>
                     </> : handleType === 2 ? <>
                     </> : handleType === 2 ? <>
+                        <Col><UserTactics
+                            type="updateAd"
+                            onChange={(value) => {
+                                setTactics(value)
+                                addDynamic()
+                            }}
+                            userId={userId}
+                        /></Col>
                         <Col><Button type='primary' icon={<PlusOutlined />} disabled={selectedRows.length === 0} onClick={addDynamic}>添加创意</Button></Col>
                         <Col><Button type='primary' icon={<PlusOutlined />} disabled={selectedRows.length === 0} onClick={addDynamic}>添加创意</Button></Col>
                         <Col>
                         <Col>
                             <Space>
                             <Space>
@@ -372,10 +382,12 @@ const Ad: React.FC<ADQV3.AdProps> = ({ userId, creativeHandle }) => {
             onClose={() => {
             onClose={() => {
                 setAddDynamicVisible(false)
                 setAddDynamicVisible(false)
             }}
             }}
+            tactics={tactics}
             onChange={() => {
             onChange={() => {
                 setAddDynamicVisible(false)
                 setAddDynamicVisible(false)
                 getAdqV3AdList.refresh()
                 getAdqV3AdList.refresh()
                 setSelectedRows([])
                 setSelectedRows([])
+                setTactics(undefined)
             }}
             }}
         />}
         />}
 
 

+ 53 - 42
src/pages/launchSystemV3/components/PageModal/index.tsx

@@ -1,7 +1,7 @@
 
 
 import { useAjax } from "@/Hook/useAjax"
 import { useAjax } from "@/Hook/useAjax"
-import { CheckOutlined, CloseOutlined, SyncOutlined } from "@ant-design/icons"
-import { Button, Checkbox, Input, message, Modal, Select, Space, Table, Typography } from "antd"
+import { CheckOutlined, CloseOutlined, QuestionCircleOutlined, SyncOutlined } from "@ant-design/icons"
+import { Button, Checkbox, Input, message, Modal, Select, Space, Table, Tooltip, Typography } from "antd"
 import React, { useEffect, useState } from "react"
 import React, { useEffect, useState } from "react"
 import style from '../GoodsModal/index.less'
 import style from '../GoodsModal/index.less'
 import columns from "./tableConfig"
 import columns from "./tableConfig"
@@ -121,39 +121,58 @@ const PageModal: React.FC<Props> = (props) => {
     }
     }
 
 
     /** 一键设置 */
     /** 一键设置 */
-    // 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 filterData = newData?.filter(item => item.accountId !== data[selectAdz - 1].accountId)
+        let ajax = filterData?.map(item => {
+            let params: any = { ...queryForm, pageNum: 1, accountId: item.accountId, ownerUid: wXDownPageAuthInfo[item.accountId]?.[0]?.accountId, pageName, pageStatus: 'NORMAL', marketingGoal, marketingTargetType, marketingCarrierType, siteSet }
+            if (!params.isSqDownPage) {
+                delete params?.ownerUid
+            }
+            if (params?.isCanvasType) {
+                params.canvasType = 'CANVAS_TYPE_COMMON_PAGE'
+            }
+            delete params?.isCanvasType
+            delete params.isSqDownPage
+            return getAdqLandingPageListApi(params)
+        })
+        Promise.all(ajax).then(res => {
+            if (res && Array.isArray(res)) {
+                res.forEach((item: any, index) => {
+                    let records = item?.data?.records
+                    if (Array.isArray(records) && records?.length > 0) {
+                        let record = records[0]
+                        let filterD = filterData[index]
+                        newData = newData.map(item => {
+                            if (item.accountId.toString() === filterD.accountId.toString() && record) {
+                                return { ...item, pageList: [{ ...record, id: record.pageId }] }
+                            }
+                            return item
+                        })
+                    }
+                })
+                setData(newData)
+            }
+            message.success('设置完成');
+            hide()
+        })
+    }
 
 
     return <Modal
     return <Modal
         title={<Space>
         title={<Space>
             <span>ADQ落地页</span>
             <span>ADQ落地页</span>
+            {data?.length > 1 && <Button style={{ padding: 0, margin: 0 }} disabled={!data[selectAdz - 1]['pageList']?.length} onClick={setOnekey} type="link" loading={listAjax.loading}>
+                <Space>
+                    <span style={{ fontSize: 12 }}>一键设置</span>
+                    <Tooltip color="#FFF" overlayInnerStyle={{ color: '#000' }} title="设置其它账号有相同名称的落地页为那个账号的落地页(需要落地页名称相同,否则不设置,注意只会根据当前条件去搜索,比如选择了被授权落地页,只会去被授权落地页里找对应落地页)">
+                        <QuestionCircleOutlined />
+                    </Tooltip>
+                </Space>
+            </Button>}
             <Text type="warning">{OPTION_ENUM[overrideCanvasHeadOption]}</Text>
             <Text type="warning">{OPTION_ENUM[overrideCanvasHeadOption]}</Text>
         </Space>}
         </Space>}
         visible={visible}
         visible={visible}
@@ -194,7 +213,7 @@ const PageModal: React.FC<Props> = (props) => {
                     ><span style={{ fontSize: 12 }}>被授权落地页</span></Checkbox>
                     ><span style={{ fontSize: 12 }}>被授权落地页</span></Checkbox>
                     {queryForm.isSqDownPage && <Select
                     {queryForm.isSqDownPage && <Select
                         placeholder='选择原生页授权方信息'
                         placeholder='选择原生页授权方信息'
-                        style={{ width: 200 }}
+                        style={{ width: 210 }}
                         showSearch
                         showSearch
                         filterOption={(input: any, option: any) =>
                         filterOption={(input: any, option: any) =>
                             (option!.children as unknown as string).toLowerCase().includes(input.toLowerCase())
                             (option!.children as unknown as string).toLowerCase().includes(input.toLowerCase())
@@ -207,19 +226,11 @@ const PageModal: React.FC<Props> = (props) => {
                         dropdownMatchSelectWidth={false}
                         dropdownMatchSelectWidth={false}
                     >
                     >
                         {wXDownPageAuthInfo?.[data[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}</Select.Option>
+                            return <Select.Option value={item.accountId} key={item.accountId}>{item.accountName}({item.accountId})</Select.Option>
                         })}
                         })}
                     </Select>}
                     </Select>}
                     <Input value={queryForm?.pageName} style={{ width: 150 }} allowClear placeholder='请输入落地页名称' onChange={(e) => setQueryForm({ ...queryForm, pageNum: 1, pageName: e.target.value })} />
                     <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 style={{ padding: 0, margin: 0 }} icon={<SyncOutlined />} type='link' loading={listAjax?.loading} onClick={() => { listAjax?.refresh() }}><span style={{ fontSize: 12 }}>刷新</span></Button>
                 </Space>
                 </Space>
                 <Table
                 <Table
                     columns={columns()}
                     columns={columns()}

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

@@ -247,7 +247,7 @@ const AddMaterial: React.FC<Props> = ({ creativeTemplateId, materialData, delive
                             </Space>}
                             </Space>}
                             className="cardResetCss"
                             className="cardResetCss"
                             key={field.key}
                             key={field.key}
-                            style={{ width: ([641, 642, 643, 720, 721, 722, 1529, 618].includes(creativeTemplateId) || dynamicGroup?.length === 1) ? '100%' : '49%' }}
+                            style={{ width: ([641, 642, 643, 720, 721, 722, 1529, 618].includes(creativeTemplateId) || dynamicGroup?.length === 1) ? '100%' : 'calc(50% - 5px)' }}
                         >
                         >
                             <Space size={30} style={{ width: '100%' }} className={styles.space}>
                             <Space size={30} style={{ width: '100%' }} className={styles.space}>
                                 {deliveryMode === 'DELIVERY_MODE_CUSTOMIZE' ? Object.keys(materialData)?.map(key => {
                                 {deliveryMode === 'DELIVERY_MODE_CUSTOMIZE' ? Object.keys(materialData)?.map(key => {

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

@@ -161,7 +161,6 @@ const NewText: React.FC<Props> = ({ visible, onClose, onChange, value, textData,
                                             }]}
                                             }]}
                                         >
                                         >
                                             <TextAideInput placeholder={'请输入' + item.label} style={{ width: 450 }} maxTextLength={item.restriction.textRestriction.maxLength} />
                                             <TextAideInput placeholder={'请输入' + item.label} style={{ width: 450 }} maxTextLength={item.restriction.textRestriction.maxLength} />
-                                            {/* <div style={{ width: 450, border: '1px solid red' }}>11111111</div> */}
                                         </Form.Item>
                                         </Form.Item>
                                     })}
                                     })}
                                 </div>
                                 </div>

+ 70 - 0
src/pages/launchSystemV3/tencentAdPutIn/create/TacticsS/index.tsx

@@ -0,0 +1,70 @@
+import { useAjax } from "@/Hook/useAjax";
+import { addV3StrategyApi } from "@/services/adqV3";
+import { Button, Form, Input, message, Modal } from "antd"
+import React, { useState } from "react"
+import '../../index.less'
+
+interface Props {
+    strategyValue: {
+        adData: any[],
+        addelivery: PULLIN.AddeliveryProps,
+        accountCreateLogs: PULLIN.AccountCreateLogsProps[],
+        materialData: any,
+        textData: any
+    }
+}
+/**
+ * 存为策略组
+ * @returns 
+ */
+const TacticsS: React.FC<Props> = ({ strategyValue }) => {
+
+    /*********************************/
+    const [form] = Form.useForm();
+    const [visible, setVisible] = useState<boolean>(false)
+
+    const addV3Strategy = useAjax((params) => addV3StrategyApi(params))
+    /*********************************/
+
+    const seve = () => {
+        setVisible(true)
+    }
+
+    const handleOk = () => {
+        form.validateFields().then(values => {
+            addV3Strategy.run({ ...values, strategyValue: JSON.stringify(strategyValue), type: 'updateAd' }).then(res => {
+                if (res) {
+                    message.success('保存成功')
+                    form.resetFields()
+                    setVisible(false)
+                }
+            })
+        })
+    }
+
+    return <>
+        <Button type='primary' onClick={seve}>存为策略组</Button>
+        {visible && <Modal
+            title="存为策略组"
+            visible={visible}
+            onCancel={() => { form.resetFields(); setVisible(false) }}
+            onOk={handleOk}
+            confirmLoading={addV3Strategy.loading}
+            className="modalResetCss"
+        >
+            <Form
+                form={form}
+                layout='vertical'
+                name="saveUpdateAd"
+                colon={false}
+                initialValues={{}}
+            >
+                <Form.Item label={<strong>策略组名称</strong>} name='strategyKey' rules={[{ required: true, message: '请输入策略组名称' }]}>
+                    <Input placeholder="请输入策略组名称" showCount maxLength={30} />
+                </Form.Item>
+            </Form>
+        </Modal>}
+    </>
+}
+
+export default React.memo(TacticsS)

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

@@ -0,0 +1,108 @@
+import { Popconfirm, TableProps, Typography } from "antd";
+import React from "react";
+import { MARKETING_CARRIER_TYPE_ENUM, MARKETING_GOAL_ENUM, MARKETING_TARGET_TYPE_ENUM, SITE_SET_ENUM } from "../../const";
+const { Paragraph } = Typography;
+
+export const Columns = (del: (id: number) => void): TableProps<any>['columns'] => {
+
+    const columns: TableProps<any>['columns'] = [
+        {
+            title: 'ID',
+            dataIndex: 'id',
+            key: 'id',
+            width: 60,
+            align: 'center'
+        },
+        {
+            title: '创建人',
+            dataIndex: 'putUserName',
+            key: 'putUserName',
+            width: 60,
+            align: 'center'
+        },
+        {
+            title: '策略组名称',
+            dataIndex: 'strategyKey',
+            key: 'strategyKey',
+            width: 150
+        },
+        {
+            title: '当前账号ID',
+            dataIndex: 'accountId',
+            key: 'accountId',
+            width: 90,
+            align: 'center',
+            render: (_, b) => {
+                let strategyValue = b.strategyValue
+                let { adData } = JSON.parse(strategyValue)
+                let AccountSet = new Set(adData.map((item: { accountId: any; }) => item.accountId))
+                return <Paragraph style={{ marginBottom: 0, wordBreak: 'break-all' }} ellipsis={{ rows: 3, tooltip: true }}>{[...AccountSet].map(accountId => accountId).join(',')}</Paragraph>
+            }
+        },
+        {
+            title: '当前广告ID',
+            dataIndex: 'adgroupId',
+            key: 'adgroupId',
+            width: 90,
+            align: 'center',
+            render: (_, b) => {
+                let strategyValue = b.strategyValue
+                let { adData } = JSON.parse(strategyValue)
+                return <Paragraph style={{ marginBottom: 0, wordBreak: 'break-all' }} ellipsis={{ rows: 3, tooltip: true }}>{adData.map((item: { adgroupId: any; }) => item.adgroupId).join(',')}</Paragraph>
+            }
+        },
+        {
+            title: '当前广告名称',
+            dataIndex: 'adName',
+            key: 'adName',
+            width: 150,
+            render: (_, b) => {
+                let strategyValue = b.strategyValue
+                let { adData } = JSON.parse(strategyValue)
+                return <Paragraph style={{ marginBottom: 0, wordBreak: 'break-all' }} ellipsis={{ rows: 3, tooltip: true }}>{adData.map((item: { adgroupName: any; }) => item.adgroupName).join(',')}</Paragraph>
+            }
+        },
+        {
+            title: '当前选择广告类型',
+            dataIndex: 'ad',
+            key: 'ad',
+            width: 350,
+            render: (_, b) => {
+                let strategyValue = b.strategyValue
+                let { adData } = JSON.parse(strategyValue)
+                return <span dangerouslySetInnerHTML={{
+                    __html: `营销目的:<span style="color: #52c41a">${MARKETING_GOAL_ENUM[adData?.[0]?.marketingGoal]}</span>,
+                    推广产品类型:<span style="color: #52c41a">${MARKETING_TARGET_TYPE_ENUM[adData?.[0]?.marketingTargetType]}</span>,
+                    营销载体类型:<span style="color: #52c41a">${MARKETING_CARRIER_TYPE_ENUM[adData?.[0]?.marketingCarrierType]}</span>,
+                    版位选择:<span style="color: #52c41a">${adData?.[0]?.automaticSiteEnabled ? '自动版位' : '选择特定版位'}</span>,
+                    ${!adData?.[0]?.automaticSiteEnabled && `广告版位:<span style="color: #52c41a">${adData?.[0]?.siteSet.map((item: string | number) => SITE_SET_ENUM[item]).toString()}</span>`}
+                `}} />
+            }
+        },
+        {
+            title: '创建时间',
+            dataIndex: 'createTime',
+            key: 'createTime',
+            ellipsis: true,
+            width: 135
+        },
+        {
+            title: '操作',
+            dataIndex: 'cz',
+            key: 'cz',
+            fixed: 'right',
+            width: 55,
+            align: 'center',
+            render: (_, b) => {
+                return <Popconfirm
+                    title="是否删除?"
+                    onConfirm={() => del(b?.id)}
+                >
+                    <a style={{ color: 'red' }}>删除</a>
+                </Popconfirm>
+            }
+        }
+    ];
+
+    return columns
+}

+ 120 - 0
src/pages/launchSystemV3/tencentAdPutIn/create/TacticsS/userTactics.tsx

@@ -0,0 +1,120 @@
+import { useAjax } from "@/Hook/useAjax"
+import { Button, Input, message, Modal, Space, Spin, Table } from "antd"
+import React, { useEffect, useState } from "react"
+import { Columns } from "./tableConfig"
+import { delV3StrategyApi, getV3StrategyListApi } from "@/services/adqV3"
+import { getAdqV3AdListApi } from "@/services/launchAdq/adqv3";
+import '../../index.less'
+
+interface Props {
+    userId: number
+    type: string,
+    onChange?: (value: any) => void
+}
+/**
+ * 使用策略组
+ * @returns 
+ */
+const UserTactics: React.FC<Props> = ({ onChange, type, userId }) => {
+
+    /***********************/
+    const [visible, setVisible] = useState<boolean>(false)
+    const [queryFormNew, setQueryFormNew] = useState<PULLIN.GetV3StrategyListProps>({ pageNum: 1, pageSize: 20, type })
+    const [selectedRowKeys, setSelectedRowKeys] = useState<any[]>([])
+
+    const getStrategy = useAjax((params) => getV3StrategyListApi(params))
+    const delStrategy = useAjax((params) => delV3StrategyApi(params))
+    const getAdqV3AdList = useAjax((params) => getAdqV3AdListApi(params), { formatResult: true })
+    /***********************/
+
+    useEffect(() => {
+        if (visible) {
+            getList()
+        }
+    }, [visible, queryFormNew])
+
+    const getList = () => {
+        getStrategy.run(queryFormNew)
+    }
+
+    const use = () => {
+        setVisible(true)
+    }
+
+    const handleOk = () => {
+        if (selectedRowKeys.length > 0) {
+            const hide = message.loading('正在检测广告是否被删除...', 0)
+            let {strategyValue} = selectedRowKeys[0]
+            let { adData } = JSON.parse(strategyValue)
+            getAdqV3AdList.run({ pageNum: 1, pageSize: 100, useType: 1, userId, adgroupIdList: adData.map((item: { adgroupId: any; }) => item.adgroupId) }).then(res => {
+                if (res?.data) {
+                    if (res.data?.records?.every((item: { isDeleted: boolean }) => !item.isDeleted)) {
+                        onChange?.(selectedRowKeys[0])
+                    } else {
+                        message.error('当前有广告给删除了')
+                    }
+                } else {
+                    message.error('找不到广告,或者服务器异常')
+                }
+                hide()
+            }).catch(() => hide())
+        } else {
+            message.error('请选择策略组')
+        }
+    }
+
+    const del = (id: number) => {
+        delStrategy.run(id).then(res => {
+            message.success('删除成功')
+            getStrategy.refresh()
+        })
+    }
+
+    return <>
+        <Button type='primary' onClick={use}>使用策略组</Button>
+        {visible && <Modal
+            title='使用策略组'
+            visible={visible}
+            onCancel={() => { setVisible(false) }}
+            onOk={handleOk}
+            width={1200}
+            confirmLoading={getAdqV3AdList.loading}
+            className="modalResetCss"
+        >
+            <Space style={{ width: '100%' }} direction='vertical'>
+                <Space>
+                    <Input.Search enterButton allowClear placeholder="请输入商品名称" onSearch={(value) => setQueryFormNew({ ...queryFormNew, strategyKey: value, pageNum: 1 })} />
+                    <span style={{ color: 'red' }}>请确保广告没有被删除</span>
+                </Space>
+                <Table
+                    dataSource={getStrategy?.data?.records}
+                    loading={getStrategy.loading}
+                    columns={Columns(del)}
+                    size="small"
+                    bordered
+                    rowKey={'id'}
+                    scroll={{ x: 800 }}
+                    rowSelection={{
+                        type: 'radio',
+                        onChange: (selectedRowKeys: React.Key[], selectedRows: any[]) => {
+                            console.log(selectedRowKeys, selectedRows);
+                            setSelectedRowKeys(selectedRows)
+                        }
+                    }}
+                    pagination={{
+                        total: getStrategy?.data?.total,
+                        current: queryFormNew?.pageNum,
+                        pageSize: queryFormNew?.pageSize
+                    }}
+                    onChange={(pagination) => {
+                        const { current, pageSize } = pagination
+                        setQueryFormNew({ ...queryFormNew, pageNum: current as number, pageSize: pageSize as number || 20 })
+                    }}
+                />
+            </Space>
+        </Modal>}
+    </>
+}
+
+
+export default React.memo(UserTactics)

+ 21 - 7
src/pages/launchSystemV3/tencentAdPutIn/create/Target/addTarget.tsx

@@ -1,4 +1,4 @@
-import { Button, Card, Checkbox, Form, Input, Modal, Radio, Select, Space, Tooltip, TreeSelect, Typography, message } from "antd"
+import { Button, Card, Checkbox, Form, Input, Modal, Radio, Select, Space, Spin, Tooltip, TreeSelect, Typography, message } from "antd"
 import React, { useEffect, useState } from "react"
 import React, { useEffect, useState } from "react"
 import style from '../index.less'
 import style from '../index.less'
 import { DEVICE_PRICE_ENUM, EDUCATION_ENUM, EXCLUDED_DIMENSION_ENUM, GENDER_ENUM, LOCATION_TYPES_ENUM, MARITAL_STATUS_ENUM, NETWORK_ENUM, OPTIMIZATIONGOAL_ENUM, USER_OS_ENUM, WECHAT_AD_NEHAVIOR_ENUM } from "../../const"
 import { DEVICE_PRICE_ENUM, EDUCATION_ENUM, EXCLUDED_DIMENSION_ENUM, GENDER_ENUM, LOCATION_TYPES_ENUM, MARITAL_STATUS_ENUM, NETWORK_ENUM, OPTIMIZATIONGOAL_ENUM, USER_OS_ENUM, WECHAT_AD_NEHAVIOR_ENUM } from "../../const"
@@ -98,7 +98,7 @@ const AddTarget: React.FC<Props> = ({ isBackVal, value, visible, onChange, onClo
             let gw = parentList.filter((item: { title: string }) => item.title === '国外')
             let gw = parentList.filter((item: { title: string }) => item.title === '国外')
             let earth = [
             let earth = [
                 { ...zg[0], children: zg_children },
                 { ...zg[0], children: zg_children },
-                { ...gw[0], disabled: true }
+                // { ...gw[0], disabled: true }
             ]
             ]
             setRegionsList(earth)
             setRegionsList(earth)
         })
         })
@@ -161,6 +161,7 @@ const AddTarget: React.FC<Props> = ({ isBackVal, value, visible, onChange, onClo
             accountId,
             accountId,
             geoLocationType,
             geoLocationType,
             ageType,
             ageType,
+            geoLocation,
             age,
             age,
             gender,
             gender,
             education,
             education,
@@ -181,6 +182,12 @@ const AddTarget: React.FC<Props> = ({ isBackVal, value, visible, onChange, onClo
         let targetValues: any = {
         let targetValues: any = {
             ...surplusValues,
             ...surplusValues,
         }
         }
+        if (geoLocationType === '1') {
+            targetValues.geoLocation = {
+                ...geoLocation,
+                regions: geoLocation.regions[0] === 1156 ? regionsList[0]?.children?.filter((item: any) => !item.disabled)?.map((item: { value: any }) => item.value) : geoLocation.regions
+            }
+        }
         // 性别
         // 性别
         if (gender !== '0') {
         if (gender !== '0') {
             targetValues.gender = [gender]
             targetValues.gender = [gender]
@@ -234,7 +241,6 @@ const AddTarget: React.FC<Props> = ({ isBackVal, value, visible, onChange, onClo
             accountId,
             accountId,
             targeting: targetValues
             targeting: targetValues
         }
         }
-
         if (isBackVal && !isAdd) {
         if (isBackVal && !isAdd) {
             delete targetingDTO.accountId
             delete targetingDTO.accountId
             delete targetingDTO.description
             delete targetingDTO.description
@@ -247,7 +253,6 @@ const AddTarget: React.FC<Props> = ({ isBackVal, value, visible, onChange, onClo
             message.error('存在相同模板名称,请修改')
             message.error('存在相同模板名称,请修改')
             return
             return
         }
         }
-
         if (value?.id) {
         if (value?.id) {
             updateTargeting.run({ ...targetingDTO, id: value?.id }).then(res => {
             updateTargeting.run({ ...targetingDTO, id: value?.id }).then(res => {
                 message.success('修改成功')
                 message.success('修改成功')
@@ -269,7 +274,8 @@ const AddTarget: React.FC<Props> = ({ isBackVal, value, visible, onChange, onClo
 
 
     // 回填数据
     // 回填数据
     useEffect(() => {
     useEffect(() => {
-        if (value && Object.keys(value).length > 0) {
+        if (value && Object.keys(value).length > 0 && regionsList.length) {
+            let regionsAll = regionsList[0]?.children?.filter((item: any) => !item.disabled)?.map((item: { value: any }) => item.value)//全选省列表
             const {
             const {
                 geoLocation,
                 geoLocation,
                 age,
                 age,
@@ -287,7 +293,6 @@ const AddTarget: React.FC<Props> = ({ isBackVal, value, visible, onChange, onClo
             } = JSON.parse(JSON.stringify(value))
             } = JSON.parse(JSON.stringify(value))
             let targetValues: any = {
             let targetValues: any = {
                 ...surplusValues,
                 ...surplusValues,
-                geoLocation,
                 age: age?.[0] || undefined,
                 age: age?.[0] || undefined,
                 gender: gender?.[0] || '0',
                 gender: gender?.[0] || '0',
                 education: education || '0',
                 education: education || '0',
@@ -299,6 +304,10 @@ const AddTarget: React.FC<Props> = ({ isBackVal, value, visible, onChange, onClo
             }
             }
             if (geoLocation && Object.keys(geoLocation).length > 0) {
             if (geoLocation && Object.keys(geoLocation).length > 0) {
                 targetValues.geoLocationType = '1'
                 targetValues.geoLocationType = '1'
+                targetValues.geoLocation = {
+                    ...geoLocation,
+                    regions: JSON.stringify(geoLocation.regions) === JSON.stringify(regionsAll) ? [1156] : geoLocation.regions
+                }
             } else {
             } else {
                 targetValues.geoLocationType = '0'
                 targetValues.geoLocationType = '0'
                 targetValues.geoLocation = {
                 targetValues.geoLocation = {
@@ -351,7 +360,7 @@ const AddTarget: React.FC<Props> = ({ isBackVal, value, visible, onChange, onClo
 
 
             form.setFieldsValue({ ...targetValues })
             form.setFieldsValue({ ...targetValues })
         }
         }
-    }, [value])
+    }, [value, regionsList])
 
 
     return <Modal
     return <Modal
         title={isBackVal ? <strong style={{ fontSize: 20 }}>
         title={isBackVal ? <strong style={{ fontSize: 20 }}>
@@ -365,6 +374,11 @@ const AddTarget: React.FC<Props> = ({ isBackVal, value, visible, onChange, onClo
         bodyStyle={{ padding: '0 0 40px', position: 'relative', borderRadius: '0 0 8px 8px' }}
         bodyStyle={{ padding: '0 0 40px', position: 'relative', borderRadius: '0 0 8px 8px' }}
         maskClosable={false}
         maskClosable={false}
     >
     >
+        {getTargetingGags.loading && <div style={{ position: 'absolute', width: '100%', top: 0, left: 0, zIndex: 20 }}>
+            <Spin spinning={getTargetingGags.loading}>
+                <div style={{ width: '100%', height: 600, backgroundColor: 'rgba(255,255,255,0.95)' }}></div>
+            </Spin>
+        </div>}
         <Form
         <Form
             form={form}
             form={form}
             name="newAdTarget"
             name="newAdTarget"

+ 44 - 18
src/pages/launchSystemV3/tencentAdPutIn/create/addDynamic.tsx

@@ -13,13 +13,14 @@ import { cartesianProduct, distributeArray } from "@/utils/utils";
 import { columnsAddDynamic } from "./tableConfig";
 import { columnsAddDynamic } from "./tableConfig";
 import { useAjax } from "@/Hook/useAjax";
 import { useAjax } from "@/Hook/useAjax";
 import { createDynamicTaskApi } from "@/services/adqV3";
 import { createDynamicTaskApi } from "@/services/adqV3";
+import TacticsS from "./TacticsS";
 const { Text, Title } = Typography;
 const { Text, Title } = Typography;
 
 
 /**
 /**
  * 新增创意
  * 新增创意
  * @returns 
  * @returns 
  */
  */
-const AddDynamic: React.FC<PULLIN.NewAddDynamic> = ({ visible, onChange, onClose, adData }) => {
+const AddDynamic: React.FC<PULLIN.NewAddDynamic> = ({ visible, onChange, onClose, adData: selectData, tactics }) => {
 
 
     /****************************************/
     /****************************************/
     const [addelivery, setAddelivery] = useState<PULLIN.AddeliveryProps>({ adgroups: {}, targeting: [], dynamic: {}, dynamicMaterialDTos: {}, dynamicCreativesTextDTOS: {}, mediaType: 0 })
     const [addelivery, setAddelivery] = useState<PULLIN.AddeliveryProps>({ adgroups: {}, targeting: [], dynamic: {}, dynamicMaterialDTos: {}, dynamicCreativesTextDTOS: {}, mediaType: 0 })
@@ -31,26 +32,39 @@ const AddDynamic: React.FC<PULLIN.NewAddDynamic> = ({ visible, onChange, onClose
     const [tableData, setTableData] = useState<any>({})
     const [tableData, setTableData] = useState<any>({})
     const [activeKey, setActiveKey] = useState<string>()
     const [activeKey, setActiveKey] = useState<string>()
     const [dynamicCount, setDynamicCount] = useState<number>(0)
     const [dynamicCount, setDynamicCount] = useState<number>(0)
+    const [adData, setAdData] = useState<any[]>(selectData)
 
 
     const createDynamicTask = useAjax((params) => createDynamicTaskApi(params))
     const createDynamicTask = useAjax((params) => createDynamicTaskApi(params))
     /****************************************/
     /****************************************/
 
 
     useEffect(() => {
     useEffect(() => {
-        if (adData?.length > 0) {
-            const { siteSet, marketingCarrierType, marketingGoal, marketingTargetType, sceneSpec, automaticSiteEnabled } = adData[0]
+        if (tactics) {
+            const {
+                adData,
+                addelivery,
+                accountCreateLogs,
+                materialData,
+                textData
+            } = JSON.parse(tactics.strategyValue)
+            setAccountCreateLogs(accountCreateLogs)
+            setAddelivery(addelivery)
+            setAdData(adData)
+            setMaterialData(materialData)
+            setTextData(textData)
+        } else if (selectData?.length > 0) {
+            const { siteSet, marketingCarrierType, marketingGoal, marketingTargetType, sceneSpec, automaticSiteEnabled } = selectData[0]
             setAddelivery({ ...addelivery, adgroups: { marketingGoal, marketingCarrierType, siteSet, automaticSiteEnabled, sceneSpec, marketingAssetOuterSpec: { marketingTargetType } } })
             setAddelivery({ ...addelivery, adgroups: { marketingGoal, marketingCarrierType, siteSet, automaticSiteEnabled, sceneSpec, marketingAssetOuterSpec: { marketingTargetType } } })
-            let AccountSet = new Set(adData.map(item => item.accountId))
+            let AccountSet = new Set(selectData.map(item => item.accountId))
             setAccountCreateLogs([...AccountSet].map(accountId => ({ accountId })))
             setAccountCreateLogs([...AccountSet].map(accountId => ({ accountId })))
         }
         }
-    }, [adData])
+    }, [selectData, tactics])
 
 
     const clearData = () => {
     const clearData = () => {
         setTableData([])
         setTableData([])
     }
     }
 
 
+    // 预览
     const preview = () => {
     const preview = () => {
-        console.log('addelivery------>', addelivery)
-        console.log('accountCreateLogs------>', accountCreateLogs)
         if (accountCreateLogs?.length === 0) {
         if (accountCreateLogs?.length === 0) {
             message.error('请先选择媒体账户')
             message.error('请先选择媒体账户')
             return
             return
@@ -115,15 +129,12 @@ const AddDynamic: React.FC<PULLIN.NewAddDynamic> = ({ visible, onChange, onClose
         // 创意组平均分配到广告逻辑
         // 创意组平均分配到广告逻辑
         let averageAdDynamicList: any[] = []
         let averageAdDynamicList: any[] = []
         if (mediaType === 1 && newDynamicGroup.length) {
         if (mediaType === 1 && newDynamicGroup.length) {
-            let adLength = 0
-            accountCreateLogs.forEach(item => {
-                adLength = adData.length
-                if (adLength > dynamicGroupLength) {
-                    message.error(`创意组分配规则选择创意组平均分配到广告时,创意组总数必须大于等于广告总数。当前创意组数量:${dynamicGroupLength},广告数量:${adLength}`)
-                    return
-                }
-                averageAdDynamicList = distributeArray(newDynamicGroup, adLength)
-            })
+            let adLength = adData.length
+            if (adLength > dynamicGroupLength) {
+                message.error(`创意组分配规则选择创意组平均分配到广告时,创意组总数必须大于等于广告总数。当前创意组数量:${dynamicGroupLength},广告数量:${adLength}`)
+                return
+            }
+            averageAdDynamicList = distributeArray(newDynamicGroup, adLength)
         }
         }
 
 
         adData.forEach((ad, index) => {
         adData.forEach((ad, index) => {
@@ -200,6 +211,7 @@ const AddDynamic: React.FC<PULLIN.NewAddDynamic> = ({ visible, onChange, onClose
         setTableData(newTableData)
         setTableData(newTableData)
     }
     }
 
 
+    // 提交
     const onSubmit = () => {
     const onSubmit = () => {
         const { dynamic, dynamicMaterialDTos, dynamicCreativesTextDTOS, mediaType } = addelivery
         const { dynamic, dynamicMaterialDTos, dynamicCreativesTextDTOS, mediaType } = addelivery
 
 
@@ -290,7 +302,6 @@ const AddDynamic: React.FC<PULLIN.NewAddDynamic> = ({ visible, onChange, onClose
             dynamicMaterialDTOS,
             dynamicMaterialDTOS,
             accountIdParamDTOMap
             accountIdParamDTOMap
         }
         }
-        console.log('----->', params)
         createDynamicTask.run(params).then(res => {
         createDynamicTask.run(params).then(res => {
             if (res) {
             if (res) {
                 message.success('创建任务提交成功')
                 message.success('创建任务提交成功')
@@ -304,7 +315,7 @@ const AddDynamic: React.FC<PULLIN.NewAddDynamic> = ({ visible, onChange, onClose
         visible={visible}
         visible={visible}
         width={1500}
         width={1500}
         onClose={onClose}
         onClose={onClose}
-        bodyStyle={{ backgroundColor: '#f1f4fc', padding: 10 }}
+        bodyStyle={{ backgroundColor: '#f1f4fc', padding: '0 10px 10px' }}
     >
     >
         <Space direction="vertical" style={{ width: '100%' }}>
         <Space direction="vertical" style={{ width: '100%' }}>
             <Spin spinning={false}>
             <Spin spinning={false}>
@@ -362,6 +373,21 @@ const AddDynamic: React.FC<PULLIN.NewAddDynamic> = ({ visible, onChange, onClose
                     </div>
                     </div>
 
 
                     <Space className={style.bts} wrap>
                     <Space className={style.bts} wrap>
+                        <TacticsS strategyValue={{
+                            adData: adData.map(item => {
+                                const { accountId, adgroupName, adgroupId, siteSet, marketingCarrierType, marketingGoal, marketingTargetType, sceneSpec, automaticSiteEnabled } = item
+                                return {
+                                    siteSet, marketingCarrierType, marketingGoal, marketingTargetType, sceneSpec, automaticSiteEnabled,
+                                    accountId,
+                                    adgroupId,
+                                    adgroupName
+                                }
+                            }),
+                            addelivery,
+                            accountCreateLogs,
+                            materialData,
+                            textData
+                        }} />
                         <Button type='primary' onClick={preview}><SearchOutlined />预览广告</Button>
                         <Button type='primary' onClick={preview}><SearchOutlined />预览广告</Button>
                     </Space>
                     </Space>
 
 

+ 10 - 10
src/pages/launchSystemV3/tencentAdPutIn/create/index.tsx

@@ -283,6 +283,7 @@ const Create: React.FC = () => {
         let averageAdDynamicList: any[] = []
         let averageAdDynamicList: any[] = []
         if (mediaType === 1 && newDynamicGroup.length) {
         if (mediaType === 1 && newDynamicGroup.length) {
             let adLength = 0
             let adLength = 0
+            let isReturn = false
             accountCreateLogs.forEach(item => {
             accountCreateLogs.forEach(item => {
                 let productList: any[] = []
                 let productList: any[] = []
                 if (['MARKETING_TARGET_TYPE_FICTION'].includes(marketingAssetOuterSpec?.marketingTargetType)) { // 小说
                 if (['MARKETING_TARGET_TYPE_FICTION'].includes(marketingAssetOuterSpec?.marketingTargetType)) { // 小说
@@ -292,11 +293,14 @@ const Create: React.FC = () => {
                 }
                 }
                 adLength += productList.length * targeting.length
                 adLength += productList.length * targeting.length
                 if (adLength > dynamicGroupLength) {
                 if (adLength > dynamicGroupLength) {
-                    message.error(`创意组分配规则选择创意组平均分配到广告时,创意组总数必须大于等于广告总数。当前创意组数量:${dynamicGroupLength},广告数量:${adLength}`)
-                    return
+                    isReturn = true
                 }
                 }
                 averageAdDynamicList = distributeArray(newDynamicGroup, adLength)
                 averageAdDynamicList = distributeArray(newDynamicGroup, adLength)
             })
             })
+            if (isReturn) {
+                message.error(`创意组分配规则选择创意组平均分配到广告时,创意组总数必须大于等于广告总数。当前创意组数量:${dynamicGroupLength},广告数量:${adLength}`)
+                return
+            }
         }
         }
         let accountIndex = 0
         let accountIndex = 0
         accountCreateLogs.forEach(item => {
         accountCreateLogs.forEach(item => {
@@ -724,17 +728,13 @@ const Create: React.FC = () => {
                         dataSource={tableData[activeKey]}
                         dataSource={tableData[activeKey]}
                         size="small"
                         size="small"
                         bordered
                         bordered
-                        scroll={{ x: 1200 }}
+                        scroll={{ x: 1200, y: 600 }}
                         rowKey={'id'}
                         rowKey={'id'}
                         pagination={{
                         pagination={{
-                            defaultPageSize: 50
+                            defaultPageSize: 50,
+                            total: tableData[activeKey]?.length || 0,
+                            showTotal: (total) => <Tag color="cyan">当前共{total}个创意,{tableData[activeKey]?.length / (tableData[activeKey]?.[0]?.rowSpan)}个广告</Tag>,
                         }}
                         }}
-                    // rowSelection={{
-                    //     selectedRowKeys: tableSelect?.map((item: any) => item?.myId.toString()),
-                    //     onChange: (selectedRowKeys: React.Key[], selectedRows: any) => {
-                    //         setTableSelect(selectedRows)
-                    //     }
-                    // }}
                     />
                     />
                 </div>
                 </div>
             </div> : <div style={{ minHeight: 400, display: 'flex', justifyContent: 'center', alignItems: 'center' }}>
             </div> : <div style={{ minHeight: 400, display: 'flex', justifyContent: 'center', alignItems: 'center' }}>

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

@@ -129,7 +129,21 @@ declare namespace PULLIN {
     type NewAddDynamic = {
     type NewAddDynamic = {
         adData: any[],
         adData: any[],
         visible?: boolean,
         visible?: boolean,
+        tactics?: any,
         onClose?: () => void,
         onClose?: () => void,
         onChange?: () => void
         onChange?: () => void
     }
     }
+    // 策略组
+    type AddV3StrategyProps = {
+        type: string,
+        strategyKey: string,
+        strategyValue: string,
+        remark?: string
+    }
+    type GetV3StrategyListProps = {
+        pageNum: number,
+        pageSize: number,
+        strategyKey?: string,
+        type?: string
+    }
 }
 }

+ 49 - 0
src/services/adqV3/index.ts

@@ -145,4 +145,53 @@ export async function createDynamicTaskApi(data: any) {
         method: 'POST',
         method: 'POST',
         data
         data
     })
     })
+}
+
+
+/************策略组*************/
+/**
+ * 添加策略组
+ * @param data 
+ * @returns 
+ */
+export async function addV3StrategyApi(data: PULLIN.AddV3StrategyProps) {
+    return request(api + `/adq/v3/strategy/add`, {
+        method: 'POST',
+        data
+    })
+}
+
+/**
+ * 策略组更新
+ * @param data 
+ * @returns 
+ */
+export async function editV3StrategyApi(data: PULLIN.AddV3StrategyProps) {
+    return request(api + `/adq/v3/strategy/update`, {
+        method: 'POST',
+        data
+    })
+}
+
+/**
+ * 获取策略组列表
+ * @param params 
+ * @returns 
+ */
+export async function getV3StrategyListApi(params: PULLIN.GetV3StrategyListProps) {
+    return request(api + `/adq/v3/strategy/list`, {
+        method: 'GET',
+        params
+    })
+}
+
+/**
+ * 删除
+ * @param strategyId 
+ * @returns 
+ */
+export async function delV3StrategyApi(strategyId: number) {
+    return request(api + `/adq/v3/strategy/delete/${strategyId}`, {
+        method: 'POST'
+    })
 }
 }