wjx 2 лет назад
Родитель
Сommit
353d28d7ad

+ 2 - 2
config/proxy.ts

@@ -10,8 +10,8 @@
  export default {
   dev: {
     '/api/': {
-      // target: 'http://test.api.zanxiangwl.com/api',
-      target: 'http://api.zanxiangwl.com',
+      target: 'http://test.api.zanxiangwl.com/api',
+      // target: 'http://api.zanxiangwl.com',
       changeOrigin: true,
       pathRewrite: { '/api': '' },
     },

+ 2 - 2
src/pages/launchSystemNew/components/addLandingPage/index.tsx

@@ -1867,7 +1867,7 @@ function AddLandingPage(props: Props) {
                                                                     <div className="adui-form-item" style={{ alignItems: 'center' }}>
                                                                         <Select style={{ width: 180 }} className="aside-select" dropdownClassName="aside-select" onChange={(e) => { setGlobalComponentItem('componentItem', e) }} value={componentItem?.elementType} size="small">
                                                                             <Option value="GH"><FollowAcc />关注公众号</Option>
-                                                                            {/* <Option value="ENTERPRISE_WX"><WxAutoSvg />添加商家微信</Option> */}
+                                                                            <Option value="ENTERPRISE_WX"><WxAutoSvg />添加商家微信</Option>
                                                                         </Select>
                                                                     </div>
                                                                 </div>
@@ -2261,7 +2261,7 @@ function AddLandingPage(props: Props) {
                         <div className={style.assembly}>
                             <div {...getDragPropsCon(`GH`)}> <FollowAcc /> <span className="my">关注公众号</span> </div>
                             {/* <div {...getDragPropsCon(`JumpLink`)}> <JumpLink /> <span className="my">跳转链接</span> </div> */}
-                            {/* <div {...getDragPropsCon(`ENTERPRISE_WX`)}> <WxAutoSvg /> <span className="my">添加商家微信</span> </div> */}
+                            <div {...getDragPropsCon(`ENTERPRISE_WX`)}> <WxAutoSvg /> <span className="my">添加商家微信</span> </div>
                         </div>
                         <div className={style.title}>营销组件</div>
                         <div className={style.assembly}>

+ 4 - 4
src/pages/launchSystemNew/components/crowdPackModal/index.tsx

@@ -63,11 +63,11 @@ const CrowdPackModal: React.FC<Props> = (props) => {
     }
 
     // 获取人群包列表
-    const getList = (params: number[]) => {
-        getCrowdPack.run(params).then(res => {
+    const getList = (accountIds: number[]) => {
+        getCrowdPack.run({ accountIds }).then(res => {
             console.log('res===>', res)
-            if (res && Object.keys(res)?.indexOf(params[0].toString()) !== -1) {
-                setTableData(res[params[0]]?.map((item: { audienceId: string }) => ({ ...item, id: item.audienceId })))
+            if (res && Object.keys(res)?.indexOf(accountIds[0].toString()) !== -1) {
+                setTableData(res[accountIds[0]]?.map((item: { audienceId: string }) => ({ ...item, id: item.audienceId })))
             } else {
                 setTableData([])
             }

+ 5 - 5
src/pages/launchSystemNew/components/customerServiceModal/index.tsx

@@ -25,7 +25,7 @@ const CustomerServiceModal: React.FC<Props> = (props) => {
     const [data, setData] = useState<any>(data1)
     const [visible, setVisible] = useState<boolean>(false)
     const [sysVisible, setSysVisible] = useState<boolean>(false)
-    const [cropId, setCropId] = useState<string>('')
+    const [corpId, setCorpId] = useState<string>('')
     const [notConfigured, setNotConfigured] = useState<any>([])
 
     const getCropWechat = useAjax((params) => getCropWechatApi(params))
@@ -88,9 +88,9 @@ const CustomerServiceModal: React.FC<Props> = (props) => {
 
     /** 同步 */
     const handleSys = () => {
-        if (cropId) {
-            console.log(data[selectAdz - 1].id, cropId);
-            sysCropWechat.run({ accountId: data[selectAdz - 1].id, cropId: cropId }).then(res => {
+        if (corpId) {
+            console.log(data[selectAdz - 1].id, corpId);
+            sysCropWechat.run({ accountId: data[selectAdz - 1].id, corpId: corpId }).then(res => {
                 if (res) {
                     getList([data[selectAdz - 1].adAccountId])
                     message.success('同步成功')
@@ -160,7 +160,7 @@ const CustomerServiceModal: React.FC<Props> = (props) => {
 
         {/* 输入企业微信ID同步 */}
         {sysVisible && <Modal title="输入企业微信ID同步" visible={sysVisible} onOk={handleSys} onCancel={() => setSysVisible(false)} okText='同步' confirmLoading={sysCropWechat.loading}>
-            <Input value={cropId} onChange={(e) => setCropId(e.target.value)} placeholder='输入企业微信ID同步' />
+            <Input value={corpId} onChange={(e) => setCorpId(e.target.value)} placeholder='输入企业微信ID同步' />
         </Modal>}
     </div>
 }

+ 3 - 3
src/pages/launchSystemNew/components/customerServiceModal/tableConfig.tsx

@@ -30,9 +30,9 @@ let columns = () => [
         }
     },
     {
-        title: 'cropId',
-        dataIndex: 'cropId',
-        key: 'cropId',
+        title: 'corpId',
+        dataIndex: 'corpId',
+        key: 'corpId',
         align: 'center',
         ellipsis: true,
         render: (a: any, b: any) => {

+ 197 - 0
src/pages/launchSystemNew/components/expandModal/index.tsx

@@ -0,0 +1,197 @@
+import { useAjax } from "@/Hook/useAjax"
+import { getCrowdPackApi, sysCrowdPackApi } from "@/services/launchAdq/createAd"
+import { Button, Checkbox, Input, message, Modal, Space, Switch } from "antd"
+import React, { useEffect, useState } from "react"
+import style from '../goodsModal/index.less'
+import columns from "../crowdPackModal/tableConfig"
+import { CheckOutlined, SyncOutlined } from "@ant-design/icons"
+import Tables from "@/components/Tables"
+
+/**
+ * 自动扩量设置
+ * @returns 
+ */
+interface Props {
+    visible?: boolean,
+    onClose?: () => void,
+    onChange?: (data: any, expandData: { expandEnabled: boolean, expandTargeting: string[] }) => void,
+    data: any,
+    sysTargeting: any,
+    expandData?: { expandEnabled: boolean, expandTargeting: string[] }
+}
+const ExpandModal: React.FC<Props> = (props) => {
+
+    /******************************/
+    const { visible, onClose, data: data1, onChange, sysTargeting, expandData } = props
+    const [data, setData] = useState<any>(data1)
+    const [tableData, setTableData] = useState<any[]>([])//table数据
+    const [selectAdz, setSelectAdz] = useState<number>(1)   // 选择账户
+    const [name, setName] = useState<string>('')
+    const [disabledList, setDisabledList] = useState<boolean[]>([true, true, true, true])
+    const [queryForm, setQueryForm] = useState<{ expandEnabled: boolean, expandTargeting: string[] }>(expandData || { expandEnabled: false, expandTargeting: [] })
+
+    const getCrowdPack = useAjax((params) => getCrowdPackApi(params))
+    const sysCrowdPack = useAjax((params) => sysCrowdPackApi(params))
+    /******************************/
+
+    useEffect(() => {
+        if (sysTargeting && sysTargeting?.targeting) {
+            let newDisabledList: boolean[] = [true, true, true, true]
+            Object.keys(sysTargeting?.targeting)?.forEach((item: any) => {
+                switch (item) {
+                    case 'geoLocation': // 地域
+                        if (sysTargeting?.targeting[item]?.regions && sysTargeting?.targeting[item]?.regions?.length > 0) {
+                            newDisabledList[0] = false
+                        }
+                        break
+                    case 'age':
+                        newDisabledList[1] = false
+                        break
+                    case 'gender':
+                        newDisabledList[2] = false
+                        break
+                    case 'education':
+                        newDisabledList[3] = false
+                        break
+                }
+            })
+            setDisabledList(newDisabledList)
+        }
+    }, [sysTargeting])
+
+    useEffect(() => {
+        // customAudienceList?: any, excludedCustomAudienceList?: any
+        if (data?.length > 0) {
+            getList([data[selectAdz - 1].adAccountId])
+        } else {
+            setTableData([])
+        }
+    }, [selectAdz])
+
+    // 同步种子人群
+    const synGoodsList = () => {
+        sysCrowdPack.run(data?.map((item: { id: number }) => item?.id)).then(res => {
+            getList([data[selectAdz - 1].adAccountId])
+        })
+    }
+
+    // 获取人群包列表
+    const getList = (accountIds: number[]) => {
+        getCrowdPack.run({ accountIds, source: 'ADVERTISER_OWN_DATA' }).then(res => {
+            if (res && Object.keys(res)?.indexOf(accountIds[0].toString()) !== -1) {
+                setTableData(res[accountIds[0]]?.map((item: { audienceId: string }) => ({ ...item, id: item.audienceId })))
+            } else {
+                setTableData([])
+            }
+        })
+    }
+
+    const handleOk = () => {
+        onChange && onChange(data, queryForm)
+    }
+
+    /** 表格选折 */
+    const onChangeTable = (selectedRowKeys: React.Key[], selectedRows: any[]) => {
+        if (selectedRows?.length > 10) {
+            message.error('扩量种子人群最多选择10个')
+            return
+        }
+        console.log('11111111111111');
+        
+        let newData = JSON.parse(JSON.stringify(data))
+        newData[selectAdz - 1]['coldStartAudienceList'] = selectedRows
+        setData([...newData])
+    }
+
+    /** 设置选中广告主 */
+    const handleSelectAdz = (value: number, item: any) => {
+        if (value === selectAdz) {
+            return
+        }
+        setSelectAdz(value)
+    }
+
+    console.log('data---->', data);
+
+
+    return <Modal
+        title={<Space>
+            <span>自动扩量</span>
+            <Button size="small" onClick={() => { synGoodsList() }} type="link" loading={sysCrowdPack.loading}>同步扩量种子人群</Button>
+        </Space>}
+        visible={visible}
+        onCancel={() => { onClose && onClose() }}
+        onOk={handleOk}
+        width={1100}
+        className={style.SelectPackage}
+        bodyStyle={{ padding: '0 10px 0 10px' }}
+    >
+        <div className={style.topContent} style={{ paddingBottom: queryForm.expandEnabled ? 4 : 20 }}>
+            <Space direction='vertical'>
+                <Space>
+                    <strong className={style.title}>自动扩量:</strong>
+                    <Switch onChange={(e) => {
+                        setQueryForm({ ...queryForm, expandEnabled: e, expandTargeting: [] });
+                        if (!e) {
+                            let newData = JSON.parse(JSON.stringify(data))
+                            newData = newData?.map((item: { coldStartAudienceList: any}) => {
+                                return { ...item, coldStartAudienceList: [] }
+                            })
+                            setData([...newData])
+                        }
+                    }} checked={queryForm.expandEnabled} checkedChildren="开启" unCheckedChildren="关闭" />
+                </Space>
+                {queryForm.expandEnabled && <>
+                    <Space>
+                        <strong className={style.title}>不可突破定向:</strong>
+                        <Checkbox.Group style={{ width: '100%' }} onChange={(e) => { setQueryForm({ ...queryForm, expandTargeting: e as string[] }) }} value={queryForm.expandTargeting} >
+                            <Checkbox value="geo_location" disabled={disabledList[0]}>地域</Checkbox>
+                            <Checkbox value="age" disabled={disabledList[1]}>年龄</Checkbox>
+                            <Checkbox value="gender" disabled={disabledList[2]}>性别</Checkbox>
+                            <Checkbox value="education" disabled={disabledList[3]}>学历</Checkbox>
+                        </Checkbox.Group>
+                    </Space>
+                    <Space>
+                        <strong className={style.title}>扩量种子人群(选填):</strong>
+                    </Space>
+                </>}
+            </Space>
+        </div>
+        {queryForm.expandEnabled && <div className={style.content} style={{ borderTop: '1px solid #f0f0f0' }}>
+            <div className={style.left}>
+                <h4 className={style.title}>媒体账户</h4>
+                {data?.map((item: { adAccountId: number, id: number }, index: number) => (
+                    <div key={index} onClick={() => { handleSelectAdz(index + 1, item) }} className={`${style.accItem} ${selectAdz === index + 1 && style.select} `}>
+                        {item?.adAccountId}
+                        {data[index]['coldStartAudienceList']?.length > 0 && <CheckOutlined style={{ color: '#1890ff' }} />}
+                    </div>))}
+            </div>
+            <div className={style.right}>
+                <Space style={{ marginBottom: 10 }}>
+                    <Input placeholder="请输入用户群名称" allowClear value={name} onChange={(e) => setName(e.target.value)} />
+                    <Button icon={<SyncOutlined />} type='link' loading={getCrowdPack?.loading} onClick={() => { getList([data[selectAdz - 1].adAccountId]) }}></Button>
+                </Space>
+                <Tables
+                    columns={columns()}
+                    dataSource={tableData?.filter((item: { name: string }) => name ? item.name.indexOf(name) !== -1 : true)}
+                    size="small"
+                    loading={getCrowdPack?.loading}
+                    scroll={{ y: 300 }}
+                    bordered
+                    defaultPageSize={100}
+                    rowSelection={{
+                        type: 'checkbox',
+                        selectedRowKeys: data[selectAdz - 1]['coldStartAudienceList']?.map((item: any) => item?.id?.toString()),
+                        onChange: onChangeTable,
+                        getCheckboxProps: (record: any) => ({
+                            id: record.id,
+                        })
+                    }}
+                />
+            </div>
+        </div>}
+    </Modal>
+}
+
+
+export default React.memo(ExpandModal)

+ 8 - 0
src/pages/launchSystemNew/components/goodsModal/index.less

@@ -1,4 +1,12 @@
 .SelectPackage{
+    .topContent {
+        padding: 20px 10px 4px;
+
+        .title {
+            width: 135px;
+            display: inline-block;
+        }
+    }
     .content{
         width: 100%;
         display: flex;

+ 30 - 16
src/pages/launchSystemNew/launchManage/createAd/index.tsx

@@ -46,8 +46,10 @@ const CreateAd: React.FC = () => {
         taskMediaMaps: [], // 创意内容
         pageList: [],//本地落地页详情入口
         adqPageList: [],//云落地页
+        expandEnabled: false,
+        expandTargeting: []
     })
-    const [accountCreateLogs, setAccountCreateLogs] = useState<{ adAccountId: number, id: number, userActionSetsList?: number, productList?: any, conversionList?: any, customAudienceList?: any, excludedCustomAudienceList?: any, pageList?: any }[]>([])  // 账户
+    const [accountCreateLogs, setAccountCreateLogs] = useState<{ adAccountId: number, id: number, userActionSetsList?: number, productList?: any, conversionList?: any, customAudienceList?: any, excludedCustomAudienceList?: any, pageList?: any, coldStartAudienceList?: any[] }[]>([])  // 账户
     const { currentUser: { userId } }: any = useModel('@@initialState', model => ({ currentUser: model.initialState?.currentUser }))
 
     const [goodsVisible, setGoodsVisible] = useState<boolean>(false) // 选择商品弹窗控制
@@ -216,27 +218,27 @@ const CreateAd: React.FC = () => {
         let newtaskMediaMaps = newQueryForm.taskMediaMaps.map((item1: { cropUserGroupMap?: any[] }) => {
             let { cropUserGroupMap, ...data } = item1
             if (cropUserGroupMap && cropUserGroupMap?.length > 0) {
-                let cropUserGroup1Map: any = {}
-                let cropUserGroup2Map: any = {}
+                let corpUserGroup1Map: any = {}
+                let corpUserGroup2Map: any = {}
                 cropUserGroupMap.forEach((cropData: { id: number, data: any[] }) => {
-                    let cropData1: { cropId: string, groupId: number }[] = []
-                    let cropData2: { cropId: string, groupId: number }[] = []
-                    cropData?.data.forEach((crop: { type: 1 | 2, cropList: { cropId: string, groupId: number }[] }) => {
+                    let cropData1: { corpId: string, groupId: number }[] = []
+                    let cropData2: { corpId: string, groupId: number }[] = []
+                    cropData?.data.forEach((crop: { type: 1 | 2, cropList: { corpId: string, groupId: number }[] }) => {
                         let cropList = crop.cropList
                         if (crop.type === 1) {
-                            cropData1.push({ cropId: cropList[0].cropId, groupId: cropList[0].groupId })
+                            cropData1.push({ corpId: cropList[0].corpId, groupId: cropList[0].groupId })
                         } else {
-                            cropData2.push({ cropId: cropList[0].cropId, groupId: cropList[0].groupId })
+                            cropData2.push({ corpId: cropList[0].corpId, groupId: cropList[0].groupId })
                         }
                     })
                     if (cropData1.length > 0) {
-                        cropUserGroup1Map[cropData.id.toString()] = cropData1
+                        corpUserGroup1Map[cropData.id.toString()] = cropData1
                     }
                     if (cropData2.length > 0) {
-                        cropUserGroup2Map[cropData.id.toString()] = cropData2
+                        corpUserGroup2Map[cropData.id.toString()] = cropData2
                     }
                 })
-                return { ...data, cropUserGroup1Map: Object.keys(cropUserGroup1Map)?.length > 0 ? cropUserGroup1Map : null, cropUserGroup2Map: Object.keys(cropUserGroup2Map)?.length > 0 ? cropUserGroup2Map : null }
+                return { ...data, corpUserGroup1Map: Object.keys(corpUserGroup1Map)?.length > 0 ? corpUserGroup1Map : null, corpUserGroup2Map: Object.keys(corpUserGroup2Map)?.length > 0 ? corpUserGroup2Map : null }
             }
             return data
         })
@@ -262,8 +264,17 @@ const CreateAd: React.FC = () => {
             if (item?.pageList) {
                 data.pageId = item?.pageData?.id
             }
+            if (item?.coldStartAudienceList?.length > 0) {
+                data.coldStartAudience = item?.coldStartAudienceList?.map((item: any) => item.id)
+            }
             return data
         })
+        if (params?.expandEnabled) {
+            params.sysAdgroup.expandEnabled = params?.expandEnabled
+        }
+        if (params?.expandTargeting?.length > 0) {
+            params.sysAdgroup.expandTargeting = params?.expandTargeting
+        }
         params.accountCreateLogs = accountLogs
         delete params.sysAdgroupId
         delete params.sysAdcreativeId
@@ -271,7 +282,10 @@ const CreateAd: React.FC = () => {
         delete params.pageList
         delete params.adqPageList
         delete params.count
+        delete params?.expandEnabled
+        delete params?.expandTargeting
         console.log('paramsSubmit====>', params)
+
         createAdBatch.run(params).then(res => {
             if (res) {
                 sessionStorage.setItem('CAMP', props?.campaignName)
@@ -311,14 +325,14 @@ const CreateAd: React.FC = () => {
             adgroupName: undefined,  // 广告名称
             configuredStatus: 'AD_STATUS_SUSPEND',  // 广告状态
             sysAdcreativeId: undefined, // 创意ID
+            expandEnabled: false,
+            expandTargeting: []
         })
     }
     /** 设置落地页 */
     const setPage = (e: any) => {
-        console.log('设置落地页=>', e[0].pageSpecsList[0].pageElementsSpecList[0])
         let arr: any = queryForm.taskMediaMaps || []
         function setUrl(item: { sysAdcreative: { overrideCanvasHeadOption: string, adcreativeElements: any } }) {
-            console.log('item====>', item)
             if (item?.sysAdcreative?.overrideCanvasHeadOption && item?.sysAdcreative?.overrideCanvasHeadOption === "OPTION_CANVAS_OVERRIDE_CREATIVE") {
                 let adcreativeElementsNew = { ...item.sysAdcreative.adcreativeElements }
                 let obj = e[0].pageSpecsList[0].pageElementsSpecList[0]
@@ -344,7 +358,6 @@ const CreateAd: React.FC = () => {
             return { ...item, sysPageId: e[0]?.id, accountPageIdMap: null, }
         }
         if (page_checked) {
-            console.log('queryForm.taskMediaMaps', queryForm.taskMediaMaps)
             arr = queryForm.taskMediaMaps?.map(item => {
                 return setUrl(item)
             })
@@ -432,6 +445,7 @@ const CreateAd: React.FC = () => {
     }, [])
 
     console.log('queryForm111111', queryForm);
+
     return <Space direction="vertical" style={{ width: '100%' }}>
         <Card
             title={<div className={style.cardTitle}>配置区</div>}
@@ -653,7 +667,7 @@ const CreateAd: React.FC = () => {
                                 <div className={style.bottom}>{
                                     (queryForm?.taskMediaMaps && queryForm?.taskMediaMaps[targetKey]?.sysAdcreative) ? <>
                                         {queryForm?.taskMediaMaps && queryForm?.taskMediaMaps[targetKey]?.sysPageId && <Button type="link" onClick={() => { setLookVisible(true) }}>查看</Button>}
-                                        {queryForm?.promotedObjectType !== 'PROMOTED_OBJECT_TYPE_LEAD_AD' && <Button type="link" onClick={() => {
+                                        <Button type="link" onClick={() => {
                                             setSelectImgVisible(true)
                                             // 判定是否用原生页顶部替换外部素材
                                             if (queryForm?.taskMediaMaps && queryForm?.taskMediaMaps[targetKey]?.sysAdcreative?.overrideCanvasHeadOption === 'OPTION_CANVAS_OVERRIDE_CREATIVE') {
@@ -661,7 +675,7 @@ const CreateAd: React.FC = () => {
                                             } else {
                                                 init({ mediaType: 'PAGE', cloudSize: undefined })
                                             }
-                                        }}>{queryForm?.taskMediaMaps && queryForm?.taskMediaMaps[targetKey]?.sysPageId ? '修改' : '选择落地页'}</Button>}
+                                        }}>{queryForm?.taskMediaMaps && queryForm?.taskMediaMaps[targetKey]?.sysPageId ? '修改' : '选择落地页'}</Button>
                                         
                                         {accountCreateLogs?.length > 0 ? <Button type="link" onClick={() => {
                                             setPageVisible(true)

+ 109 - 44
src/pages/launchSystemNew/launchManage/createAd/targeting/index.tsx

@@ -1,14 +1,16 @@
 import { CreateAdProps } from "@/services/launchAdq/createAd"
 import { BaseResult } from "@ahooksjs/use-request/lib/types"
-import { CloseOutlined } from "@ant-design/icons"
-import { Button, Col, Empty, Popover, Space, Spin, Tooltip } from "antd"
-import React, { useCallback, useState } from "react"
+import { CloseOutlined, DownOutlined } from "@ant-design/icons"
+import { Button, Col, Dropdown, Empty, Menu, Popover, Space, Spin, Tooltip } from "antd"
+import React, { useCallback, useEffect, useState } from "react"
 import TargetingModal from "../../../components/targetingModal"
 import TargetingPup from "./modal"
 import TargetingTooltip from "../../../components/targetingTooltip"
 import CrowdPackModal from "../../../components/crowdPackModal"
 import style from '../index.less'
 import { ModalConfig } from "./modal"
+import ExpandModal from "@/pages/launchSystemNew/components/expandModal"
+import { ExpandTargeting } from "@/services/launchAdq/enum"
 type Props = {
     queryForm: Partial<CreateAdProps>,
     setQueryForm: React.Dispatch<React.SetStateAction<Partial<CreateAdProps>>>,
@@ -38,6 +40,7 @@ function TargetIng(props: Props) {
     })
     const [dxVisible, setDxVisible] = useState<boolean>(false) // 选择定向弹窗控制
     const [cpVisible, setCpVisible] = useState<boolean>(false) // 选择设置名称弹窗控制
+    const [expandVisible, setExpandVisible] = useState<boolean>(false) // 自动扩量弹窗控制
 
     // 设置变量
     const handleAdModalConfig = useCallback((arg: ModalConfig) => {
@@ -51,15 +54,39 @@ function TargetIng(props: Props) {
             clearData()
         })
     }, [queryForm])
+
     return <Col className={style.conRightBorder}>
         <div className={style.top}>
             定向
             {/* (queryForm.sysAdgroup?.bidMode === 'BID_MODE_CPM' || queryForm.sysAdgroup?.bidMode === 'BID_MODE_CPC') &&  */}
-            {<>{
-                accountCreateLogs?.length > 0 && queryForm?.sysTargeting ? <Button type="link" style={{ fontSize: 12, padding: 0 }} onClick={() => setCpVisible(true)}>选择定向包</Button> : <Tooltip title={accountCreateLogs?.length > 0 ? `请先添加定向` : `请先选择媒体账户`}>
-                    <Button type="link" style={{ fontSize: 12, padding: 0 }}>选择定向包</Button>
-                </Tooltip>
-            }</>}
+            <Dropdown
+                overlay={<Menu style={{ padding: 0 }} items={[
+                    {
+                        key: '1',
+                        label: <>
+                            {accountCreateLogs?.length > 0 && queryForm?.sysTargeting ? <Button type="link" style={{ fontSize: 12, padding: 0 }} onClick={() => setCpVisible(true)}>选择定向包</Button> : <Tooltip title={accountCreateLogs?.length > 0 ? `请先添加定向` : `请先选择媒体账户`}>
+                                <Button type="link" style={{ fontSize: 12, padding: 0 }}>选择定向包</Button>
+                            </Tooltip>}
+                        </>
+                    },
+                    {
+                        key: '2',
+                        label: <>
+                            {accountCreateLogs?.length > 0 && queryForm?.sysTargeting ? <Button type="link" style={{ fontSize: 12, padding: 0 }} onClick={() => setExpandVisible(true)}>自动扩量</Button> : <Tooltip title={accountCreateLogs?.length > 0 ? `请先添加定向` : `请先选择媒体账户`}>
+                                <Button type="link" style={{ fontSize: 12, padding: 0 }}>自动扩量</Button>
+                            </Tooltip>}
+                        </>
+                    }
+                ]} />}
+            >
+                <a onClick={e => e.preventDefault()}>
+                    <Space>
+                        扩展
+                        <DownOutlined />
+                    </Space>
+                </a>
+            </Dropdown>
+
             {queryForm.sysTargeting && <a onClick={() => {
                 setQueryForm({ ...queryForm, sysTargeting: undefined, sysTargetingId: undefined })
                 setAccountCreateLogs([])
@@ -69,40 +96,19 @@ function TargetIng(props: Props) {
             <Spin spinning={getsysTargeting.loading}>
                 <div className={style.centerContent}>
                     {queryForm?.sysTargeting ? <>
-                        {accountCreateLogs?.some((item: any) => item?.customAudienceList?.length > 0) ?
-                         <>
-                            {queryForm.sysTargeting && <Popover
-                                content={<div className={style.popover}>
-                                    <TargetingTooltip data={queryForm.sysTargeting} geoLocationList={geoLocationList} modelList={modelList} />
-                                </div>}
-                                trigger="hover"
-                                placement="right"
-                            >
-                                <div className={style.popoverContent}>
-                                    <div><strong>定向名称:</strong> <span style={{color:"#5a5a5a"}}>{queryForm?.sysTargeting?.targetingName}</span></div>
-                                    <div><strong>定向描述:</strong> <span style={{color:"#5a5a5a"}}>{queryForm?.sysTargeting?.description || '<空>'}</span></div>
-                                </div>
-                            </Popover>}
+                        {queryForm.expandEnabled && <div className={style.popoverContent}>
+                            <div><strong>自动扩量:</strong> <span style={{ color: "#5a5a5a" }}>开启</span></div>
+                            <div><strong>不可突破定向:</strong> <span style={{ color: "#5a5a5a" }}>{queryForm?.expandTargeting?.map(item => ExpandTargeting[item]).toString() || '无'}</span></div>
                             {accountCreateLogs?.map((item: any, index: number) => {
-                                if (item?.customAudienceList) {
+                                if (item?.coldStartAudienceList) {
                                     return <div className={style.acc} key={index}>
                                         <div className={style.accName} style={{ fontWeight: 800 }}>{item.adAccountId}</div>
-                                        {item?.customAudienceList?.length > 0 && <>
-                                            <div className={style.accName}>定向用户群</div>
-                                            {
-                                                item?.customAudienceList?.map((pack: { name: string, id: number }, index1: number) => {
-                                                    return <div className={style.accCon} key={pack.id}>{pack.name}<CloseOutlined className={style.close} onClick={() => {
-                                                        cpDel(index, index1, 'customAudienceList')
-                                                    }} /></div>
-                                                })
-                                            }
-                                        </>}
-                                        {item?.excludedCustomAudienceList?.length > 0 && <>
-                                            <div className={style.accName} style={{ marginTop: 5 }}>排除用户群</div>
+                                        {item?.coldStartAudienceList?.length > 0 && <>
+                                            <div className={style.accName}>扩量种子人群</div>
                                             {
-                                                item?.excludedCustomAudienceList?.map((pack: { name: string, id: number }, index1: number) => {
+                                                item?.coldStartAudienceList?.map((pack: { name: string, id: number }, index1: number) => {
                                                     return <div className={style.accCon} key={pack.id}>{pack.name}<CloseOutlined className={style.close} onClick={() => {
-                                                        cpDel(index, index1, 'excludedCustomAudienceList')
+                                                        cpDel(index, index1, 'coldStartAudienceList')
                                                     }} /></div>
                                                 })
                                             }
@@ -112,13 +118,58 @@ function TargetIng(props: Props) {
                                     return null
                                 }
                             })}
-                        </> 
-                        : 
-                        <>
-                            <div><strong>定向名称:</strong> <span style={{color:"#5a5a5a"}}>{queryForm?.sysTargeting?.targetingName}</span></div>
-                            <div><strong>定向描述:</strong> <span style={{color:"#5a5a5a"}}>{queryForm?.sysTargeting?.description || '<空>'}</span></div>
-                            <TargetingTooltip data={queryForm?.sysTargeting} geoLocationList={geoLocationList} modelList={modelList} />
-                        </>}
+                        </div>}
+
+                        {accountCreateLogs?.some((item: any) => item?.customAudienceList?.length > 0) ?
+                            <>
+                                {queryForm.sysTargeting && <Popover
+                                    content={<div className={style.popover}>
+                                        <TargetingTooltip data={queryForm.sysTargeting} geoLocationList={geoLocationList} modelList={modelList} />
+                                    </div>}
+                                    trigger="hover"
+                                    placement="right"
+                                >
+                                    <div className={style.popoverContent}>
+                                        <div><strong>定向名称:</strong> <span style={{ color: "#5a5a5a" }}>{queryForm?.sysTargeting?.targetingName}</span></div>
+                                        <div><strong>定向描述:</strong> <span style={{ color: "#5a5a5a" }}>{queryForm?.sysTargeting?.description || '<空>'}</span></div>
+                                    </div>
+                                </Popover>}
+                                {accountCreateLogs?.map((item: any, index: number) => {
+                                    if (item?.customAudienceList) {
+                                        return <div className={style.acc} key={index}>
+                                            <div className={style.accName} style={{ fontWeight: 800 }}>{item.adAccountId}</div>
+                                            {item?.customAudienceList?.length > 0 && <>
+                                                <div className={style.accName}>定向用户群</div>
+                                                {
+                                                    item?.customAudienceList?.map((pack: { name: string, id: number }, index1: number) => {
+                                                        return <div className={style.accCon} key={pack.id}>{pack.name}<CloseOutlined className={style.close} onClick={() => {
+                                                            cpDel(index, index1, 'customAudienceList')
+                                                        }} /></div>
+                                                    })
+                                                }
+                                            </>}
+                                            {item?.excludedCustomAudienceList?.length > 0 && <>
+                                                <div className={style.accName} style={{ marginTop: 5 }}>排除用户群</div>
+                                                {
+                                                    item?.excludedCustomAudienceList?.map((pack: { name: string, id: number }, index1: number) => {
+                                                        return <div className={style.accCon} key={pack.id}>{pack.name}<CloseOutlined className={style.close} onClick={() => {
+                                                            cpDel(index, index1, 'excludedCustomAudienceList')
+                                                        }} /></div>
+                                                    })
+                                                }
+                                            </>}
+                                        </div>
+                                    } else {
+                                        return null
+                                    }
+                                })}
+                            </>
+                            :
+                            <>
+                                <div><strong>定向名称:</strong> <span style={{ color: "#5a5a5a" }}>{queryForm?.sysTargeting?.targetingName}</span></div>
+                                <div><strong>定向描述:</strong> <span style={{ color: "#5a5a5a" }}>{queryForm?.sysTargeting?.description || '<空>'}</span></div>
+                                <TargetingTooltip data={queryForm?.sysTargeting} geoLocationList={geoLocationList} modelList={modelList} />
+                            </>}
 
 
                     </> : <Empty image={Empty.PRESENTED_IMAGE_SIMPLE} />}
@@ -135,6 +186,20 @@ function TargetIng(props: Props) {
         {dxVisible && <TargetingModal visible={dxVisible} onClose={() => setDxVisible(false)} onChange={getInfo} sysTargetingId={queryForm?.sysTargetingId} />}
         {/* 选择定向包 */}
         {cpVisible && <CrowdPackModal visible={cpVisible} data={accountCreateLogs} onClose={() => setCpVisible(false)} onChange={(e) => { setAccountCreateLogs(e); setCpVisible(false); clearData() }} />}
+        {/* 设置自动扩量 */}
+        {expandVisible && <ExpandModal
+            visible={expandVisible}
+            sysTargeting={queryForm.sysTargeting}
+            expandData={{ expandEnabled: queryForm.expandEnabled || false, expandTargeting: queryForm.expandTargeting || [] }}
+            data={accountCreateLogs}
+            onClose={() => setExpandVisible(false)}
+            onChange={(e, expandData) => {
+                setAccountCreateLogs(e);
+                setQueryForm({ ...queryForm, ...expandData })
+                setExpandVisible(false)
+                clearData()
+            }}
+        />}
         {/* 新建定向包 */}
         {adModalConfig.visible && <TargetingPup visible={adModalConfig.visible} PupFn={handleAdModalConfig} callback={(values: any) => {
             setQueryForm({ ...queryForm, sysTargeting: values, }); setDxVisible(false); clearData();

+ 2 - 2
src/services/api.ts

@@ -1,5 +1,5 @@
-// export let api: any = process.env.NODE_ENV === 'development' ? 'api' : 'http://test.api.zanxiangwl.com/api'
-export let api: any = process.env.NODE_ENV === 'development' ? 'api' : 'http://api.zanxiangwl.com'
+export let api: any = process.env.NODE_ENV === 'development' ? 'api' : 'http://test.api.zanxiangwl.com/api'
+// export let api: any = process.env.NODE_ENV === 'development' ? 'api' : 'http://api.zanxiangwl.com'
 export let dataApi: any = process.env.NODE_ENV === 'development' ? 'dapi' : `http://data.zanxiangnet.com`
 export let wxApi: any = process.env.NODE_ENV === 'development' ? 'wxapi' : `https://report.zanxiangwl.com`
 export let launchApi: any = `http://192.168.7.175:8018`

+ 6 - 4
src/services/launchAdq/createAd.ts

@@ -26,6 +26,8 @@ export interface CreateAdProps {
   firstDayBeginTime?: string,  //hh:mm:ss 开始时间
   endDate?: string, // 结束日期
   bidAmount?: number, // 出价
+  expandEnabled?: boolean,  // 自动扩量
+  expandTargeting?: string[], // 扩量不可突破定向
   accountCreateLogs: {
     adAccountId: number, // 媒体账户ID
     userActionSets?: {
@@ -125,7 +127,7 @@ export async function sysIdApi(data: number[]) {
  * @param data 
  * @returns 
  */
-export async function getCrowdPackApi(data: number[]) {
+export async function getCrowdPackApi(data: { accountIds: number[], source?: string }) {
   return request(api + `/adq/customAudiences/allByAccount`, {
     method: 'POST',
     data
@@ -153,7 +155,7 @@ export async function sysCrowdPackApi(data: number[]) {
  * @returns 
  */
 export async function getCropWechatApi(data: number[]) {
-  return request(api + `/adq/cropWechatCsgroup/allByAccount`, {
+  return request(api + `/adq/corpWechatCsgroup/allByAccount`, {
     method: 'POST',
     data
   })
@@ -165,8 +167,8 @@ export async function getCropWechatApi(data: number[]) {
  * @param data 
  * @returns 
  */
-export async function sysCropWechatApi({ accountId, cropId }: { accountId: number, cropId: number }) {
-  return request(api + `/adq/cropWechatCsgroup/syncByAccount/${accountId}/${cropId}`, {
+export async function sysCropWechatApi({ accountId, corpId }: { accountId: number, corpId: number }) {
+  return request(api + `/adq/cropWechatCsgroup/syncByAccount/${accountId}/${corpId}`, {
     method: 'POST'
   })
 }

+ 8 - 0
src/services/launchAdq/enum.ts

@@ -519,4 +519,12 @@ export enum GoalRoasEnum {
   GOAL_30DAY_ORDER_ROAS = '下单ROI',
   GOAL_1DAY_PURCHASE_ROAS = '首日付费 ROI',
   GOAL_1DAY_MONETIZATION_ROAS = '	首日变现 ROI'
+}
+
+
+export enum ExpandTargeting {
+  'geo_location' = '地域',
+  'age' = '年龄',
+  'gender' = '性别',
+  'education' = '学历'
 }