shenwu há 2 anos atrás
pai
commit
a732470c61

+ 1 - 1
src/Hook/useAjax.tsx

@@ -49,7 +49,7 @@ export function useAjax(fnc: CombineService<any, any>, options?: Options){
         // throttleInterval:500,
         formatResult: (res) => {
             let reqTime = moment().format('YYYY-MM-DD HH:mm:ss')
-            return options?.formatResult ? {...res,reqTime} : res.data
+            return options?.formatResult ? {...res,reqTime} : {...res.data,reqTime}
         },
         onSuccess: (res) => {
             if (res) {

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

@@ -139,14 +139,14 @@ function TableData(props: Prosp) {
                             <Tooltip title='刷新'><RedoOutlined /></Tooltip>
                         </Button>
                     }
-                    <Button
+                   {config && <Button
                         size='small'
                         type='text'
                         onClick={() => {
                             setVisible(true)
                         }}>
                         <Tooltip title='设置'><SettingOutlined /></Tooltip>
-                    </Button>
+                    </Button>}
                     <Button
                         type='text'
                         size='small'

+ 81 - 24
src/pages/launchSystemNew/launchManage/localAd/ad/index.tsx

@@ -1,42 +1,63 @@
 import { FnAjax, useAjax } from '@/Hook/useAjax'
 import { ListData, SysAdgroupsDTO } from '@/services/launchAdq'
-import { getSysAdgroupsList } from '@/services/launchAdq/localAd'
-import { Col, Row, Input, Select,Button } from 'antd'
-import React, { useEffect ,useState,useCallback} from 'react'
+import { PromotedObjectType } from '@/services/launchAdq/enum'
+import { createSysAdgroups, getSysAdgroupsList } from '@/services/launchAdq/localAd'
+import { Col, Row, Input, Select, Button } from 'antd'
+import React, { useEffect, useState, useCallback } from 'react'
 import TableData from '../../../components/TableData'
 import AdModal from './modal'
+import tableConfig from './tableConfig'
 
-export interface ModalConfig{
-    visible:boolean;
-    title?:string;
+export interface ModalConfig {
+    visible: boolean;
+    title?: string;
 }
 
 function Ad() {
     // 变量
-    const [modalConfig,setModalConfig]=useState<ModalConfig>({
-        visible:true,
-        title:'新建'
+    const [modalConfig, setModalConfig] = useState<ModalConfig>({
+        visible: false,
+        title: '新建'
     })
+    const [oldsearchData, setOldsearchData] = useState<any>(null)
     // api方法
     const sysAdgroupsList: FnAjax<ListData<SysAdgroupsDTO>> = useAjax((params) => getSysAdgroupsList(params))
+    const createSysAdgroup = useAjax((params) => createSysAdgroups(params))
     // 初始获取列表
     useEffect(() => {
-        sysAdgroupsList.run({ pageNum: 1, pageSize: 20 })
+        getList({ pageSize: 20, pageNum: 1 })
     }, [])
+    // 获取列表
+    const getList = useCallback((arg: { pageSize: number, pageNum: number, adgroupName?: string, promotedObjectType?: string }) => {
+        Object.keys(arg).forEach(key => {
+            !arg[key] && delete arg[key]
+        })
+        if (JSON.stringify(arg) !== JSON.stringify(oldsearchData)) {
+            setOldsearchData(arg)
+            sysAdgroupsList.run(arg)
+        }
+    }, [oldsearchData])
 
     // 设置变量
-    const handleModalConfig=useCallback((arg:ModalConfig)=>{
-        setModalConfig({...modalConfig,...arg})
-    },[modalConfig])
+    const handleModalConfig = useCallback((arg: ModalConfig) => {
+        setModalConfig({ ...modalConfig, ...arg })
+    }, [modalConfig])
     // submit
-    const submit=useCallback((arg:any)=>{
+    const submit = useCallback((arg: any) => {
         console.log(arg)
-    },[])
+        createSysAdgroup.run(arg).then(res => {
+            if (res) {
+                sysAdgroupsList.refresh()
+                handleModalConfig({ visible: false })
+            }
+        })
+    }, [sysAdgroupsList])
+    console.log(PromotedObjectType)
     return <div>
         <TableData
-            columns={() => []}
+            columns={tableConfig}
             ajax={sysAdgroupsList}
-            dataSource={[]}
+            dataSource={sysAdgroupsList?.data?.records}
             loading={sysAdgroupsList?.loading}
             scroll={{ y: 600 }}
             total={sysAdgroupsList?.data?.total}
@@ -44,21 +65,57 @@ function Ad() {
             pageSize={sysAdgroupsList?.data?.size}
             leftChild={<>
                 <Row gutter={[10, 10]}>
-                    <Col span={24}><Button type='primary' onClick={()=>{
-                        handleModalConfig({visible:true})
+                    <Col span={24}><Button type='primary' onClick={() => {
+                        handleModalConfig({ visible: true })
                     }}>新建广告模板</Button></Col>
-                    <Col><Input placeholder='广告名称' allowClear /></Col>
-                    <Col><Select placeholder='推广目标' allowClear options={[{ label: '朋友圈', value: 1 }]} /></Col>
+                    <Col>
+                        <Input
+                            placeholder='广告名称'
+                            allowClear
+                            onBlur={(e) => {
+                                let value = e.target.value
+                                getList({ pageNum: 1, pageSize: 20, adgroupName: value })
+                            }}
+                            onKeyDownCapture={(e: any) => {
+                                let key = e.key
+                                if (key === 'Enter') {
+                                    let value = e.target.value
+                                    getList({ pageNum: 1, pageSize: 20, adgroupName: value })
+                                }
+                            }}
+                            onChange={(e) => {
+                                let value = e.target.value
+                                if (!value) {
+                                    getList({ pageNum: 1, pageSize: 20, adgroupName: value })
+                                }
+                            }}
+                        />
+                    </Col>
+                    <Col>
+                        <Select placeholder='推广目标选择' style={{ minWidth: 200 }} showSearch filterOption={(input, option) =>
+                            (option!.children as unknown as string).toLowerCase().includes(input.toLowerCase())
+                        } allowClear onChange={(value) => {
+                            getList({ pageNum: 1, pageSize: 20, promotedObjectType: value })
+                        }}>
+                            {
+                                Object.keys(PromotedObjectType).map(key => {
+                                    // let obj = JSON.parse(PromotedObjectType[key])
+                                    return <Select.Option value={key} key={key}>{PromotedObjectType[key]}</Select.Option>
+                                })
+                            }
+                        </Select>
+                    </Col>
                 </Row>
             </>}
             onChange={(props: any) => {
-                // let { sortData, pagination } = props
-                // let { current, pageSize } = pagination
+                let { sortData, pagination } = props
+                let { current, pageSize } = pagination
+                getList({pageNum:current,pageSize})
             }}
         // config={guanggao}
         // configName={'广告模板列表'}
         />
-        <AdModal  visible={modalConfig.visible} title={modalConfig.title} PupFn={handleModalConfig} callback={submit}/>
+        {modalConfig.visible && <AdModal visible={modalConfig.visible} title={modalConfig.title} PupFn={handleModalConfig} callback={submit} confirmLoading={createSysAdgroup.loading} />}
     </div>
 }
 export default Ad

+ 20 - 5
src/pages/launchSystemNew/launchManage/localAd/ad/modal.tsx

@@ -1,6 +1,6 @@
 import React, { useCallback } from 'react'
 import { Modal, Form, Input, Divider, Select, Radio, DatePicker, Switch } from 'antd'
-import { SiteSetEnum, BidModeEnum, OptimizationGoalEnum, BidStrategyEnum } from '@/services/launchAdq/enum'
+import { SiteSetEnum, BidModeEnum, OptimizationGoalEnum, BidStrategyEnum, PromotedObjectType } from '@/services/launchAdq/enum'
 import { ModalConfig } from '.'
 import moment from 'moment';
 const { RangePicker }: { RangePicker: any } = DatePicker;
@@ -9,10 +9,12 @@ interface Props {
     title?: string,
     visible: boolean,
     PupFn: (arg: ModalConfig) => void,
-    callback: (params: any) => void
+    callback: (params: any) => void,
+    confirmLoading: boolean
 }
+/**广告模板*/
 function AdModal(props: Props) {
-    let { visible, title, PupFn ,callback} = props
+    let { visible, title, confirmLoading, PupFn, callback } = props
     const [form] = Form.useForm();
     let dateType = Form.useWatch('dateType', form)
     let bidMode = Form.useWatch('bidMode', form)
@@ -43,6 +45,7 @@ function AdModal(props: Props) {
         onCancel={() => { PupFn({ visible: false }) }}
         onOk={handleOk}
         width={900}
+        confirmLoading={confirmLoading}
     >
         <Form
             form={form}
@@ -60,11 +63,23 @@ function AdModal(props: Props) {
         >
             {/* ============================================================基本信息============================================================= */}
             <Divider orientation='center'>基本信息</Divider>
+            <Form.Item label={<strong>推广目标类型</strong>} name='promotedObjectType' rules={[{ required: true, message: '请选择推广告推广目标类型!' }]}>
+                <Select style={{ width: 300 }} showSearch filterOption={(input, option) =>
+                    (option!.children as unknown as string).toLowerCase().includes(input.toLowerCase())
+                } allowClear>
+                    {
+                        Object.keys(PromotedObjectType).map(key => {
+                            // let obj = JSON.parse(PromotedObjectType[key])
+                            return <Select.Option value={key} key={key}>{PromotedObjectType[key]}</Select.Option>
+                        })
+                    }
+                </Select>
+            </Form.Item>
             <Form.Item label={<strong>广告名称</strong>} name='adgroupName' rules={[{ required: true, message: '请输入广告名称!' }]}>
                 <Input placeholder='广告名称' style={{ width: 300 }} />
             </Form.Item>
             <Form.Item label={<strong>广告版位</strong>} name='siteSet' rules={[{ required: true, message: '请输入选择广告版位!' }]}>
-                <Select mode='multiple' style={{ width: 300 }}>
+                <Select mode='multiple' style={{ width: 300 }} allowClear>
                     {
                         Object.keys(SiteSetEnum).map(key => {
                             return <Select.Option value={key} key={key}>{SiteSetEnum[key]}</Select.Option>
@@ -109,7 +124,7 @@ function AdModal(props: Props) {
                     <Form.Item label={<strong>优化目标</strong>} name='optimizationGoal' rules={[{ required: true, message: '请选择优化目标' }]}>
                         <Select style={{ width: 300 }} showSearch filterOption={(input, option) =>
                             (option!.children as unknown as string).toLowerCase().includes(input.toLowerCase())
-                        }>
+                        } allowClear>
                             {
                                 Object.keys(OptimizationGoalEnum).map(key => {
                                     return <Select.Option value={key} key={key}>{OptimizationGoalEnum[key]}</Select.Option>

+ 48 - 0
src/pages/launchSystemNew/launchManage/localAd/ad/tableConfig.tsx

@@ -0,0 +1,48 @@
+import { PromotedObjectType } from '@/services/launchAdq/enum'
+function tableConfig():any{
+    return [
+        {
+            title: 'ID',
+            dataIndex: 'id',
+            key: 'id',
+            align: 'center',
+        },
+        {
+            title: '广告名称',
+            dataIndex: 'adgroupName',
+            key: 'adgroupName',
+            align: 'center',
+        },
+        {
+            title: '广告推广目标类型',
+            dataIndex: 'promotedObjectType',
+            key: 'promotedObjectType',
+            align: 'center',
+           render:(a: string | number)=>{
+            return PromotedObjectType[a]
+           } 
+        },
+        {
+            title: '投放日期',
+            dataIndex: 'beginDate',
+            key: 'beginDate',
+            align: 'center',
+            render:(a: string,b: { endDate: string })=>{
+                return b?.endDate ? a+'~'+b.endDate : a+'~'+'长期投放'
+            }
+        },
+        {
+            title: '广告出价',
+            dataIndex: 'bidAmount',
+            key: 'bidAmount',
+            align: 'center',  
+        },
+        {
+            title: '创建时间',
+            dataIndex: 'createTime',
+            key: 'createTime',
+            align: 'center',
+        },
+    ]
+}
+export default tableConfig

+ 200 - 0
src/pages/launchSystemNew/launchManage/localAd/adenum.ts

@@ -0,0 +1,200 @@
+const ad_enum = {
+  /**推广计划类型*/
+  campaign_type: {
+    // CAMPAIGN_TYPE_NORMAL: {
+    //   label: '普通展示广告',
+    //   /**推广目标*/
+    //   promoted_object_type: {
+    //     PROMOTED_OBJECT_TYPE_LINK: {
+    //       label: '网页',
+    //       campaign_type: 'CAMPAIGN_TYPE_NORMAL',
+    //       site_set: 'SITE_SET_KANDIAN,SITE_SET_MOBILE_INNER,SITE_SET_MOBILE_UNION',
+    //     },
+    //     PROMOTED_OBJECT_TYPE_LINK_WECHAT: {
+    //       label: '品牌网页',
+    //       campaign_type: 'CAMPAIGN_TYPE_NORMAL,PROMOTED_OBJECT_TYPE_LINK_WECHAT',
+    //       site_set: 'SITE_SET_MOMENTS',
+    //     },
+    //     PROMOTED_OBJECT_TYPE_ECOMMERCE: {
+    //       label: '商品推广',
+    //       campaign_type: 'CAMPAIGN_TYPE_NORMAL,CAMPAIGN_TYPE_WECHAT_MOMENTS',
+    //       site_set: 'SITE_SET_KANDIAN,SITE_SET_MOBILE_INNER,SITE_SET_MOBILE_UNION,SITE_SET_MOMENTS',
+    //     },
+    //     PROMOTED_OBJECT_TYPE_APP_ANDROID: {
+    //       label: 'Android应用', //名称
+    //       campaign_type: 'CAMPAIGN_TYPE_NORMAL,CAMPAIGN_TYPE_WECHAT_MOMENTS', //关联的推广计划类型
+    //       site_set:
+    //         'SITE_SET_KANDIAN,SITE_SET_MINI_GAME_QQ,SITE_SET_MINI_GAME_WECHAT,SITE_SET_MOBILE_GAME,SITE_SET_MOBILE_INNER,SITE_SET_MOBILE_UNION,SITE_SET_MOBILE_YYB,SITE_SET_MOMENTS',
+    //     },
+    //     PROMOTED_OBJECT_TYPE_APP_IOS: {
+    //       label: 'IOS应用',
+    //       campaign_type: 'CAMPAIGN_TYPE_NORMAL,CAMPAIGN_TYPE_WECHAT_MOMENTS',
+    //       site_set: 'SITE_SET_KANDIAN,SITE_SET_MOBILE_INNER,SITE_SET_MOBILE_UNION,SITE_SET_MOMENTS',
+    //     },
+    //   },
+    // },
+    CAMPAIGN_TYPE_WECHAT_MOMENTS: {
+      label: '微信朋友圈广告',
+      /**推广目标*/
+      promoted_object_type: {
+        PROMOTED_OBJECT_TYPE_WECHAT_OFFICIAL_ACCOUNT: {
+          label: '微信公众号',
+          site_set: {
+            SITE_SET_MOMENTS: {
+              label: '微信朋友圈',
+            },
+            SITE_SET_WECHAT: {
+              label: '微信公众号与小程序',
+            },
+          },
+        },
+        // PROMOTED_OBJECT_TYPE_ECOMMERCE: {
+        //   label: '商品推广',
+        //   campaign_type: 'CAMPAIGN_TYPE_NORMAL,CAMPAIGN_TYPE_WECHAT_MOMENTS',
+        //   site_set: 'SITE_SET_KANDIAN,SITE_SET_MOBILE_INNER,SITE_SET_MOBILE_UNION,SITE_SET_MOMENTS',
+        // },
+        // PROMOTED_OBJECT_TYPE_LINK_WECHAT: {
+        //   label: '品牌网页',
+        //   campaign_type: 'CAMPAIGN_TYPE_NORMAL,PROMOTED_OBJECT_TYPE_LINK_WECHAT',
+        //   site_set: 'SITE_SET_MOMENTS',
+        // },
+        // PROMOTED_OBJECT_TYPE_APP_ANDROID: {
+        //   label: 'Android应用', //名称
+        //   campaign_type: 'CAMPAIGN_TYPE_NORMAL,CAMPAIGN_TYPE_WECHAT_MOMENTS', //关联的推广计划类型
+        //   site_set:
+        //     'SITE_SET_KANDIAN,SITE_SET_MINI_GAME_QQ,SITE_SET_MINI_GAME_WECHAT,SITE_SET_MOBILE_GAME,SITE_SET_MOBILE_INNER,SITE_SET_MOBILE_UNION,SITE_SET_MOBILE_YYB,SITE_SET_MOMENTS',
+        // },
+        // PROMOTED_OBJECT_TYPE_APP_IOS: {
+        //   label: 'IOS应用',
+        //   campaign_type: 'CAMPAIGN_TYPE_NORMAL,CAMPAIGN_TYPE_WECHAT_MOMENTS',
+        //   site_set: 'SITE_SET_KANDIAN,SITE_SET_MOBILE_INNER,SITE_SET_MOBILE_UNION,SITE_SET_MOMENTS',
+        // },
+        // PROMOTED_OBJECT_TYPE_LEAD_AD: {
+        //   label: '销售线索',
+        //   campaign_type: 'CAMPAIGN_TYPE_NORMAL',
+        //   site_set: 'SITE_SET_MOMENTS',
+        // },
+        // PROMOTED_OBJECT_TYPE_MINI_GAME_WECHAT: {
+        //   label: '微信小游戏',
+        //   campaign_type: 'CAMPAIGN_TYPE_NORMAL,PROMOTED_OBJECT_TYPE_LINK_WECHAT',
+        //   site_set: '',
+        // },
+        // PROMOTED_OBJECT_TYPE_LOCAL_ADS_WECHAT: {
+        //   label: '本地门店',
+        //   campaign_type: 'CAMPAIGN_TYPE_NORMAL,PROMOTED_OBJECT_TYPE_LINK_WECHAT',
+        //   site_set: '',
+        // },
+      },
+    },
+  },
+  /**推广目标*/
+    promoted_object_type: {
+      PROMOTED_OBJECT_TYPE_WECHAT_OFFICIAL_ACCOUNT: {
+        label: '微信公众号',
+        campaign_type: 'CAMPAIGN_TYPE_WECHAT_MOMENTS',
+        site_set: 'SITE_SET_MOMENTS,SITE_SET_WECHAT',
+        adcreative_template_id: '720,',
+      },
+      PROMOTED_OBJECT_TYPE_APP_ANDROID: {
+        label: 'Android应用', //名称
+        campaign_type: 'CAMPAIGN_TYPE_NORMAL,CAMPAIGN_TYPE_WECHAT_MOMENTS', //关联的推广计划类型
+        site_set:
+          'SITE_SET_KANDIAN,SITE_SET_MINI_GAME_QQ,SITE_SET_MINI_GAME_WECHAT,SITE_SET_MOBILE_GAME,SITE_SET_MOBILE_INNER,SITE_SET_MOBILE_UNION,SITE_SET_MOBILE_YYB,SITE_SET_MOMENTS',
+      },
+      PROMOTED_OBJECT_TYPE_APP_IOS: {
+        label: 'IOS应用',
+        campaign_type: 'CAMPAIGN_TYPE_NORMAL,CAMPAIGN_TYPE_WECHAT_MOMENTS',
+        site_set: 'SITE_SET_KANDIAN,SITE_SET_MOBILE_INNER,SITE_SET_MOBILE_UNION,SITE_SET_MOMENTS',
+      },
+      PROMOTED_OBJECT_TYPE_MINI_GAME_WECHAT: {
+        label: '微信小游戏',
+        campaign_type: 'CAMPAIGN_TYPE_NORMAL,PROMOTED_OBJECT_TYPE_LINK_WECHAT',
+        site_set: '',
+      },
+      PROMOTED_OBJECT_TYPE_ECOMMERCE: {
+        label: '商品推广',
+        campaign_type: 'CAMPAIGN_TYPE_NORMAL,CAMPAIGN_TYPE_WECHAT_MOMENTS',
+        site_set: 'SITE_SET_KANDIAN,SITE_SET_MOBILE_INNER,SITE_SET_MOBILE_UNION,SITE_SET_MOMENTS',
+      },
+      PROMOTED_OBJECT_TYPE_LEAD_AD: {
+        label: '销售线索',
+        campaign_type: 'CAMPAIGN_TYPE_NORMAL',
+        site_set: 'SITE_SET_MOMENTS',
+      },
+      PROMOTED_OBJECT_TYPE_LINK: {
+        label: '网页',
+        campaign_type: 'CAMPAIGN_TYPE_NORMAL',
+        site_set: 'SITE_SET_KANDIAN,SITE_SET_MOBILE_INNER,SITE_SET_MOBILE_UNION',
+      },
+      PROMOTED_OBJECT_TYPE_LINK_WECHAT: {
+        label: '品牌网页',
+        campaign_type: 'CAMPAIGN_TYPE_NORMAL,PROMOTED_OBJECT_TYPE_LINK_WECHAT',
+        site_set: 'SITE_SET_MOMENTS',
+      },
+      PROMOTED_OBJECT_TYPE_QQ_MESSAGE: {
+        label: 'QQ消息',
+        campaign_type: 'CAMPAIGN_TYPE_NORMAL',
+        site_set: 'SITE_SET_MOBILE_INNER',
+      },
+      PROMOTED_OBJECT_TYPE_APP_ANDROID_UNION: {
+        label: 'Android应用(优量汇推广)',
+        campaign_type: 'CAMPAIGN_TYPE_NORMAL',
+        site_set: 'SITE_SET_KANDIAN,SITE_SET_MOBILE_UNION',
+      },
+    },
+  /**广告版位*/
+  site_set: {
+    SITE_SET_MOMENTS: {
+      label: '微信朋友圈',
+    },
+    SITE_SET_WECHAT: {
+      label: '微信公众号与小程序',
+    },
+    SITE_SET_KANDIAN: {
+      label: '腾讯看点',
+    },
+    SITE_SET_MINI_GAME_QQ: {
+      label: 'QQ小游戏',
+    },
+    SITE_SET_MINI_GAME_WECHAT: {
+      label: '微信小游戏',
+    },
+    SITE_SET_MOBILE_GAME: {
+      label: 'App游戏',
+    },
+    SITE_SET_MOBILE_INNER: {
+      label: '移动内部站点',
+    },
+    SITE_SET_MOBILE_UNION: {
+      label: '优量汇',
+    },
+    SITE_SET_MOBILE_YYB: {
+      label: '应用宝',
+    },
+    SITE_SET_QQ_MUSIC_GAME: {
+      label: 'QQ、腾讯音乐及游戏',
+    },
+    SITE_SET_TENCENT_NEWS: {
+      label: '腾讯新闻',
+    },
+    SITE_SET_TENCENT_VIDEO: {
+      label: '腾讯视频',
+    },
+  },
+  /**创意形式ID*/
+  adcreative_template_id: {
+    720: {
+      label: '横版视频 16:9',
+    },
+  },
+  /**出价方式*/
+  bid_mode: {},
+  /**	广告优化目标类型*/
+  optimization_goal: {},
+  /**	落地页类型*/
+  page_type: {},
+  /**文字链跳转类型类型*/
+  link_page_type: {},
+  /**链接名称类型*/
+  link_name_type: {},
+};

+ 0 - 6
src/pages/launchSystemNew/launchManage/localAd/campaign/index.tsx

@@ -1,6 +0,0 @@
-import React from 'react'
-
-function Campaign(){
-    return <div>计划</div>
-}
-export default Campaign

+ 119 - 3
src/pages/launchSystemNew/launchManage/localAd/creative/index.tsx

@@ -1,6 +1,122 @@
-import React from 'react'
 
-function Creative(){
-    return <div>创意</div>
+import { FnAjax, useAjax } from '@/Hook/useAjax'
+import { ListData, } from '@/services/launchAdq'
+import { PromotedObjectType } from '@/services/launchAdq/enum'
+import { createSysAdcreative, getSysAdcreativeList } from '@/services/launchAdq/creative'
+import { Col, Row, Input, Select, Button } from 'antd'
+import React, { useEffect, useState, useCallback } from 'react'
+import TableData from '../../../components/TableData'
+import AdModal from './modal'
+import tableConfig from './tableConfig'
+
+export interface ModalConfig {
+    visible: boolean;
+    title?: string;
+}
+
+function Creative() {
+    // 变量
+    const [modalConfig, setModalConfig] = useState<ModalConfig>({
+        visible: true,
+        title: '新建'
+    })
+    const [oldsearchData, setOldsearchData] = useState<any>(null)
+    // api方法
+    const sysAdcreativeList: FnAjax<ListData<any>> = useAjax((params) => getSysAdcreativeList(params))
+    const createSysAdgroup = useAjax((params) => createSysAdcreative(params))
+    // 初始获取列表
+    useEffect(() => {
+        getList({ pageSize: 20, pageNum: 1 })
+    }, [])
+    // 获取列表
+    const getList = useCallback((arg: { pageSize: number, pageNum: number, adcreativeName?: string, promotedObjectType?: string }) => {
+        Object.keys(arg).forEach(key => {
+            !arg[key] && delete arg[key]
+        })
+        if (JSON.stringify(arg) !== JSON.stringify(oldsearchData)) {
+            setOldsearchData(arg)
+            sysAdcreativeList.run(arg)
+        }
+    }, [oldsearchData])
+
+    // 设置变量
+    const handleModalConfig = useCallback((arg: ModalConfig) => {
+        setModalConfig({ ...modalConfig, ...arg })
+    }, [modalConfig])
+    // submit
+    const submit = useCallback((arg: any) => {
+        console.log(arg)
+        createSysAdgroup.run(arg).then(res => {
+            if (res) {
+                sysAdcreativeList.refresh()
+                handleModalConfig({ visible: false })
+            }
+        })
+    }, [sysAdcreativeList])
+    console.log(sysAdcreativeList)
+    return <div>
+        <TableData
+            columns={tableConfig}
+            ajax={sysAdcreativeList}
+            dataSource={sysAdcreativeList?.data?.records}
+            loading={sysAdcreativeList?.loading}
+            scroll={{ y: 600 }}
+            total={sysAdcreativeList?.data?.total}
+            page={sysAdcreativeList?.data?.current}
+            pageSize={sysAdcreativeList?.data?.size}
+            leftChild={<>
+                <Row gutter={[10, 10]}>
+                    <Col span={24}><Button type='primary' onClick={() => {
+                        handleModalConfig({ visible: true })
+                    }}>新建创意模板</Button></Col>
+                    <Col>
+                        <Input
+                            placeholder='创意名称'
+                            allowClear
+                            onBlur={(e) => {
+                                let value = e.target.value
+                                getList({ pageNum: 1, pageSize: 20, adcreativeName: value })
+                            }}
+                            onKeyDownCapture={(e: any) => {
+                                let key = e.key
+                                if (key === 'Enter') {
+                                    let value = e.target.value
+                                    getList({ pageNum: 1, pageSize: 20, adcreativeName: value })
+                                }
+                            }}
+                            onChange={(e) => {
+                                let value = e.target.value
+                                if (!value) {
+                                    getList({ pageNum: 1, pageSize: 20, adcreativeName: value })
+                                }
+                            }}
+                        />
+                    </Col>
+                    <Col>
+                        <Select placeholder='推广目标选择' style={{ minWidth: 200 }} showSearch filterOption={(input, option) =>
+                            (option!.children as unknown as string).toLowerCase().includes(input.toLowerCase())
+                        } allowClear onChange={(value) => {
+                            getList({ pageNum: 1, pageSize: 20, promotedObjectType: value })
+                        }}>
+                            {
+                                Object.keys(PromotedObjectType).map(key => {
+                                    // let obj = JSON.parse(PromotedObjectType[key])
+                                    return <Select.Option value={key} key={key}>{PromotedObjectType[key]}</Select.Option>
+                                })
+                            }
+                        </Select>
+                    </Col>
+                </Row>
+            </>}
+            onChange={(props: any) => {
+                let { sortData, pagination } = props
+                let { current, pageSize } = pagination
+                getList({ pageNum: current, pageSize })
+            }}
+        // config={guanggao}
+        // configName={'广告模板列表'}
+        />
+        {modalConfig.visible && <AdModal visible={modalConfig.visible} title={modalConfig.title} PupFn={handleModalConfig} callback={submit} confirmLoading={createSysAdgroup.loading} />}
+    </div>
 }
 export default Creative

+ 177 - 0
src/pages/launchSystemNew/launchManage/localAd/creative/modal.tsx

@@ -0,0 +1,177 @@
+import React, { useCallback } from 'react'
+import { Modal, Form, Input, Divider, Select, Radio, DatePicker, Switch } from 'antd'
+import { SiteSetEnum, BidModeEnum, OptimizationGoalEnum, BidStrategyEnum, PromotedObjectType } from '@/services/launchAdq/enum'
+import { ModalConfig } from '.'
+import moment from 'moment';
+const { RangePicker }: { RangePicker: any } = DatePicker;
+let DatePickers: any = DatePicker
+interface Props {
+    title?: string,
+    visible: boolean,
+    PupFn: (arg: ModalConfig) => void,
+    callback: (params: any) => void,
+    confirmLoading: boolean
+}
+/**创意模板*/
+function AdModal(props: Props) {
+    let { visible, title, confirmLoading, PupFn, callback } = props
+    const [form] = Form.useForm();
+    let dateType = Form.useWatch('dateType', form)
+    let bidMode = Form.useWatch('bidMode', form)
+    let smartBidType = Form.useWatch('smartBidType', form)
+    let autoAcquisitionEnabled = Form.useWatch('autoAcquisitionEnabled', form)
+    // let siteSet = Form.useWatch('siteSet', form)
+
+    // 确定事件
+    const handleOk = useCallback(() => {
+        form.validateFields().then(values => {
+            let newValues = JSON.parse(JSON.stringify(values))
+            if (newValues.dateType === '2') {
+                newValues['beginDate'] = moment(newValues.date).format('YYYY-MM-DD')
+            } else {
+                newValues['beginDate'] = moment(newValues.date[0]).format('YYYY-MM-DD')
+                newValues['endDate'] = moment(newValues.date[1]).format('YYYY-MM-DD')
+            }
+            delete newValues['dateType']
+            delete newValues['date']
+            newValues['timeSeries'] = Array(336).fill(1).join('')
+            callback(newValues)
+        })
+        // PupFn({ visible: false })
+    }, [form])
+    return <Modal
+        visible={visible}
+        title={title + '创意'}
+        onCancel={() => { PupFn({ visible: false }) }}
+        onOk={handleOk}
+        width={900}
+        confirmLoading={confirmLoading}
+    >
+        <Form
+            form={form}
+            labelCol={{ span: 3 }}
+            initialValues={
+                {
+                    bidMode: 'BID_MODE_OCPM',
+                    dateType: '2',
+                    bidStrategy: 'BID_STRATEGY_AVERAGE_COST',
+                    timeSeries: '1',
+                    smartBidType: 'SMART_BID_TYPE_CUSTOM',
+                    autoAcquisitionEnabled: false,
+                }
+            }
+        >
+            {/* ============================================================基本信息============================================================= */}
+            <Divider orientation='center'>基本信息</Divider>
+            <Form.Item label={<strong>创意名称</strong>} name='adcreativeName' rules={[{ required: true, message: '请输入广告名称!' }]}>
+                <Input placeholder='创意名称' style={{ width: 300 }} />
+            </Form.Item>
+            <Form.Item label={<strong>广告版位</strong>} name='siteSet' rules={[{ required: true, message: '请输入选择广告版位!' }]}>
+                <Select mode='multiple' style={{ width: 300 }} allowClear>
+                    {
+                        Object.keys(SiteSetEnum).map(key => {
+                            return <Select.Option value={key} key={key}>{SiteSetEnum[key]}</Select.Option>
+                        })
+                    }
+                </Select>
+            </Form.Item>
+            <Form.Item label={<strong>推广目标类型</strong>} name='promotedObjectType' rules={[{ required: true, message: '请选择推广告推广目标类型!' }]}>
+                <Select style={{ width: 300 }} showSearch filterOption={(input, option) =>
+                    (option!.children as unknown as string).toLowerCase().includes(input.toLowerCase())
+                } allowClear>
+                    {
+                        Object.keys(PromotedObjectType).map(key => {
+                            // let obj = JSON.parse(PromotedObjectType[key])
+                            return <Select.Option value={key} key={key}>{PromotedObjectType[key]}</Select.Option>
+                        })
+                    }
+                </Select>
+            </Form.Item>
+            {/* ============================================================排期与出价============================================================= */}
+            <Divider orientation='center'>排期与出价</Divider>
+            <Form.Item label={<strong>投放日期</strong>} name='dateType'>
+                <Radio.Group >
+                    <Radio.Button value="1">选择开始与结束日期</Radio.Button>
+                    <Radio.Button value="2">长期投放</Radio.Button>
+                </Radio.Group>
+            </Form.Item>
+            {/* 投放日期的不同展示不同的日期选择 */}
+            {
+                dateType === '1' ? <Form.Item name='date' rules={[{ required: true, message: '请选择日期' }]}>
+                    <RangePicker style={{ marginLeft: 107 }}></RangePicker>
+                </Form.Item> : <Form.Item name='date' style={{ marginLeft: 107 }} rules={[{ required: true, message: '请选择日期' }]}>
+                    <DatePickers />
+                </Form.Item>
+            }
+            <Form.Item label={<strong>投放时段</strong>}>
+                <Radio.Group name='timeSeries' defaultValue='1'>
+                    <Radio.Button value={'1'}>全天投放</Radio.Button>
+                </Radio.Group>
+            </Form.Item>
+            <Form.Item label={<strong>出价方式</strong>} name='bidMode'>
+                <Radio.Group >
+                    {
+                        Object.keys(BidModeEnum).map(key => {
+                            return <Radio.Button value={key} key={key} disabled={!key.includes('CPM')}>{BidModeEnum[key]}</Radio.Button>
+                        })
+                    }
+
+                </Radio.Group>
+            </Form.Item>
+            {/* 出价方式为OCPM才展示 */}
+            {
+                bidMode === 'BID_MODE_OCPM' && <>
+                    <Form.Item label={<strong>优化目标</strong>} name='optimizationGoal' rules={[{ required: true, message: '请选择优化目标' }]}>
+                        <Select style={{ width: 300 }} showSearch filterOption={(input, option) =>
+                            (option!.children as unknown as string).toLowerCase().includes(input.toLowerCase())
+                        } allowClear>
+                            {
+                                Object.keys(OptimizationGoalEnum).map(key => {
+                                    return <Select.Option value={key} key={key}>{OptimizationGoalEnum[key]}</Select.Option>
+                                })
+                            }
+                        </Select>
+                    </Form.Item>
+                    <Form.Item label={<strong>出价类型</strong>} name='smartBidType'>
+                        <Radio.Group >
+                            <Radio.Button value="SMART_BID_TYPE_CUSTOM">手动出价</Radio.Button>
+                            <Radio.Button value="SMART_BID_TYPE_SYSTEMATIC">自动出价</Radio.Button>
+                        </Radio.Group>
+                    </Form.Item>
+                    <Form.Item label={<strong>出价策略</strong>} name='bidStrategy'>
+                        <Radio.Group >
+                            {
+                                Object.keys(BidStrategyEnum).map(key => {
+                                    return <Radio.Button value={key} key={key} disabled={smartBidType === 'SMART_BID_TYPE_SYSTEMATIC' && key === 'BID_STRATEGY_PRIORITY_CAP_COST'}> {BidStrategyEnum[key]}</Radio.Button>
+                                })
+                            }
+                        </Radio.Group>
+                    </Form.Item>
+                </>
+            }
+            {/* 出价类型为手动出价才展示 */}
+            {
+                smartBidType !== 'SMART_BID_TYPE_SYSTEMATIC' && <>
+                    <Form.Item label={<strong>出价</strong>} name='bidAmount' rules={[{ required: true, message: '请输入价格' }]}>
+                        <Input placeholder='输入价格 元/千次曝光' style={{ width: 300 }} />
+                    </Form.Item>
+                    {/* 当版位选择大于1时才出现 */}
+                    {/* {siteSet?.length > 1 &&<Form.Item label={<strong>分版位出价</strong>} name='bidAdjustment'>
+                        <Switch checkedChildren="开启" unCheckedChildren="关闭" />
+                    </Form.Item>} */}
+                    <Form.Item label={<strong>一键起量</strong>} name='autoAcquisitionEnabled' valuePropName="checked">
+                        <Switch checkedChildren="开启" unCheckedChildren="关闭" />
+                    </Form.Item>
+                    {/* 一键起量开启时才出现 */}
+                    {autoAcquisitionEnabled && <Form.Item label={<strong>起量预算</strong>} name='autoAcquisitionBudget' rules={[{ required: true, message: '请输入起量预算' }]}>
+                        <Input placeholder='起量预算' style={{ width: 300 }} />
+                    </Form.Item>}
+                </>
+            }
+            <Form.Item label={<strong>广告日预算</strong>} name='dailyBudget'>
+                <Input placeholder='不填默认为不限' style={{ width: 300 }} />
+            </Form.Item>
+        </Form>
+    </Modal >
+}
+export default AdModal

+ 48 - 0
src/pages/launchSystemNew/launchManage/localAd/creative/tableConfig.tsx

@@ -0,0 +1,48 @@
+import { PromotedObjectType } from '@/services/launchAdq/enum'
+function tableConfig():any{
+    return [
+        {
+            title: 'ID',
+            dataIndex: 'id',
+            key: 'id',
+            align: 'center',
+        },
+        {
+            title: '广告名称',
+            dataIndex: 'adgroupName',
+            key: 'adgroupName',
+            align: 'center',
+        },
+        {
+            title: '广告推广目标类型',
+            dataIndex: 'promotedObjectType',
+            key: 'promotedObjectType',
+            align: 'center',
+           render:(a: string | number)=>{
+            return PromotedObjectType[a]
+           } 
+        },
+        {
+            title: '投放日期',
+            dataIndex: 'beginDate',
+            key: 'beginDate',
+            align: 'center',
+            render:(a: string,b: { endDate: string })=>{
+                return b?.endDate ? a+'~'+b.endDate : a+'~'+'长期投放'
+            }
+        },
+        {
+            title: '广告出价',
+            dataIndex: 'bidAmount',
+            key: 'bidAmount',
+            align: 'center',  
+        },
+        {
+            title: '创建时间',
+            dataIndex: 'createTime',
+            key: 'createTime',
+            align: 'center',
+        },
+    ]
+}
+export default tableConfig

+ 3 - 3
src/pages/launchSystemNew/launchManage/localAd/index.tsx

@@ -2,17 +2,17 @@ import React, { useState } from 'react'
 import { Card, Button, Tabs } from 'antd';
 import './index.less'
 import Ad from './ad';
-import Campaign from './campaign';
 import Creative from './creative';
+import Targeting from './targeting';
 const { TabPane } = Tabs;
 const tabsConfig = [
     // { key: '1', tab: '计划模板',jsx:<Campaign/> },
     { key: '1', tab: '广告模板',jsx:<Ad/>},
     { key: '2', tab: '创意模板' ,jsx:<Creative/>},
-    { key: '3', tab: '定向模板' ,jsx:<Creative/>},
+    { key: '3', tab: '定向模板' ,jsx:<Targeting/>},
 ]
 function LocalAd() {
-    const [activeKey, setActiveKey] = useState('1')
+    const [activeKey, setActiveKey] = useState('3')
     return <Card>
         <Tabs activeKey={activeKey} type="card"  onChange={(activeKey) => { setActiveKey(activeKey) }} >
             {

+ 106 - 0
src/pages/launchSystemNew/launchManage/localAd/targeting/index.tsx

@@ -0,0 +1,106 @@
+
+import { FnAjax, useAjax } from '@/Hook/useAjax'
+import { ListData, } from '@/services/launchAdq'
+import { createsysTargeting, getsysTargetingList } from '@/services/launchAdq/targeting'
+import { Col, Row, Input,  Button } from 'antd'
+import React, { useEffect, useState, useCallback } from 'react'
+import TableData from '../../../components/TableData'
+import AdModal from './modal'
+import tableConfig from './tableConfig'
+
+export interface ModalConfig {
+    visible: boolean;
+    title?: string;
+}
+
+function Targeting() {
+    // 变量
+    const [modalConfig, setModalConfig] = useState<ModalConfig>({
+        visible: false,
+        title: '新建'
+    })
+    const [oldsearchData, setOldsearchData] = useState<any>(null)
+    // api方法
+    const list: FnAjax<ListData<any>> = useAjax((params) => getsysTargetingList(params))
+    const create = useAjax((params) => createsysTargeting(params))
+    // 初始获取列表
+    useEffect(() => {
+        getList({ pageSize: 20, pageNum: 1 })
+    }, [])
+    // 获取列表
+    const getList = useCallback((arg: { pageSize: number, pageNum: number, targetingName?: string, promotedObjectType?: string }) => {
+        Object.keys(arg).forEach(key => {
+            !arg[key] && delete arg[key]
+        })
+        if (JSON.stringify(arg) !== JSON.stringify(oldsearchData)) {
+            setOldsearchData(arg)
+            list.run(arg)
+        }
+    }, [oldsearchData])
+
+    // 设置变量
+    const handleModalConfig = useCallback((arg: ModalConfig) => {
+        setModalConfig({ ...modalConfig, ...arg })
+    }, [modalConfig])
+    // submit
+    const submit = useCallback((arg: any) => {
+        console.log(arg)
+        create.run(arg).then(res => {
+            if (res) {
+                list.refresh()
+                handleModalConfig({ visible: false })
+            }
+        })
+    }, [list])
+    return <div>
+        <TableData
+            columns={tableConfig}
+            ajax={list}
+            dataSource={list?.data?.records}
+            loading={list?.loading}
+            scroll={{ y: 600 }}
+            total={list?.data?.total}
+            page={list?.data?.current}
+            pageSize={list?.data?.size}
+            leftChild={<>
+                <Row gutter={[10, 10]}>
+                    <Col span={24}><Button type='primary' onClick={() => {
+                        handleModalConfig({ visible: true })
+                    }}>新建定向模板</Button></Col>
+                    <Col>
+                        <Input
+                            placeholder='定向名称'
+                            allowClear
+                            onBlur={(e) => {
+                                let value = e.target.value
+                                getList({ pageNum: 1, pageSize: 20, targetingName: value })
+                            }}
+                            onKeyDownCapture={(e: any) => {
+                                let key = e.key
+                                if (key === 'Enter') {
+                                    let value = e.target.value
+                                    getList({ pageNum: 1, pageSize: 20, targetingName: value })
+                                }
+                            }}
+                            onChange={(e) => {
+                                let value = e.target.value
+                                if (!value) {
+                                    getList({ pageNum: 1, pageSize: 20, targetingName: value })
+                                }
+                            }}
+                        />
+                    </Col>
+                </Row>
+            </>}
+            onChange={(props: any) => {
+                let { sortData, pagination } = props
+                let { current, pageSize } = pagination
+                getList({ pageNum: current, pageSize })
+            }}
+        // config={guanggao}
+        // configName={'广告模板列表'}
+        />
+        {modalConfig.visible && <AdModal visible={modalConfig.visible} title={modalConfig.title} PupFn={handleModalConfig} callback={submit} confirmLoading={create.loading} />}
+    </div>
+}
+export default Targeting

+ 576 - 0
src/pages/launchSystemNew/launchManage/localAd/targeting/modal.tsx

@@ -0,0 +1,576 @@
+import React, { useCallback, useState, useEffect } from 'react'
+import { Modal, Form, Input, Divider, Select, Radio, Checkbox, TreeSelect } from 'antd'
+import { GenderEnum, EducationEnum, ExcludedDimensionEnum, MaritalStatusEnum, OptimizationGoalEnum, UserOsEnum, DevicePriceEnum, NetworkEnum, WechatAdBehaviorEnum } from '@/services/launchAdq/enum'
+import { ModalConfig } from '.'
+import { useAjax } from '@/Hook/useAjax'
+import { getTagsList } from '@/services/launchAdq/global'
+interface Props {
+    title?: string,
+    visible: boolean,
+    PupFn: (arg: ModalConfig) => void,
+    callback: (params: any) => void,
+    confirmLoading: boolean
+}
+const ios_os = Object.keys(UserOsEnum).filter(key => key.includes('IOS'))
+const android_os = Object.keys(UserOsEnum).filter(key => key.includes('ANDROID'))
+/**创意模板*/
+function AdModal(props: Props) {
+    let { visible, title, confirmLoading, PupFn, callback } = props
+    const tagsList_REGION = useAjax((params) => getTagsList(params))
+    const tagsList_MODEL = useAjax((params) => getTagsList(params))
+    const [form] = Form.useForm();
+    const [indeterminateIos, setIndeterminateIos] = useState(false);
+    const [indeterminateAndroid, setIndeterminateAndroid] = useState(false);
+    const [modelList, setModelList] = useState([])
+    const [regionsList, setRegionsList] = useState([])
+    let educationType = Form.useWatch('educationType', form)
+    let ageType = Form.useWatch('ageType', form)
+    let age_min = Form.useWatch('age_min', form)
+    let age_max = Form.useWatch('age_max', form)
+    let maritalStatusType = Form.useWatch('maritalStatusType', form)
+    let excludedDimension = Form.useWatch('excludedDimension', form)
+    let userOsType = Form.useWatch('userOsType', form)
+    let userOsIos = Form.useWatch('userOsIos', form)
+    let userOsAndroid = Form.useWatch('userOsAndroid', form)
+    let devicePriceType = Form.useWatch('devicePriceType', form)
+    let networkType = Form.useWatch('networkType', form)
+    let wechatAdBehaviorType = Form.useWatch('wechatAdBehaviorType', form)
+    let actions = Form.useWatch('actions', form)
+    let excludedActions = Form.useWatch('excludedActions', form)
+    let deviceBrandModelType = Form.useWatch('deviceBrandModelType', form)
+    let deviceBrandModelList = Form.useWatch('deviceBrandModelList', form)
+    let geoLocationType = Form.useWatch('geoLocationType', form)
+
+    // 确定事件
+    const handleOk = useCallback(() => {
+        form.validateFields().then(values => {
+            let newValues = JSON.parse(JSON.stringify(values))
+            newValues.targeting = {}
+            Object.keys(newValues).forEach(key => {
+                switch (key) {
+                    case 'geoLocationType':
+                        if (newValues[key] === '1') {
+                            newValues.targeting.geoLocation = {
+                                locationTypes: ['LIVE_IN'],//对于微信流量(site_set=SITE_SET_WECHAT、SITE_SET_MOMENTS、SITE_SET_MINI_GAME_WECHAT),仅能选择"LIVE_IN"(常住);
+                                regions: newValues.regions
+                            }
+                        }
+                        delete newValues[key]
+                        delete newValues.regions
+                        break;
+                    case 'ageType'://年龄处理
+                        if (newValues[key] === '1') {
+                            newValues.targeting.age = {
+                                min: newValues.age_min,
+                                max: newValues.age_max
+                            }
+                        }
+                        delete newValues[key]
+                        delete newValues.age_min
+                        delete newValues.age_max
+                        break;
+                    case 'gender'://性别
+                        newValues[key] !== '0' && (newValues.targeting.gender = newValues[key])
+                        delete newValues[key]
+                        break;
+                    case 'educationType'://学历
+                        newValues[key] === '1' && (newValues.targeting.education = newValues.education)
+                        delete newValues[key]
+                        break;
+                    case 'maritalStatusType'://婚恋
+                        newValues[key] === '1' && (newValues.targeting.maritalStatus = newValues.maritalStatus)
+                        delete newValues[key]
+                        break;
+                    case 'customAudienceType'://定向人群
+                        break;
+                    case 'deviceBrandModelType'://品牌型号
+                        if (newValues[key] === '1') {
+                            newValues.targeting.deviceBrandModel = {}
+                            if (newValues.isexcluded) {
+                                newValues.targeting.deviceBrandModel.excludedList = newValues.deviceBrandModelList
+                                delete newValues.targeting.deviceBrandModel.includedList
+                            } else {
+                                newValues.targeting.deviceBrandModel.includedList = newValues.deviceBrandModelList
+                                delete newValues.targeting.deviceBrandModel.excludedList
+                            }
+                            if (!newValues.targeting.deviceBrandModel.excludedList && !newValues.targeting.deviceBrandModel.includedList) {
+                                delete newValues.targeting.deviceBrandModel
+                            }
+                        }
+                        delete newValues[key]
+                        delete newValues.deviceBrandModelList
+                        delete newValues.isexcluded
+                        break;
+                    case 'wechatAdBehaviorType'://微信再营销
+                        if (newValues[key] === '1') {
+                            newValues.targeting.wechatAdBehavior = {}
+                            if (newValues.actions) {
+                                newValues.targeting.wechatAdBehavior = { ...newValues.targeting.wechatAdBehavior, actions: newValues.actions }
+                            }
+                            if (newValues.excludedActions) {
+                                newValues.targeting.wechatAdBehavior = { ...newValues.targeting.wechatAdBehavior, excludedActions: newValues.excludedActions }
+                            }
+                            // 去除空值的参数
+                            Object.keys(newValues.targeting.wechatAdBehavior).forEach(key => {
+                                if (!newValues.targeting.wechatAdBehavior[key] || newValues.targeting.wechatAdBehavior[key]?.length === 0) {
+                                    delete newValues.targeting.wechatAdBehavior[key]
+                                }
+                            })
+                            // 什么都没删除参数
+                            if (!newValues.targeting.wechatAdBehavior.actions && !newValues.targeting.wechatAdBehavior.excludedActions) {
+                                delete newValues.targeting.wechatAdBehavior
+                            }
+                        }
+                        delete newValues[key]
+                        delete newValues.actions
+                        delete newValues.excludedActions
+                        break;
+                    case 'networkType'://联网方式
+                        newValues[key] === '1' && (newValues.targeting.networkType = newValues.network)
+                        delete newValues[key]
+                        delete newValues.network
+                        break;
+                    case 'devicePriceType'://手机价格
+                        newValues[key] === '1' && (newValues.targeting.network = newValues.network)
+                        delete newValues[key]
+                        delete newValues.devicePrice
+                        break;
+                    case 'userOsType'://手机系统
+                        if (newValues[key] === '1') {
+                            newValues.targeting.userOs = []
+                            if (newValues.userOsIos) {
+                                newValues.targeting.userOs = [...newValues.targeting.userOs, ...newValues.userOsIos]
+                            }
+                            if (newValues.userOsAndroid) {
+                                newValues.targeting.userOs = [...newValues.targeting.userOs, ...newValues.userOsAndroid]
+                            }
+                            if (newValues.targeting.userOs.length === 0) {
+                                delete newValues.targeting.userOs
+                            }
+                        }
+                        delete newValues[key]
+                        delete newValues.userOsIosAll
+                        delete newValues.userOsAndroidAll
+                        delete newValues.userOsIos
+                        delete newValues.userOsAndroid
+                        break;
+                    case 'excludedDimension'://排除已转化用户
+                        if (newValues[key] !== '0') {
+                            newValues.targeting.excludedConvertedAudience = newValues.conversionBehaviorList ? {
+                                excludedDimension: newValues.excludedDimension,
+                                conversionBehaviorList: [newValues.conversionBehaviorList]
+                            } : {
+                                excludedDimension: newValues.excludedDimension,
+                            }
+                        }
+                        delete newValues[key]
+                        delete newValues.conversionBehaviorList
+                        break;
+                }
+            })
+            // console.log(newValues)
+            callback(newValues)
+        })
+    }, [form])
+
+    // 监听ios系统全选事件
+    useEffect(() => {
+        setIndeterminateIos(!!userOsIos?.length && userOsIos?.length < ios_os.length)
+        form.setFieldsValue({ userOsIosAll: userOsIos?.length === ios_os.length })
+    }, [userOsIos])
+    // 监听android系统全选事件
+    useEffect(() => {
+        setIndeterminateAndroid(!!userOsAndroid?.length && userOsAndroid?.length < android_os.length)
+        form.setFieldsValue({ userOsAndroidAll: userOsAndroid?.length === android_os.length })
+    }, [userOsAndroid])
+    // 获取定向标签
+    useEffect(() => {
+        // 获取地域
+        tagsList_REGION.run({ type: 'REGION' }).then(res => {
+            let arr: any = Object.values(res).filter(v => typeof v !== 'string')
+            let parentList = arr.filter((item: { parentName: any }) => !item.parentName)
+            let childrenList = arr.filter((item: { parentName: any }) => item.parentName)
+            parentList = parentList.map((item: { name: any; id: any, parentId: any }) => {
+                let children = childrenList?.filter((c: { parentId: any }) => {
+                    return item.id === c.parentId
+                })
+                let obj = {
+                    title: item.name,
+                    value: item.id,
+                    key: item.id,
+                    parentId: item.parentId,
+                    disabled: item.id === 710000 || item.id === 810000 || item.id === 820000,
+                    children: children.map((item: { name: any; id: any, parentId: any }) => ({
+                        title: item.name,
+                        value: item.id,
+                        key: item.id,
+                        parentId: item.parentId
+                    }))
+                }
+                return obj
+            })
+            parentList = parentList.map((item: any) => {
+                let itemArr = item?.children?.map((c: any) => {
+                    let arr = childrenList.filter((d: { parentId: any }) => {
+                        return d.parentId === c.value
+                    })
+                    arr = arr.map((i: { name: any; id: any }) => ({
+                        title: i.name,
+                        value: i.id,
+                        key: i.id,
+                    }))
+                    return { ...c, children: arr }
+                })
+                return { ...item, children: itemArr }
+            })
+            // let zg = parentList.filter((item: { title: string }) => item.title === '中国')
+            let zg_children = parentList.filter((item: { title: string }) => (item.title !== '中国' && item.title !== '国外'))
+            // zg[0].children = zg_children
+            setRegionsList(zg_children)
+        })
+        // 获取手机
+        tagsList_MODEL.run({ type: 'DEVICE_BRAND_MODEL' }).then(res => {
+            let arr: any = Object.values(res).filter(v => typeof v !== 'string')
+            let parentList = arr.filter((item: { parentName: any }) => !item.parentName)
+            let childrenList = arr.filter((item: { parentName: any }) => item.parentName)
+            parentList = parentList.map((item: { name: any; id: any }) => {
+                let children = childrenList?.filter((c: { parentId: any }) => {
+                    return item.id === c.parentId
+                })
+                let obj = {
+                    title: item.name,
+                    value: item.id,
+                    key: item.id,
+                    children: children.map((item: { name: any; id: any }) => ({
+                        title: item.name,
+                        value: item.id,
+                        key: item.id,
+                    }))
+                }
+                return obj
+            })
+            setModelList(parentList)
+        })
+    }, [])
+    return <Modal
+        visible={visible}
+        title={title + '定向'}
+        onCancel={() => { PupFn({ visible: false }) }}
+        onOk={handleOk}
+        width={900}
+        confirmLoading={confirmLoading}
+    >
+        <Form
+            form={form}
+            labelCol={{ span: 3 }}
+            initialValues={
+                {
+                    geoLocationType: '0',
+                    educationType: '0',
+                    ageType: '0',
+                    gender: '0',
+                    maritalStatusType: '0',
+                    age_min: 14,
+                    age_max: 66,
+                    targetingName: '',
+                    excludedDimension: '0',
+                    userOsType: '0',
+                    devicePriceType: '0',
+                    networkType: '0',
+                    wechatAdBehaviorType: '0',
+                    deviceBrandModelType: '0'
+                }
+            }
+        >
+            {/* ============================================================基本信息============================================================= */}
+            <Divider orientation='left'><h3>基本信息</h3></Divider>
+            {/* ====================定向名称========================= */}
+            <Form.Item label={<strong>定向名称</strong>} name='targetingName' rules={[{ required: true, message: '请输入定向名称!' }]}>
+                <Input placeholder='定向名称' style={{ width: 300 }} />
+            </Form.Item>
+            {/* ====================定向描述========================= */}
+            <Form.Item label={<strong>定向描述</strong>} name='description' >
+                <Input.TextArea placeholder='定向名称' style={{ width: 300 }} rows={2} />
+            </Form.Item>
+            {/* ============================================================排期与出价============================================================= */}
+            <Divider orientation='left'>人口学数学</Divider>
+            {/* ====================地理位置========================= */}
+            <Form.Item label={<strong>地理位置</strong>} name='geoLocationType' style={geoLocationType === '1' ? { marginBottom: 5 } : {}}>
+                <Radio.Group >
+                    <Radio.Button value="0">不限</Radio.Button>
+                    <Radio.Button value="1">按区域</Radio.Button>
+                </Radio.Group>
+            </Form.Item>
+            {
+                geoLocationType === '1' && <Form.Item
+                    style={{ marginLeft: 107, marginBottom: 10 }}
+                    name='regions'
+                    rules={[{ type: 'array', max: 1000, message: '最多选择1000' }]}
+                >
+                    <TreeSelect
+                        showSearch={true}
+                        maxTagCount={50}
+                        treeCheckable={true}
+                        showCheckedStrategy={TreeSelect.SHOW_PARENT}
+                        treeData={regionsList}
+                        style={{ width: '100%' }}
+                        allowClear
+                        filterTreeNode={(inputValue: string, treeNode: any) => {
+                            if (treeNode.title.includes(inputValue)) {
+                                return true
+                            } else {
+                                return false
+                            }
+                        }}
+                    />
+                </Form.Item>
+            }
+            {/* ====================年龄========================= */}
+            <Form.Item label={<strong>年龄</strong>} name='ageType' style={ageType === '1' ? { marginBottom: 5 } : {}}>
+                <Radio.Group >
+                    <Radio.Button value="0">不限</Radio.Button>
+                    <Radio.Button value="1">自定义</Radio.Button>
+                </Radio.Group>
+            </Form.Item>
+            {
+                ageType === '1' && <div style={{ display: 'flex', justifyContent: 'left', alignItems: 'center' }}>
+                    <Form.Item style={{ marginLeft: 107 }} name='age_min'>
+                        <Select style={{ width: 120 }} >
+                            {
+                                Array(66 - 13).fill('').map((n, i) => i + 14).filter(i => i !== 15 && i !== 16 && i !== 17).map(i => {
+                                    return <Select.Option disabled={i > age_max} value={i} key={i}>{i === 66 ? '66 岁及以上' : i + ' 岁'}</Select.Option>
+                                })
+
+                            }
+
+                        </Select>
+                    </Form.Item>
+                    <Form.Item style={{ marginLeft: 10 }} name='age_max'>
+                        <Select style={{ width: 120 }}>
+                            {
+                                Array(66 - 17).fill('').map((n, i) => {
+                                    return <Select.Option disabled={i + 18 < age_min} value={i + 18} key={i + 18}>{i + 18 === 66 ? '66 岁及以上' : i + 18 + ' 岁'}</Select.Option>
+                                })
+                            }
+
+                        </Select>
+                    </Form.Item>
+                </div>
+            }
+            {/* ====================性别========================= */}
+            <Form.Item label={<strong>性别</strong>} name='gender'>
+                <Radio.Group >
+                    <Radio.Button value="0">不限</Radio.Button>
+                    {
+                        Object.keys(GenderEnum).map(key => {
+                            return <Radio.Button value={key} key={key}>{GenderEnum[key]}</Radio.Button>
+                        })
+                    }
+
+                </Radio.Group>
+            </Form.Item>
+            {/* ====================学历========================= */}
+            <Form.Item label={<strong>学历</strong>} name='educationType' style={educationType === '1' ? { marginBottom: 5 } : {}}>
+                <Radio.Group >
+                    <Radio.Button value="0">不限</Radio.Button>
+                    <Radio.Button value="1">自定义</Radio.Button>
+                </Radio.Group>
+            </Form.Item>
+            {
+                educationType === '1' && <Form.Item style={{ marginLeft: 107 }} name='education'>
+                    <Checkbox.Group options={Object.keys(EducationEnum).map(key => ({ label: EducationEnum[key], value: key }))} />
+                </Form.Item>
+            }
+            {/* ====================婚恋育儿状态========================= */}
+            <Form.Item label={<strong>婚恋育儿状态</strong>} name='maritalStatusType' style={maritalStatusType === '1' ? { marginBottom: 5 } : {}}>
+                <Radio.Group >
+                    <Radio.Button value="0">不限</Radio.Button>
+                    <Radio.Button value="1">自定义</Radio.Button>
+                </Radio.Group>
+            </Form.Item>
+            {
+                maritalStatusType === '1' && <Form.Item style={{ marginLeft: 107 }} name='maritalStatus'>
+                    <Checkbox.Group options={Object.keys(MaritalStatusEnum).map(key => ({ label: MaritalStatusEnum[key], value: key }))} />
+                </Form.Item>
+            }
+
+            {/* ============================================================用户行为============================================================= */}
+            <Divider orientation='left'>用户行为</Divider>
+            {/* <Form.Item label={<strong>行为兴趣意向</strong>} name='behaviorOrInterestType'>
+                <Radio.Group >
+                    <Radio.Button value="0">不限</Radio.Button>
+                    <Radio.Button value="1">自定义</Radio.Button>
+                </Radio.Group>
+            </Form.Item> */}
+            {/* ====================排除已转化用户========================= */}
+            <Form.Item label={<strong>排除已转化用户</strong>} name='excludedDimension' style={excludedDimension !== '0' ? { marginBottom: 5 } : {}}>
+                <Radio.Group >
+                    <Radio.Button value="0">不限</Radio.Button>
+                    {
+                        Object.keys(ExcludedDimensionEnum).map(key => {
+                            return <Radio.Button value={key} key={key}>{ExcludedDimensionEnum[key]}</Radio.Button>
+                        })
+                    }
+                </Radio.Group>
+            </Form.Item>
+            {
+                excludedDimension !== '0' && <Form.Item style={{ marginLeft: 107 }} name='conversionBehaviorList'>
+                    <Select style={{ width: 300 }} showSearch filterOption={(input, option) =>
+                        (option!.children as unknown as string).toLowerCase().includes(input.toLowerCase())
+                    } allowClear placeholder='转化行为,不选为默认行为'>
+                        {
+                            Object.keys(OptimizationGoalEnum).map(key => {
+                                return <Select.Option value={key} key={key}>{OptimizationGoalEnum[key]}</Select.Option>
+                            })
+                        }
+                    </Select>
+                </Form.Item>
+            }
+            {/* ============================================================自定义人群============================================================= */}
+            {/* <Divider orientation='left'>自定义人群</Divider> */}
+            {/* ====================自定义人群========================= */}
+            {/* <Form.Item label={<strong>自定义人群</strong>} name='customAudienceType'>
+                <Radio.Group >
+                    <Radio.Button value="0">不限</Radio.Button>
+                    <Radio.Button value="1">自定义</Radio.Button>
+                </Radio.Group>
+            </Form.Item> */}
+
+            {/* ============================================================设备定向============================================================= */}
+            <Divider orientation='left'>设备定向</Divider>
+            {/* ====================设备品牌型号========================= */}
+            <Form.Item label={<strong>设备品牌型号</strong>} name='deviceBrandModelType' style={deviceBrandModelType === '1' ? { marginBottom: 5 } : {}}>
+                <Radio.Group >
+                    <Radio.Button value="0">不限</Radio.Button>
+                    <Radio.Button value="1">自定义</Radio.Button>
+                </Radio.Group>
+            </Form.Item>
+            {
+                deviceBrandModelType === '1' && <>
+                    <Form.Item style={{ marginLeft: 107, marginBottom: 10 }}
+                        name='deviceBrandModelList'
+                        rules={[{ type: 'array', max: 400, message: '最多选择400个设备型号' }]}
+                    >
+                        <TreeSelect
+                            showSearch={true}
+                            maxTagCount={50}
+                            treeCheckable={true}
+                            showCheckedStrategy={TreeSelect.SHOW_CHILD}
+                            treeData={modelList}
+                            style={{ width: '100%' }}
+                            allowClear
+                            filterTreeNode={(inputValue: string, treeNode: any) => {
+                                if (treeNode.title.includes(inputValue)) {
+                                    return true
+                                } else {
+                                    return false
+                                }
+                            }}
+                        />
+                    </Form.Item>
+                    <Form.Item name='isexcluded' valuePropName="checked" style={{ marginLeft: 107, marginBottom: 10 }} >
+                        <Checkbox ><p style={{
+                            position: 'absolute',
+                            width: '95%',
+                            top: '50%',
+                            transform: 'translate(0, -50%)'
+                        }}>排除所选设备的用户 <span style={{ float: 'right' }}>已选 <span style={deviceBrandModelList?.length > 400 ? { color: 'red' } : {}}>{deviceBrandModelList?.length ?? 0}</span>/400</span></p></Checkbox>
+                    </Form.Item>
+                </>
+            }
+            {/* ====================操作系统版本========================= */}
+            <Form.Item label={<strong>操作系统版本</strong>} name='userOsType' style={userOsType === '1' ? { marginBottom: 5 } : {}}>
+                <Radio.Group >
+                    <Radio.Button value="0">不限</Radio.Button>
+                    <Radio.Button value="1">自定义</Radio.Button>
+                </Radio.Group>
+            </Form.Item>
+            {
+                userOsType === '1' && <>
+                    <Form.Item style={{ marginLeft: 107, marginBottom: 0 }} name='userOsIosAll' valuePropName="checked" getValueFromEvent={(e) => {
+                        let checked = e.target.checked
+                        form.setFieldsValue({ userOsIos: checked ? ios_os : [] })
+                        setIndeterminateIos(false)
+                    }}>
+                        <Checkbox indeterminate={indeterminateIos} >
+                            IOS全选
+                        </Checkbox>
+                    </Form.Item>
+                    <Form.Item style={{ marginLeft: 107 }} name='userOsIos' >
+                        <Checkbox.Group
+                            options={
+                                ios_os.map(key => {
+                                    return { label: UserOsEnum[key], value: key }
+                                })
+                            }
+                        />
+                    </Form.Item>
+                    <Form.Item style={{ marginLeft: 107, marginBottom: 0 }} name='userOsAndroidAll' valuePropName="checked" getValueFromEvent={(e) => {
+                        let checked = e.target.checked
+                        form.setFieldsValue({ userOsAndroid: checked ? android_os : [] })
+                        setIndeterminateAndroid(false)
+                    }}>
+                        <Checkbox indeterminate={indeterminateAndroid}>
+                            Android全选
+                        </Checkbox>
+                    </Form.Item>
+                    <Form.Item style={{ marginLeft: 107 }} name='userOsAndroid'>
+                        <Checkbox.Group
+                            options={
+                                android_os.map(key => {
+                                    return { label: UserOsEnum[key], value: key }
+                                })
+                            }
+                        />
+                    </Form.Item>
+                </>
+            }
+            {/* ====================联网方式========================= */}
+            <Form.Item label={<strong>联网方式</strong>} name='networkType' style={networkType === '1' ? { marginBottom: 5 } : {}}>
+                <Radio.Group >
+                    <Radio.Button value="0">不限</Radio.Button>
+                    <Radio.Button value="1">自定义</Radio.Button>
+                </Radio.Group>
+            </Form.Item>
+            {
+                networkType === '1' && <Form.Item style={{ marginLeft: 107 }} name='network'>
+                    <Checkbox.Group options={Object.keys(NetworkEnum).map(key => ({ label: NetworkEnum[key], value: key }))} />
+                </Form.Item>
+            }
+            {/* ====================设备价格========================= */}
+            <Form.Item label={<strong>设备价格</strong>} name='devicePriceType' style={devicePriceType === '1' ? { marginBottom: 5 } : {}}>
+                <Radio.Group >
+                    <Radio.Button value="0">不限</Radio.Button>
+                    <Radio.Button value="1">自定义</Radio.Button>
+                </Radio.Group>
+            </Form.Item>
+            {
+                devicePriceType === '1' && <Form.Item style={{ marginLeft: 107 }} name='devicePrice'>
+                    <Checkbox.Group options={Object.keys(DevicePriceEnum).map(key => ({ label: DevicePriceEnum[key], value: key }))} />
+                </Form.Item>
+            }
+            {/* ============================================================流量方数学============================================================= */}
+            <Divider orientation='left'>流量方数学</Divider>
+            {/* ====================微信再营销========================= */}
+            <Form.Item label={<strong>微信再营销</strong>} name='wechatAdBehaviorType' style={wechatAdBehaviorType === '1' ? { marginBottom: 5 } : {}}>
+                <Radio.Group >
+                    <Radio.Button value="0">不限</Radio.Button>
+                    <Radio.Button value="1">自定义</Radio.Button>
+                </Radio.Group>
+            </Form.Item>
+            {
+                wechatAdBehaviorType === '1' && <>
+                    <p style={{ marginBottom: 5, marginLeft: 107 }}><strong style={{ marginRight: 20 }}>再营销</strong></p>
+                    <Form.Item style={{ marginLeft: 107, marginBottom: 10 }} name='actions'>
+                        <Checkbox.Group options={Object.keys(WechatAdBehaviorEnum).map(key => ({ label: WechatAdBehaviorEnum[key], value: key, disabled: excludedActions?.some((k: string) => k === key) }))} />
+                    </Form.Item>
+                    <p style={{ marginBottom: 5, marginLeft: 107 }}><strong style={{ marginRight: 20 }}>排除营销</strong></p>
+                    <Form.Item style={{ marginLeft: 107 }} name='excludedActions'>
+                        <Checkbox.Group options={Object.keys(WechatAdBehaviorEnum).map(key => ({ label: WechatAdBehaviorEnum[key], value: key, disabled: actions?.some((k: string) => k === key) }))} />
+                    </Form.Item>
+                </>
+            }
+        </Form>
+    </Modal >
+}
+export default AdModal

+ 30 - 0
src/pages/launchSystemNew/launchManage/localAd/targeting/tableConfig.tsx

@@ -0,0 +1,30 @@
+import { PromotedObjectType } from '@/services/launchAdq/enum'
+function tableConfig():any{
+    return [
+        {
+            title: 'ID',
+            dataIndex: 'id',
+            key: 'id',
+            align: 'center',
+        },
+        {
+            title: '定向名称',
+            dataIndex: 'targetingName',
+            key: 'targetingName',
+            align: 'center',
+        },
+        {
+            title: '定向描述',
+            dataIndex: 'description',
+            key: 'description',
+            align: 'center',
+        },
+        {
+            title: '创建时间',
+            dataIndex: 'createTime',
+            key: 'createTime',
+            align: 'center',
+        },
+    ]
+}
+export default tableConfig

+ 53 - 0
src/services/launchAdq/creative.ts

@@ -0,0 +1,53 @@
+import { request } from 'umi';
+import { ListData } from '.';
+import { api } from '../api';
+
+/**
+ * 获取广告组列表
+ * @param adgroupName 广告名称
+ * @param promotedObjectType 广告类型
+ */
+export async function getSysAdcreativeList(params: {
+  pageNum: number;
+  pageSize: number;
+  adcreativeName?: string;
+  promotedObjectType?: string;
+}){
+  return request(api + '/adq/sysAdcreative/list', {
+    method: 'POST',
+    data: params,
+  })
+}
+/**
+ * 获取广告详情
+ * @param AdcreativeId 广告ID
+ */ 
+ export async function getSysAdcreativeInfo(AdcreativeId: string){
+    return request(api + `/adq/sysAdcreative/${AdcreativeId}`)
+  }
+/**
+ * 新增广告
+ * */ 
+export async function createSysAdcreative(params:any){
+    return request(api+`/adq/sysAdcreative`,{
+        method:'POST',
+        data:params
+    })
+}
+/**
+ * 编辑广告
+ * */ 
+export async function editSysAdcreative(AdcreativeId:string,params:any){
+    return request(api+`/adq/sysAdcreative/${AdcreativeId}`,{
+        method:'PUT',
+        data:params
+    })
+}
+/**
+ * 删除广告
+ * */ 
+export async function delSysAdcreative(AdcreativeId:string){
+    return request(api+`/adq/sysAdcreative/${AdcreativeId}`,{
+        method:'DELETE',
+    })
+}

+ 151 - 15
src/services/launchAdq/enum.ts

@@ -1,17 +1,38 @@
 /**广告组推广目标类型*/
 export enum PromotedObjectType {
-  'PROMOTED_OBJECT_TYPE_LINK' = '网页',
-  'PROMOTED_OBJECT_TYPE_LINK_WECHAT' = '品牌网页',
-  'PROMOTED_OBJECT_TYPE_ECOMMERCE' = '商品推广',
-  'PROMOTED_OBJECT_TYPE_APP_ANDROID' = 'Android应用',
-  'PROMOTED_OBJECT_TYPE_APP_IOS' = 'IOS应用',
-  'PROMOTED_OBJECT_TYPE_APP_ANDROID_MYAPP' = '应用宝推广',
-  'PROMOTED_OBJECT_TYPE_APP_ANDROID_UNION' = 'Android应用(优量汇推广)',
-  'PROMOTED_OBJECT_TYPE_LOCAL_ADS_WECHAT' = '本地门店',
-  'PROMOTED_OBJECT_TYPE_QQ_BROWSER_MINI_PROGRAM' = 'QQ浏览器小程序',
-  'PROMOTED_OBJECT_TYPE_QQ_MESSAGE' = 'QQ消息',
-  'PROMOTED_OBJECT_TYPE_LEAD_AD' = '销售线索',
+  PROMOTED_OBJECT_TYPE_WECHAT_OFFICIAL_ACCOUNT = '微信公众号',
+  PROMOTED_OBJECT_TYPE_LEAD_AD = '销售线索',
+  PROMOTED_OBJECT_TYPE_LINK = '网页',
+  PROMOTED_OBJECT_TYPE_LINK_WECHAT = '品牌网页',
+  PROMOTED_OBJECT_TYPE_ECOMMERCE = '商品推广',
+  PROMOTED_OBJECT_TYPE_APP_ANDROID = 'Android应用',
+  PROMOTED_OBJECT_TYPE_APP_IOS = 'IOS应用',
+  PROMOTED_OBJECT_TYPE_APP_ANDROID_MYAPP = '应用宝推广',
+  PROMOTED_OBJECT_TYPE_APP_ANDROID_UNION = 'Android应用(优量汇推广)',
+  PROMOTED_OBJECT_TYPE_LOCAL_ADS_WECHAT = '本地门店',
+  PROMOTED_OBJECT_TYPE_QQ_BROWSER_MINI_PROGRAM = 'QQ浏览器小程序',
+  PROMOTED_OBJECT_TYPE_QQ_MESSAGE = 'QQ消息',
 }
+// {
+//     PROMOTED_OBJECT_TYPE_LINK='网页',
+//     PROMOTED_OBJECT_TYPE_LINK_WECHAT='品牌网页',
+//     PROMOTED_OBJECT_TYPE_ECOMMERCE='商品推广',
+//     PROMOTED_OBJECT_TYPE_APP_ANDROID='Android应用',
+//     PROMOTED_OBJECT_TYPE_APP_QUICK_APP='快应用',
+//     PROMOTED_OBJECT_TYPE_APP_IOS= 'IOS应用',
+//     PROMOTED_OBJECT_TYPE_APP_ANDROID_MYAPP= '应用宝推广',
+//     PROMOTED_OBJECT_TYPE_APP_ANDROID_UNION = 'Android应用(优量汇推广)',
+//     PROMOTED_OBJECT_TYPE_LOCAL_ADS_WECHAT= '本地门店',
+//     PROMOTED_OBJECT_TYPE_QQ_MESSAGE = 'QQ消息',
+//     PROMOTED_OBJECT_TYPE_LEAD_AD= '销售线索',
+//     PROMOTED_OBJECT_TYPE_MINI_GAME_WECHAT= '微信小游戏',
+//     PROMOTED_OBJECT_TYPE_MINI_GAME_QQ='QQ小游戏',
+//     // PROMOTED_OBJECT_TYPE_MINI_PROGRAM_WECHAT,
+//     PROMOTED_OBJECT_TYPE_WECHAT_CHANNELS='微信视频号',
+//     PROMOTED_OBJECT_TYPE_WECHAT_OFFICIAL_ACCOUNT='微信公众号',
+//     PROMOTED_OBJECT_TYPE_LOCAL_ADS='本地广告,仅可读'
+// }
+
 /**计费类型*/
 export enum BillingEventEnum {
   BILLINGEVENT_CLICK = '按点击扣费',
@@ -73,7 +94,37 @@ export enum OptimizationGoalEnum {
   OPTIMIZATIONGOAL_OPEN_ACCOUNT = '券商开户',
   OPTIMIZATIONGOAL_SEVEN_DAY_ECOMMERCE_ORDER = '7日下单',
 }
-
+/**推广计划类型*/
+export enum CampaignTypeEnum {
+  CAMPAIGN_TYPE_NORMAL = '普通展示广告',
+  CAMPAIGN_TYPE_WECHAT_MOMENTS = '微信朋友圈广告',
+}
+/**普通展示广告创意推广目标类型*/
+export enum NormalCreativePromotedObjectTypeEnum {
+  PROMOTED_OBJECT_TYPE_LINK = '	网页',
+  PROMOTED_OBJECT_TYPE_LINK_WECHAT = '品牌网页',
+  PROMOTED_OBJECT_TYPE_ECOMMERCE = '商品推广',
+  PROMOTED_OBJECT_TYPE_APP_ANDROID = 'Android应用',
+  PROMOTED_OBJECT_TYPE_APP_IOS = 'IOS应用',
+  PROMOTED_OBJECT_TYPE_APP_ANDROID_MYAPP = '应用宝推广',
+  PROMOTED_OBJECT_TYPE_APP_ANDROID_UNION = 'Android应用(优量汇推广)',
+  PROMOTED_OBJECT_TYPE_LOCAL_ADS_WECHAT = '本地门店',
+  PROMOTED_OBJECT_TYPE_QQ_MESSAGE = 'QQ 消息',
+  PROMOTED_OBJECT_TYPE_LEAD_AD = '销售线索',
+  PROMOTED_OBJECT_TYPE_MINI_GAME_WECHAT = '微信小游戏',
+  PROMOTED_OBJECT_TYPE_APP_QUICK_APP = '快应用',
+  PROMOTED_OBJECT_TYPE_WECHAT_OFFICIAL_ACCOUNT = '微信公众号',
+}
+/**微信朋友圈广告创意推广目标类型*/
+export enum WechatCreativePromotedObjectTypeEnum {
+  PROMOTED_OBJECT_TYPE_LINK_WECHAT = '品牌网页',
+  PROMOTED_OBJECT_TYPE_LOCAL_ADS_WECHAT = '本地门店',
+  PROMOTED_OBJECT_TYPE_ECOMMERCE = '商品推广',
+  PROMOTED_OBJECT_TYPE_APP_ANDROID = '	Android应用',
+  PROMOTED_OBJECT_TYPE_APP_IOS = 'IOS应用',
+  PROMOTED_OBJECT_TYPE_LEAD_AD = '销售线索',
+  PROMOTED_OBJECT_TYPE_MINI_GAME_WECHAT = '微信小游戏',
+}
 /**性别枚举*/
 export enum GenderEnum {
   MALE = '男性',
@@ -89,11 +140,49 @@ export enum EducationEnum {
   PRIMARY = '小学',
   JUNIOR_COLLEGE = '专科',
 }
+/**育儿*/
+export enum MaritalStatusEnum {
+  SINGLE = '单身',
+  IN_LOVE = '热恋',
+  NEWLY_MARRIED = '新婚',
+  MARRIED = '已婚',
+  PARENTING = '育儿',
+  PARENTING_0 = '育儿(孕育中)',
+  PARENTING_0_6 = '育儿(宝宝 0-6=个月)',
+  PARENTING_6_12 = '育儿(宝宝 6-12个月)',
+  PARENTING_12_24 = '育儿(宝宝 1-2岁)',
+  PARENTING_24_36 = '育儿(宝宝 2-3岁)',
+  CHILD_PRE_SCHOOL = '育儿(孩子 3-6周岁)',
+  CHILD_PRIMARY_SCHOOL = '育儿(孩子 6-12周岁)',
+  CHILD_JUNIOR_SCHOOL = '育儿(孩子 12-15周岁)',
+  CHILD_HIGH_SCHOOL = '育儿(孩子 15-18周岁)',
+}
+/**排除已转化用户定向范围*/
+export enum ExcludedDimensionEnum {
+  EXCLUDED_DIMENSION_CAMPAIGN = '同计划广告',
+  EXCLUDED_DIMENSION_UID = '同账号广告',
+  EXCLUDED_DIMENSION_BUSINESS_MANAGER = '同商务管家广告',
+  EXCLUDED_DIMENSION_COMPANY_ACCOUNT = '同主体广告',
+  EXCLUDED_DIMENSION_APP = '同应用',
+  EXCLUDED_DIMENSION_PRODUCT = '同商品',
+}
+
 /**广告版位*/
 export enum SiteSetEnum {
-  SITE_SET_MOMENTS = '微信朋友圈',
-  SITE_SET_MINI_GAME_WECHAT = '微信小游戏',
+  // "SITE_SET_KANDIAN"="腾讯看点",
+  // "SITE_SET_MINI_GAME_QQ"="QQ小游戏",
+  // "SITE_SET_MINI_GAME_WECHAT"="微信小游戏",
+  // "SITE_SET_MOBILE_GAME"="App游戏",
+  // "SITE_SET_MOBILE_MYAPP"="应用宝移动",
+  // "SITE_SET_MOBILE_UNION"="优量汇",
+  // "SITE_SET_MOBILE_YYB"="应用宝",
+  'SITE_SET_MOMENTS' = '微信朋友圈',
+  // "SITE_SET_QQ_MUSIC_GAME"="QQ、腾讯音乐及游戏",
+  // "SITE_SET_TENCENT_NEWS"="腾讯新闻",
+  // "SITE_SET_TENCENT_VIDEO"="腾讯视频",
+  'SITE_SET_WECHAT' = '微信公众号与小程序',
 }
+/***/
 /**出价方式*/
 export enum BidModeEnum {
   BID_MODE_OCPM = 'oCPM',
@@ -106,6 +195,53 @@ export enum BidModeEnum {
 export enum BidStrategyEnum {
   BID_STRATEGY_AVERAGE_COST = '稳定拿量',
   BID_STRATEGY_TARGET_COST = '优先拿量',
-//   BID_STRATEGY_PRIORITY_LOW_COST = '优先低成本',
+  //   BID_STRATEGY_PRIORITY_LOW_COST = '优先低成本',
   BID_STRATEGY_PRIORITY_CAP_COST = '控制成本上限',
 }
+
+/**操作系统*/
+export enum UserOsEnum {
+  IOS_VERSION_4 = ' iOS 4.x',
+  IOS_VERSION_5 = 'iOS 5.x',
+  IOS_VERSION_6 = 'iOS 6.x',
+  IOS_VERSION_7 = 'iOS 7.x',
+  IOS_VERSION_8 = 'iOS 8.x',
+  IOS_VERSION_9 = 'iOS 9.x',
+  IOS_VERSION_10 = 'iOS 10.x',
+  IOS_VERSION_11 = 'iOS 11.x',
+  IOS_VERSION_12 = 'iOS 12.x',
+  IOS_VERSION_13 = 'iOS 13.x',
+  IOS_VERSION_14 = 'iOS 14.x',
+  ANDROID_VERSION_1 = 'Android 1.x',
+  ANDROID_VERSION_2 = 'Android 2.x',
+  ANDROID_VERSION_3 = 'Android 3.x',
+  ANDROID_VERSION_4 = 'Android 4.x',
+  ANDROID_VERSION_5 = 'Android 5.x',
+  ANDROID_VERSION_6 = 'Android 6.x',
+  ANDROID_VERSION_7 = 'Android 7.x',
+  ANDROID_VERSION_8 = 'Android 8.x',
+  ANDROID_VERSION_9 = 'Android 9.x',
+  ANDROID_VERSION_10 = 'Android 10.x',
+}
+/**设备价格*/
+export enum DevicePriceEnum {
+  PRICE_1500_LESS = '¥ 1500 以下',
+  PRICE_1500_2500 = '¥ 1500 ~ 2500',
+  PRICE_2500_3500 = '¥ 2500 ~ 3500',
+  PRICE_3500_4500 = '¥ 3500 ~ 4500',
+  PRICE_4500_MORE = '¥ 4500 以上',
+}
+/**联网方式*/
+export enum NetworkEnum {
+  WIFI = '无线网络',
+  NET_2G = '2G 网络',
+  NET_3G = '3G 网络',
+  NET_4G = '4G 网络',
+  NET_5G = '5G 网络',
+}
+/**联网方式*/
+export enum WechatAdBehaviorEnum{
+  WECHAT_OFFICIAL_ACCOUNT_AD_LIKE='曾对你的公众号广告感兴趣',
+  WECHAT_MOMENTS_AD_LIKE='曾对你的朋友圈广告感兴趣',
+  MINI_GAME_WECHAT_REGISTERED='已关注过你的公众号'
+ }

+ 12 - 0
src/services/launchAdq/global.ts

@@ -0,0 +1,12 @@
+import { request } from 'umi';
+import { api } from '../api';
+/**
+ * 定向标签获取
+ * 
+*/
+export async function getTagsList(params:any){
+    return request(api+`/adq/launch/tools/targeting/tags/list`,{
+        method:'POST',
+        data:params
+    })
+}

+ 342 - 2
src/services/launchAdq/index.d.ts

@@ -1,4 +1,5 @@
 import { PromotedObjectType } from './enum';
+/**==============================================================================广告=======================================================================================*/ 
 /**推广目标类型*/
 export interface SysPromotedObjectDTO {
   promotedObjectType: PromotedObjectType;
@@ -68,7 +69,7 @@ export interface UnbreakableTargetingSetting {
 export interface SmartTargeting {
     smartTargetingVersion: number,
     smartTargetingSwitch: Boolean,
-    startAudience: List<number>,
+    startAudience: Array<number>,
     unbreakableTargeting: UnbreakableTargetingSetting,
 }
 
@@ -122,7 +123,346 @@ export interface SysAdgroupsDTO {
   customAdgroupTag: Array<string>; //广告标签
   smartTargeting: SmartTargeting; //智能定向功能,功能灰度开放,如需使用可联系您的运营接口同学。
 }
-// 列表接口返回数据
+/**==============================================================================创意=======================================================================================*/ 
+
+export interface AdcreativeCreativeElementsMp {
+    image: string,//图片
+    image2: string,//图片
+    image3: string,
+    title: string,
+    description: string,
+    corporate: AdcreativeCorporate,
+    video: string,
+    deepLinkType: string,
+    linkNameType: LinkNameType,
+    imageList: Array<string>,
+    elementStory: Array<AdcreativeElementStoryArrayItem>,
+    url: string,
+    buttonText: string,
+    bottomText: string,
+    excitationText: string,
+    countdownBegin: number,
+    countdownExpiringTimestamp: number,
+    countdownPrice: string,
+    countdownTimeType: AdCreativeCountdownTimeType,
+    label: Array<CreativeLabel>,
+    productTags: Array<string>,
+    logoDescription: string,
+    logo: string,
+    leftBottomTxt: string,
+    animationEffect: string,
+    phone: string,
+    shortVideoStruct: ShortVideoStruct,
+    longVideoStruct: numberVideoStruct,
+    bannerContent: AdcreativeBannerContent,
+    cardContent: AdcreativeCardContent,
+    videoPopupButton: AdcreativeVideoPopupButton,
+    buttonUrl: string,
+    brand: AdCreativeBrand,
+    caption: string,
+    labelledImg: AdcreativeLabelledImg,
+    fullScreenImage: string,
+    zipUrl: string,
+    endPage: AdCreativeEndPage,
+    headLine: string,
+    shopImageStruct: AdCreativeShopImageStruct,
+    chosenButton: ChosenButton,
+    livingDescStruct: AdCreativeLivingDescStruct,
+    leftButton: string,
+    rightButton: string,
+    leftCanvas: string,
+    rightCanvas: string,
+    floatingZoneStruct: FloatingZone,
+    canvasShareImage: string,
+    wegameInfoSpec: WegameInfoSpec,
+}
+
+export interface AdcreativeElementStoryArrayItem {
+    image: string,
+    image2: string,
+    description: string,
+    url: string,
+    title: string,
+}
+
+export interface CreativeLabel {
+    content: string,
+    type: LabelType,
+}
+
+export interface ShortVideoStruct {
+    shortVideo1: number,
+    shortVideo2: number,
+}
+
+export interface numberVideoStruct {
+    longVideo1: number,
+    longVideo2: number,
+}
+
+export interface AdcreativeBannerContent {
+    image: string,
+    title: string,
+    url: string,
+}
+
+export interface AdcreativeCardContent {
+    image: string,
+    description: string,
+    url: string,
+}
+
+export interface AdcreativeVideoPopupButton {
+    videoPopupButtonText: string,
+    videoPopupButtonUrl: string,
+}
+
+export interface AdCreativeBrand {
+    brandName: string,
+    brandImg: string,
+    brandDescription: string,
+}
+
+export interface AdcreativeLabelledImg {
+    image: string,
+    label: Array<AdcreativeLabel>,
+}
+
+export interface AdCreativeEndPage {
+    endPageType: string,
+    endPageDesc: string,
+}
+
+export interface AdCreativeShopImageStruct {
+    shopImageSwitch: boolean,
+    dynamicShopImageSwitch: boolean,
+    shopImageId: string,
+    shopImageTitle: string,
+    shopImageDescription: string,
+}
+
+export interface ChosenButton {
+    chosenButtonText1: string,
+    chosenButtonLandingPage1: LandingPageStructure,
+    chosenButtonText2: string,
+    chosenButtonLandingPage2: LandingPageStructure,
+}
+
+export interface AdCreativeLivingDescStruct {
+    livingDescStructSwitch: boolean,
+    livingDescList: Array<string>,
+}
+
+export interface FloatingZone {
+    floatingZoneSwitch: boolean,
+    floatingZoneImageId: string,
+    floatingZoneName: string,
+    floatingZoneDesc: string,
+    floatingZoneButtonText: string,
+    floatingZoneType: FloatingZoneType,
+    floatingZoneSingleImageId: string,
+}
+
+export interface WegameInfoSpec {
+    wegameInfoSwitch: boolean,
+}
+/**落地页信息,根据不同 promoted_object_type 和 page_type,要求的 page_spec 信息不同*/ 
+export interface PageSpec {
+    pageId: number,//落地页 id
+    pageUrl: string,//落地页 url
+    miniProgramSpec: {//小程序落地页,mini_program_id 和 mini_program_path 要同时填写
+        miniProgramId:string,//小程序 id
+        miniProgramPath?:string,//小程序路径
+        miniProgramPaths?:string[],//小程序落地页 path 列表
+    },
+    miniGameSpec: {
+        miniGameTrackingParameter:string,//小游戏监控参数,需以英文字符?开头
+        miniGameOpenlink:string,//openlink 地址字段
+
+    },
+    overrideCanvasHeadOption: string,//原生推广页顶部素材和广告创意素材之间的替换关系,
+    dynamicProductSpec: {
+        pageUrl:string,//动态落地页 url
+        miniProgramPaths:string[],//动态多商品广告小程序落地页 path 列表
+        miniGameOpenlinkPageSpec:{//小游戏蹊径落地页,当投放版位含优量汇时、推广目标是微信小游戏推广目标时
+            landingPageType:string,//openlink 落地页页面类型,不大于 1024 个英文字符或数字
+            landingPageId:number,//落地页 id
+        }
+    },
+}
+/**文字链跳转信息,根据不同 promoted_object_type 和 page_type、link_page_type,要求的 link_page_spec 信息不同*/ 
+export interface LinkPageSpec {
+    pageId: number,//	落地页 id
+    pageUrl: string,//落地页 url
+    miniProgramSpec: {//小程序落地页,mini_program_id 和 mini_program_path 要同时填写
+        miniProgramId:string,//小程序 id
+        miniProgramPath?:string,//小程序路径
+        miniProgramPaths?:string[],//小程序落地页 path 列表
+    },
+    miniGameSpec: {//小游戏落地页信息
+        miniGameTrackingParameter:string//小游戏监控参数,需以英文字符?开头
+    },
+}
+/**简版原生页分享信息*/ 
+export interface ShareContentSpec {
+    shareTitle: string,//简版原生页分享标题,字段长度最小 1 个等宽字符,长度最大 14 个等宽字符(即字段最大长度为 14 个中文字或全角标点,28 个英文字或半角标点。一个等宽字符等价于一个中文,等价于两个英文。)
+    shareDescription: string,//简版原生页分享描述,字段长度最小 1 个等宽字符,长度最大 20 个等宽字符(即字段最大长度为 20 个中文字或全角标点,40 个英文字或半角标点。一个等宽字符等价于一个中文,等价于两个英文。)
+}
+/**动态商品广告属性,当创意为动态商品广告创意时,该字段必填*/ 
+export interface DynamicAdcreativeSpec {
+    productCatalogId: number,//商品库 id
+    productMode: AdNum,//动态商品广告(DPA)类型
+    productSource: string,//动态商品广告所使用的商品信息,可以填入商品系列 id 或者商品 id
+    productExposureQuantityMode: string,//动态商品广告推荐的商品数量模式,当广告形态为动态多商品广告时该字段必填
+    landingPageUrlType: string,//MDPA 落地页类型,当创意为动态多商品广告创意时,该字段必填
+}
+/**	视频播放结束页,(当前仅支持互动推广页)*/ 
+export interface VideoEndPageSpec {
+    endPageId: string,//视频播放结束页 id
+    endPageType: string,//视频播放结束页类型
+}
+/**浮层卡片创意内容*/ 
+export interface FloatingZone {
+    floatingZoneSwitch: boolean,//浮层卡片开关
+    floatingZoneImageId: string,//尺寸:512*512,大小:不超过 50 KB,格式:*.jpg|*.jpeg|*.png ;
+    floatingZoneName: string,//文案一,字段长度最小 1 个等宽字符,长度最大 8 等宽字符(即字段最大长度为 8 个中文字或全角标点,16 个英文字或半角标点。一个等宽字符等价于一个中文,等价于两个英文。)
+    floatingZoneDesc: string,//文案二,字段长度最小 0 个等宽字符,长度最大 6 等宽字符(即字段最大长度为 6 个中文字或全角标点,12 个英文字或半角标点。一个等宽字符等价于一个中文,等价于两个英文。)
+    floatingZoneButtonText: string,//按钮文案,字段长度最小 0 个等宽字符,长度最大 4 等宽字符(即字段最大长度为 4 个中文字或全角标点,8 个英文字或半角标点。一个等宽字符等价于一个中文,等价于两个英文。)
+    floatingZoneType: string,//浮层卡片类型
+    floatingZoneSingleImageId: string,//尺寸: 540*276 ,大小:不超过 50 KB,格式:*.jpg|*.jpeg|*.png ;
+}
+/**头像点击跳转信息*/ 
+export interface HeadClickSpec {
+    brandAppId: string,//搜一搜品牌形象 app id
+}
+/**弹幕列表*/ 
+export interface BarrageListCreateStruct {
+    id: number,//弹幕 id
+}
+/**	礼包码,微信朋友圈广告创意形式*/ 
+export interface AppGiftPackCode {
+    code: string,//礼包码,微信朋友圈广告创意形式需要填写,礼包码
+    tips: string,//礼包码提示,微信朋友圈广告创意形式需要填写,礼包码提示
+}
+/**	厂商下载信息*/ 
+export interface UnionMarketSpec {
+    unionMarketJumpType: string,//厂商直达链接跳转类型
+}
+/**安卓快应用跳转信息*/ 
+export interface AndroidQuickAppSpec {
+    androidQuickAppJumpType: string,//安卓快应用跳转类型
+    androidQuickAppJumpUrl: string,//安卓快应用跳转 URL
+}
+/**创意参数*/
+export interface SysAdcreative {
+    adcreativeName: string,//广告创意名称 *
+    adcreativeTemplateId: number,//创意形式 id *
+    adcreativeElements: AdcreativeCreativeElementsMp,//创意元素,不同 adcreative_template_id 要求的元素不尽相同 *
+    promotedObjectType: string,//推广目标类型 *
+    pageType: string,//落地页类型 *
+    automaticSiteEnabled: boolean,//是否开启自动版位功能(暂不包含 SITE_SET_WECHAT 和 SITE_SET_MOMENTS),此字段与 site_set 字段至少需要写入一个。
+    siteSet: Array<string>,//投放版位集合
+    pageSpec: PageSpec,//落地页信息
+    linkPageType: string,//文字链跳转类型类型
+    linkNameType: string,//链接名称类型
+    linkPageSpec: LinkPageSpec,//文字链跳转信息
+    conversionDataType: string,//投放指引,数据展示的数据类型,素材下方展示账户内积累的展示推广目标相关的转化数据,吸引用户点击。
+    conversionTargetType: string,//数据展示转化行为,仅 conversion_data_type 为 CONVERSION_DATA_ADMETRIC 时可设置
+    qqMiniGameTrackingQuerystring: string,//QQ 小游戏监控参数
+    deepLinkUrl: string,//应用直达页 URL,微信朋友圈广告
+    androidDeepLinkAppId: string,//安卓应用直达 AppId
+    iosDeepLinkAppId: string,//IOS 应用直达 AppId
+    universalLinkUrl: string,//通用链接页 URL
+    promotedObjectId: string,//推广目标 id
+    profileId: number,//朋友圈头像昵称跳转页 id
+    shareContentSpec: ShareContentSpec,//简版原生页分享信息
+    dynamicAdcreativeSpec: DynamicAdcreativeSpec,//动态商品广告属性
+    componentId: number,//附加创意组件 id
+    unionMarketSwitch: boolean,//跳转厂商应用商店
+    playablePageMaterialId: string,//互动推广页落地页 id
+    videoEndPage: VideoEndPageSpec,//视频播放结束页,(当前仅支持互动推广页)
+    feedsVideoCommentSwitch: boolean,//视频广告评论开关
+    webviewUrl: string,//简易原生页嵌入 Webview url,和 simple_canvas_sub_type 配合使用
+    simpleCanvasSubType: string,//简版原生页子类型(灰度中),仅在简版原生页下生效,其他情况改字段内容会被忽略
+    floatingZone: FloatingZone,//浮层卡片创意内容
+    marketingPendantImageId: number,//挂件图,悬浮展示在竖版视频上以展示营销卖点
+    countdownSwitch: boolean,//倒计时组件开关
+    headClickType: string,//头像点击跳转信息
+    headClickSpec: HeadClickSpec,//头像点击跳转信息
+    pageTrackUrl: string,//页面级转化跟踪 URL(可选)
+    barrageList: Array<BarrageListCreateStruct>,//弹幕列表
+    appGiftPackCode: AppGiftPackCode,//礼包码,微信朋友圈广告创意形式需要填写,礼包码
+    enableBreakthroughSiteset: boolean,//是否支持版位突破,广告版位选择“微信朋友圈”,当广告有机会获得更多曝光与转化时,将可能投放到微信公众号与小程序版位,若不传值默认为 true
+    industryLabel: string,//行业标签内容
+    unionMarketSpec: UnionMarketSpec,//厂商下载信息,厂商下载信息,仅可在跳转厂商应用商店(union_market_switch)值为 true 时使用。
+    androidQuickAppSpec: AndroidQuickAppSpec,//	安卓快应用跳转信息
+
+} 
+/**==============================================================================定向参数=======================================================================================*/ 
+
+export interface SysTargeting {
+    targetingName: string,//定向名称
+    targeting: WriteTargetingSetting,//定向详细设置,存放所有定向条件
+    description: string,//定向描述
+
+}
+
+export interface WriteTargetingSetting {
+    age: Array<AgeStruct>,//年龄定向
+    gender: Array<string>,//性别定向
+    education: Array<string>,//用户学历
+    maritalStatus: Array<string>,//婚恋育儿状态
+    geoLocation: GeoLocations,//地理位置定向,针对朋友圈广告(campaign_type=CAMPAIGN_TYPE_WECHAT_MOMENTS)地域必填,非朋友圈广告选填
+    userOs: Array<string>,//操作系统定向, 该功能即将下线,仅部分行业灰度开放,如有问题可联系您的客户运营
+    devicePrice: Array<string>,//设备价格定向,该功能即将下线,仅部分行业灰度开放,如有问题可联系您的客户运营
+    deviceBrandModel: DeviceBrandModel,//设备品牌型号定向,该功能即将下线,仅部分行业灰度开放,如有问题可联系您的客户运营
+    networkType: Array<string>,//联网方式定向
+    networkOperator: Array<string>,//移动运营商定向,该功能即将下线,仅部分行业灰度开放,如有问题可联系您的客户运营
+    appInstallStatus: Array<string>,//应用安装(应用用户
+    consumptionStatus: Array<string>,//消费水平
+    gameConsumptionLevel: Array<string>,//游戏消费能力
+    financialSituation: Array<string>,//财产状态,该功能即将下线,仅部分行业灰度开放,如有问题可联系您的客户运营
+    wechatAdBehavior: WechatAdBehavior,//微信再营销,原微信广告行为定向升级为微信再营销,当且仅当投放微信流量
+    customAudience: Array<number>,//自定义定向用户群
+    excludedCustomAudience: Array<number>,//自定义排除用户群
+    behaviorOrInterest: BehaviorOrInterest,//行为兴趣意向定向,2022 年 6 月 30 日起,该定向将无法在竞价 oCPC、oCPM 场景使用
+    excludedConvertedAudience: ExcludedConvertedAudience,//排除已转化用户定向同应用,仅当推广目标为应用下载时可以使用,没有选择自定义转化行为(excluded_dimension)时,使用该定向出价需要满足是 oCPC、oCPM 广告;同商品,仅当 SDPA 商品广告下使用,不支持自定义转化行为默认排除已下单、和已付费用户,不限制出价方式;非同应用、非同商品,没有选择自定义转化行为(excluded_dimension)时,使用该定向出价需要满足是 oCPC、oCPM 广告;
+}
+
+export interface AgeStruct {
+    min: number,
+    max: number,
+}
+export interface GeoLocations {
+    locationTypes: Array<string>,//对于微信流量(site_set=SITE_SET_WECHAT、SITE_SET_MOMENTS、SITE_SET_MINI_GAME_WECHAT),仅能选择"LIVE_IN"(常住);
+    regions: Array<number>,//省市区县列表,当投放微信流量(site_set=SITE_SET_WECHAT、SITE_SET_MOMENTS、SITE_SET_MINI_GAME_WECHAT)时,仅支持中国大陆(不包含港澳台)地域 id
+    businessDistricts: Array<number>,
+    customLocations: Array<CustomLocationsItemWithName>,
+}
+export interface CustomLocationsItemWithName {
+    longitude: Double,
+    latitude: Double,
+    radius: number,
+}
+export interface DeviceBrandModel {
+    includedList: Array<number>,
+    excludedList: Array<number>,
+}
+export interface WechatAdBehavior {
+    actions: Array<string>,
+    excludedActions: Array<string>,
+}
+export interface BehaviorOrInterest {
+    interest: Interest,
+    behavior: Array<BehaviorStruct>,
+    intention: Intention,
+}
+export interface ExcludedConvertedAudience {
+    excludedDimension: string,//排除已转化用户定向范围
+    conversionBehaviorList: Array<string>,//自定义转化行为
+}
+/**==============================================================================列表接口=======================================================================================*/ 
+/**列表接口返回数据*/ 
 export interface ListData<T> {
   countId: number;
   current: number;

+ 18 - 1
src/services/launchAdq/localAd.ts

@@ -29,8 +29,25 @@ export async function getSysAdgroupsList(params: {
  * 新增广告
  * */ 
 export async function createSysAdgroups(params:SysAdgroupsDTO){
-    return request(api+`/sysAdgroups`,{
+    return request(api+`/adq/sysAdgroups`,{
         method:'POST',
         data:params
     })
 }
+/**
+ * 编辑广告
+ * */ 
+export async function editSysAdgroups(adgroupsId:string,params:SysAdgroupsDTO){
+    return request(api+`/adq/sysAdgroups/${adgroupsId}`,{
+        method:'PUT',
+        data:params
+    })
+}
+/**
+ * 删除广告
+ * */ 
+export async function delSysAdgroups(adgroupsId:string){
+    return request(api+`/adq/sysAdgroups/${adgroupsId}`,{
+        method:'DELETE',
+    })
+}

+ 52 - 0
src/services/launchAdq/targeting.ts

@@ -0,0 +1,52 @@
+import { request } from 'umi';
+import { api } from '../api';
+
+/**
+ * 获取广告组列表
+ * @param adgroupName 广告名称
+ * @param promotedObjectType 广告类型
+ */
+export async function getsysTargetingList(params: {
+  pageNum: number;
+  pageSize: number;
+  targetingName?: string;
+  promotedObjectType?: string;
+}){
+  return request(api + '/adq/sysTargeting/list', {
+    method: 'POST',
+    data: params,
+  })
+}
+/**
+ * 获取广告详情
+ * @param AdcreativeId 广告ID
+ */ 
+ export async function getsysTargetingInfo(AdcreativeId: string){
+    return request(api + `/adq/sysTargeting/${AdcreativeId}`)
+  }
+/**
+ * 新增广告
+ * */ 
+export async function createsysTargeting(params:any){
+    return request(api+`/adq/sysTargeting`,{
+        method:'POST',
+        data:params
+    })
+}
+/**
+ * 编辑广告
+ * */ 
+export async function editsysTargeting(AdcreativeId:string,params:any){
+    return request(api+`/adq/sysTargeting/${AdcreativeId}`,{
+        method:'PUT',
+        data:params
+    })
+}
+/**
+ * 删除广告
+ * */ 
+export async function delsysTargeting(AdcreativeId:string){
+    return request(api+`/adq/sysTargeting/${AdcreativeId}`,{
+        method:'DELETE',
+    })
+}