wjx 2 years ago
parent
commit
04971eb27b

+ 7 - 7
src/pages/launchSystemNew/components/adModal/index.tsx

@@ -13,12 +13,12 @@ interface Props {
     visible?: boolean,
     visible?: boolean,
     onClose?: () => void,
     onClose?: () => void,
     onChange?: (data: any) => void,
     onChange?: (data: any) => void,
-    sysAdgroupsId?: number
+    sysAdgroupId?: number
 }
 }
 const AdModal: React.FC<Props> = (props) => {
 const AdModal: React.FC<Props> = (props) => {
 
 
     /**********************/
     /**********************/
-    const { visible, onClose, onChange, promotedObjectType, sysAdgroupsId } = props
+    const { visible, onClose, onChange, promotedObjectType, sysAdgroupId } = props
     const [oldsearchData, setOldsearchData] = useState<any>(null)
     const [oldsearchData, setOldsearchData] = useState<any>(null)
     const sysAdgroupsList: FnAjax<ListData<SysAdgroupsDTO>> = useAjax((params) => getSysAdgroupsList(params))
     const sysAdgroupsList: FnAjax<ListData<SysAdgroupsDTO>> = useAjax((params) => getSysAdgroupsList(params))
     const [selectedRowKeys, setSelectedRowKeys] = useState<React.Key[]>([])
     const [selectedRowKeys, setSelectedRowKeys] = useState<React.Key[]>([])
@@ -26,10 +26,10 @@ const AdModal: React.FC<Props> = (props) => {
 
 
     // 回填
     // 回填
     useEffect(() => {
     useEffect(() => {
-        if (sysAdgroupsId) {
-            setSelectedRowKeys([sysAdgroupsId])
+        if (sysAdgroupId) {
+            setSelectedRowKeys([sysAdgroupId])
         }
         }
-    }, [sysAdgroupsId])
+    }, [sysAdgroupId])
     
     
     // 初始获取列表
     // 初始获取列表
     useEffect(() => {
     useEffect(() => {
@@ -50,8 +50,8 @@ const AdModal: React.FC<Props> = (props) => {
     // 确定
     // 确定
     const handleOk = () => {
     const handleOk = () => {
         if (selectedRowKeys?.length) {
         if (selectedRowKeys?.length) {
-            if (sysAdgroupsId) {
-                if (selectedRowKeys?.indexOf(sysAdgroupsId) === -1) {
+            if (sysAdgroupId) {
+                if (selectedRowKeys?.indexOf(sysAdgroupId) === -1) {
                     onChange && onChange(selectedRowKeys.toString())
                     onChange && onChange(selectedRowKeys.toString())
                 } else {
                 } else {
                     onClose && onClose()
                     onClose && onClose()

+ 169 - 0
src/pages/launchSystemNew/components/crowdPackModal/index.tsx

@@ -0,0 +1,169 @@
+import Tables from "@/components/Tables"
+import { useAjax } from "@/Hook/useAjax"
+import { getCrowdPackApi, sysCrowdPackApi } from "@/services/launchAdq/createAd"
+import { CheckOutlined, SyncOutlined } from "@ant-design/icons"
+import { Button, Input, Modal, Space } from "antd"
+import React, { useEffect, useState } from "react"
+import style from '../goodsModal/index.less'
+import columns from "./tableConfig"
+
+
+const crowdpackData = [
+    {
+        id: 1,
+        name: '定向用户群'
+    },
+    {
+        id: 2,
+        name: '排除用户群'
+    }
+]
+
+/**
+ * 获取人群包列表
+ * @returns 
+ */
+interface Props {
+    visible?: boolean,
+    onClose?: () => void,
+    onChange?: (data: any) => void,
+    data: any
+}
+const CrowdPackModal: React.FC<Props> = (props) => {
+
+    /*****************/
+    const { visible, onClose, data: data1, onChange } = props
+    const [data, setData] = useState<any>(data1)
+    const [tableData, setTableData] = useState<any[]>([])//table数据
+    const [selectAdz, setSelectAdz] = useState<number>(1)   // 选择账户
+    const [selectCp, setSelectCp] = useState<number>(1)   // 选择自定义
+    const [name, setName] = useState<string>('')
+
+    const getCrowdPack = useAjax((params) => getCrowdPackApi(params))
+    const sysCrowdPack = useAjax((params) => sysCrowdPackApi(params))
+    /*****************/
+
+    useEffect(() => {
+        // customAudienceList?: any, excludedCustomAudienceList?: any
+        if (data?.length > 0) {
+            getList([data[selectAdz - 1].adAccountId])
+        } else {
+            setTableData([])
+        }
+    }, [selectAdz])
+
+    const getKey = (index: number, reverse?: boolean) => {
+        if (reverse) {
+            if (index === 1) return 'excludedCustomAudienceList'
+            return 'customAudienceList'
+        } else {
+            if (index === 1) return 'customAudienceList'
+            return 'excludedCustomAudienceList'
+        }
+    }
+
+    // 获取人群包列表
+    const getList = (params: number[]) => {
+        getCrowdPack.run(params).then(res => {
+            console.log('res===>', res)
+            if (res && Object.keys(res)?.indexOf(params[0].toString()) !== -1) {
+                setTableData(res[params[0]]?.map((item: { audienceId: string }) => ({ ...item, id: item.audienceId })))
+            } else {
+                setTableData([])
+            }
+        })
+    }
+
+    const handleOk = () => {
+        onChange && onChange(data)
+    }
+
+    // 同步人群包
+    const synGoodsList = () => {
+        sysCrowdPack.run(data?.map((item: { id: number }) => item?.id)).then(res => {
+            getList([data[selectAdz - 1].adAccountId])
+        })
+    }
+
+    /** 设置选中广告主 */
+    const handleSelectAdz = (value: number, item: any) => {
+        if (value === selectAdz) {
+            return
+        }
+        setSelectAdz(value)
+    }
+
+    const handleSelectCp = (value: number) => {
+        if (value === selectCp) {
+            return
+        }
+        setSelectCp(value)
+    }
+
+    /** 表格选折 */
+    const onChangeTable = (selectedRowKeys: React.Key[], selectedRows: any) => {
+        let newData = JSON.parse(JSON.stringify(data))
+        newData[selectAdz - 1][getKey(selectCp)] = selectedRows
+        setData([...newData])
+    }
+
+    return <Modal
+        title={<Space>
+            <span>人群包</span>
+            <Button size="small" onClick={() => { synGoodsList() }} type="link" loading={sysCrowdPack.loading}>同步人群包</Button>
+        </Space>}
+        visible={visible}
+        onCancel={() => { onClose && onClose() }}
+        onOk={handleOk}
+        width={1100}
+        className={style.SelectPackage}
+        bodyStyle={{ padding: '0 10px 0 10px' }}
+    >
+        <div className={style.content}>
+            <div className={style.left} style={{ width: 140 }}>
+                <h4 className={style.title}>人或目标场景</h4>
+                {crowdpackData.map((item: { id: number, name: string }, index: number) => (
+                    <div key={index} onClick={() => { handleSelectCp(index + 1) }} className={`${style.accItem} ${selectCp === index + 1 && style.select} `}>
+                        {item?.name}
+                        {/* {orientPackage[selectAdz - 1]?.goods?.key === item?.catalogId && orientPackage[selectAdz - 1].goods?.data?.length > 0 && <CheckOutlined style={{ color: '#1890ff' }} />} */}
+                    </div>))
+                }
+            </div>
+            <div className={style.left}>
+                <h4 className={style.title}>媒体账户</h4>
+                {data?.map((item: { adAccountId: number, id: number }, index: number) => (
+                    <div key={index} onClick={() => { handleSelectAdz(index + 1, item) }} className={`${style.accItem} ${selectAdz === index + 1 && style.select} `}>
+                        {item?.adAccountId}
+                        {data[index][getKey(selectCp)]?.length > 0 && <CheckOutlined style={{ color: '#1890ff' }} />}
+                    </div>))}
+            </div>
+            <div className={style.right}>
+                <Space style={{ marginBottom: 10 }}>
+                    <Input placeholder="请输入用户群名称" allowClear value={name} onChange={(e) => setName(e.target.value)} />
+                    <Button icon={<SyncOutlined />} type='link' loading={getCrowdPack?.loading} onClick={() => { getList([data[selectAdz - 1].adAccountId]) }}></Button>
+                </Space>
+                <Tables
+                    columns={columns()}
+                    dataSource={tableData?.filter((item: { name: string }) => name ? item.name.indexOf(name) !== -1 : true)}
+                    size="small"
+                    loading={getCrowdPack?.loading}
+                    scroll={{ y: 300 }}
+                    bordered
+                    defaultPageSize={100}
+                    rowSelection={{
+                        type: 'checkbox',
+                        selectedRowKeys: data[selectAdz - 1][getKey(selectCp)]?.map((item: any) => item?.id?.toString()),
+                        onChange: onChangeTable,
+                        getCheckboxProps: (record: any) => ({
+                            disabled: data[selectAdz - 1][getKey(selectCp, true)]?.map((item: any) => item?.id)?.includes(record.id),
+                            id: record.id,
+                        })
+                    }}
+                />
+            </div>
+        </div>
+    </Modal>
+}
+
+
+export default React.memo(CrowdPackModal)

+ 52 - 0
src/pages/launchSystemNew/components/crowdPackModal/tableConfig.tsx

@@ -0,0 +1,52 @@
+import { CrowdSourceEnum } from "@/services/launchAdq/enum"
+import React from "react"
+let columns = () => [
+    {
+        title: '用户群名称',
+        dataIndex: 'name',
+        key: 'name',
+        width: 260,
+        ellipsis: true,
+        render: (a: any, b: any) => {
+            return <span style={{ fontSize: "12px" }}>{a}</span>
+        }
+    },
+    {
+        title: 'ID',
+        dataIndex: 'audienceId',
+        key: 'audienceId',
+        align: 'center',
+        render: (a: any, b: any) => {
+            return <span style={{ fontSize: "12px" }}>{a}</span>
+        }
+    },
+    {
+        title: '来源',
+        dataIndex: 'source',
+        key: 'source',
+        align: 'center',
+        render: (a: any, b: any) => {
+            return <span style={{ fontSize: "12px" }}>{CrowdSourceEnum[a]}</span>
+        }
+    },
+    {
+        title: '覆盖数量',
+        dataIndex: 'userCount',
+        key: 'userCount',
+        align: 'center',
+        render: (a: any, b: any) => {
+            return <span style={{ fontSize: "12px" }}>{a}</span>
+        }
+    },
+    {
+        title: '状态',
+        dataIndex: 'status',
+        key: 'status',
+        align: 'center',
+        render: (a: any, b: any) => {
+            return <span style={{ fontSize: "12px" }}>{a}</span>
+        }
+    },
+]
+
+export default columns

+ 3 - 3
src/pages/launchSystemNew/components/dataSourceModal/index.tsx

@@ -79,7 +79,7 @@ const DataSourceModal: React.FC<Props> = (props) => {
     return <Modal
     return <Modal
         title={<Space>
         title={<Space>
             <span>数据源</span>
             <span>数据源</span>
-            <Button size="small" onClick={() => { synDataSourceList() }} loading={sysDataSource?.loading}>同步数据源</Button>
+            <Button size="small" onClick={() => { synDataSourceList() }} type='link' loading={sysDataSource?.loading}>同步数据源</Button>
         </Space>}
         </Space>}
         visible={visible}
         visible={visible}
         onCancel={() => { onClose && onClose() }}
         onCancel={() => { onClose && onClose() }}
@@ -90,7 +90,7 @@ const DataSourceModal: React.FC<Props> = (props) => {
     >
     >
         <div className={style.content}>
         <div className={style.content}>
             <div className={style.left}>
             <div className={style.left}>
-                <h4 className={style.title}>广告主账户</h4>
+                <h4 className={style.title}>媒体账户</h4>
                 {data?.map((item: { adAccountId: number, id: number }, index: number) => (
                 {data?.map((item: { adAccountId: number, id: number }, index: number) => (
                     <div key={index} onClick={() => { handleSelectAdz(index + 1, item) }} className={`${style.accItem} ${selectAdz === index + 1 && style.select} `}>
                     <div key={index} onClick={() => { handleSelectAdz(index + 1, item) }} className={`${style.accItem} ${selectAdz === index + 1 && style.select} `}>
                         {item?.adAccountId}
                         {item?.adAccountId}
@@ -98,7 +98,7 @@ const DataSourceModal: React.FC<Props> = (props) => {
                     </div>))}
                     </div>))}
             </div>
             </div>
             <div className={style.right}>
             <div className={style.right}>
-                <Space style={{ marginBottom: 10 }}>
+                <Space style={{ marginBottom: 10 }} align="end">
                     <Button icon={<SyncOutlined />} type='link' loading={getDataSource?.loading} onClick={() => { getList([data[selectAdz - 1].adAccountId]) }}></Button>
                     <Button icon={<SyncOutlined />} type='link' loading={getDataSource?.loading} onClick={() => { getList([data[selectAdz - 1].adAccountId]) }}></Button>
                 </Space>
                 </Space>
                 <Tables
                 <Tables

+ 2 - 2
src/pages/launchSystemNew/components/goodsModal/index.less

@@ -5,7 +5,7 @@
         justify-content: flex-start;
         justify-content: flex-start;
         min-height: 200px;
         min-height: 200px;
         .left{
         .left{
-            width: 200px;
+            width: 150px;
             padding-top: 10px;
             padding-top: 10px;
             border-right: 1px solid #f0f0f0;
             border-right: 1px solid #f0f0f0;
             box-sizing: border-box;
             box-sizing: border-box;
@@ -43,7 +43,7 @@
         .right{
         .right{
             padding: 10px;
             padding: 10px;
             box-sizing: border-box;
             box-sizing: border-box;
-            width: calc(100% - 200px);
+            width: calc(100% - 150px);
         }
         }
     }
     }
 
 

+ 4 - 12
src/pages/launchSystemNew/components/goodsModal/index.tsx

@@ -78,7 +78,7 @@ const GoodsModal: React.FC<Props> = (props) => {
     return <Modal
     return <Modal
         title={<Space>
         title={<Space>
             <span>商品库</span>
             <span>商品库</span>
-            <Button size="small" onClick={() => { synGoodsList() }} loading={synGoods?.loading}>同步商品库</Button>
+            <Button size="small" onClick={() => { synGoodsList() }} type="link" loading={synGoods?.loading}>同步商品库</Button>
         </Space>}
         </Space>}
         visible={visible}
         visible={visible}
         onCancel={() => { onClose && onClose() }}
         onCancel={() => { onClose && onClose() }}
@@ -89,24 +89,15 @@ const GoodsModal: React.FC<Props> = (props) => {
     >
     >
         <div className={style.content}>
         <div className={style.content}>
             <div className={style.left}>
             <div className={style.left}>
-                <h4 className={style.title}>广告主账户</h4>
+                <h4 className={style.title}>媒体账户</h4>
                 {data?.map((item: { adAccountId: number, id: number }, index: number) => (
                 {data?.map((item: { adAccountId: number, id: number }, index: number) => (
                     <div key={index} onClick={() => { handleSelectAdz(index + 1, item) }} className={`${style.accItem} ${selectAdz === index + 1 && style.select} `}>
                     <div key={index} onClick={() => { handleSelectAdz(index + 1, item) }} className={`${style.accItem} ${selectAdz === index + 1 && style.select} `}>
                         {item?.adAccountId}
                         {item?.adAccountId}
                         {data[index].productList?.length > 0 && <CheckOutlined style={{ color: '#1890ff' }} />}
                         {data[index].productList?.length > 0 && <CheckOutlined style={{ color: '#1890ff' }} />}
                     </div>))}
                     </div>))}
             </div>
             </div>
-            {/* <div className={style.left}>
-                <h4 className={style.title}>商品库</h4>
-                {goodsData?.map((item: { name: string, goodsList: any[], catalogId: number }, index: number) => (
-                    <div key={index} onClick={() => { handleGoods(index + 1, { ...queryFormDetail, godsId: goodsData[index].catalogId }) }} className={`${style.accItem} ${selectGoods === index + 1 && style.select} `}>
-                        {item?.name}
-                        {orientPackage[selectAdz - 1]?.goods?.key === item?.catalogId && orientPackage[selectAdz - 1].goods?.data?.length > 0 && <CheckOutlined style={{ color: '#1890ff' }} />}
-                    </div>))
-                }
-            </div> */}
             <div className={style.right}>
             <div className={style.right}>
-                <Space style={{ marginBottom: 10 }}>
+                <Space style={{ marginBottom: 10 }} align="end">
                     <Button icon={<SyncOutlined />} type='link' loading={getGoods?.loading} onClick={() => { getList([data[selectAdz - 1].adAccountId]) }}></Button>
                     <Button icon={<SyncOutlined />} type='link' loading={getGoods?.loading} onClick={() => { getList([data[selectAdz - 1].adAccountId]) }}></Button>
                 </Space>
                 </Space>
                 <Tables
                 <Tables
@@ -116,6 +107,7 @@ const GoodsModal: React.FC<Props> = (props) => {
                     loading={getGoods?.loading}
                     loading={getGoods?.loading}
                     scroll={{ y: 300 }}
                     scroll={{ y: 300 }}
                     bordered
                     bordered
+                    defaultPageSize={100}
                     rowSelection={{
                     rowSelection={{
                         type: 'radio',
                         type: 'radio',
                         selectedRowKeys: data[selectAdz - 1]?.productList?.map((item: any) => item?.id?.toString()),
                         selectedRowKeys: data[selectAdz - 1]?.productList?.map((item: any) => item?.id?.toString()),

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

@@ -0,0 +1,8 @@
+
+
+.popover {
+    width: 350px;
+    max-height: 150px;
+    overflow: hidden;
+    overflow-y: auto;
+}

+ 73 - 0
src/pages/launchSystemNew/components/targetingPopover/index.tsx

@@ -0,0 +1,73 @@
+import { useAjax } from "@/Hook/useAjax"
+import { getTagsList } from "@/services/launchAdq/global"
+import { getsysTargetingInfo } from "@/services/launchAdq/targeting"
+import { Popover, Spin } from "antd"
+import React, { useState } from "react"
+import TargetingTooltip from "../targetingTooltip"
+import style from './index.less'
+
+
+/**
+ * 表格查看信息
+ * @returns 
+ */
+interface Props {
+    id: number
+}
+const TargetingPopover: React.FC<Props> = (props) => {
+
+    /***************************/
+    const { id } = props
+    const [visible, setVisible] = useState<boolean>(false)
+    const [geoLocationList, setGeoLocationList] = useState<any>({}) // 所有地域列表
+    const [modelList, setModelList] = useState<any>({})  // 所有品牌手机
+
+    const tagsList_REGION = useAjax((params) => getTagsList(params))
+    const tagsList_MODEL = useAjax((params) => getTagsList(params))
+    const getsysTargeting = useAjax((params) => getsysTargetingInfo(params))
+    /***************************/
+
+    const handleVisibleChange = (newVisible: boolean) => {
+        setVisible(newVisible)
+        if (id && newVisible) {
+            getsysTargeting.run(id)
+            tagsList_REGION.run({ type: 'REGION' }).then(res => {
+                if (res) {
+                    setGeoLocationList(() => (res as any[])?.reduce((prev: any, cur: { id: number }) => {
+                        prev[cur.id] = cur
+                        return prev
+                    }, {}))
+                }
+            })
+            tagsList_MODEL.run({ type: 'DEVICE_BRAND_MODEL' }).then(res => {
+                if (res) {
+                    setModelList(() => (res as any[])?.reduce((prev: any, cur: { id: number }) => {
+                        prev[cur.id] = cur
+                        return prev
+                    }, {}))
+                }
+            })
+        }
+    }
+
+    return <Popover
+        content={<Spin spinning={getsysTargeting.loading || tagsList_MODEL.loading || tagsList_REGION.loading}>
+            <div className={style.popover}>
+                {getsysTargeting?.data && <>
+                    <div>定向名称: <span>{getsysTargeting?.data?.targetingName}</span></div>
+                    <div>定向描述: <span>{getsysTargeting?.data?.description}</span></div>
+                    <TargetingTooltip data={getsysTargeting?.data} geoLocationList={geoLocationList} modelList={modelList} />
+                </>}
+            </div>
+        </Spin>}
+        title="定向"
+        trigger="click"
+        placement="left"
+        visible={visible}
+        onVisibleChange={handleVisibleChange}
+    >
+        <a style={{ color: '#1890ff', fontSize: 12 }}>查看定向</a>
+    </Popover>
+}
+
+export default React.memo(TargetingPopover)

+ 1 - 1
src/pages/launchSystemNew/components/targetingTooltip/index.tsx

@@ -8,7 +8,7 @@ const targetingData = [
     { key: 'gender', name: '性别' },
     { key: 'gender', name: '性别' },
     { key: 'education', name: '学历' },
     { key: 'education', name: '学历' },
     { key: 'maritalStatus', name: '婚恋' },
     { key: 'maritalStatus', name: '婚恋' },
-    { key: 'customAudience', name: '定向人群' },
+    // { key: 'customAudience', name: '定向人群' },
     { key: 'deviceBrandModel', name: '品牌型号' },
     { key: 'deviceBrandModel', name: '品牌型号' },
     { key: 'wechatAdBehavior', name: '微信再营销' },
     { key: 'wechatAdBehavior', name: '微信再营销' },
     { key: 'networkType', name: '联网方式' },
     { key: 'networkType', name: '联网方式' },

+ 28 - 1
src/pages/launchSystemNew/launchManage/createAd/index.less

@@ -94,7 +94,6 @@
             width: 100%;
             width: 100%;
             min-height: 200px;
             min-height: 200px;
             font-size: 12px;
             font-size: 12px;
-
             // span {
             // span {
             //   color: #3085ff;
             //   color: #3085ff;
             // }
             // }
@@ -169,3 +168,31 @@
     justify-content: flex-end;
     justify-content: flex-end;
   }
   }
 }
 }
+.popoverContent {
+  border: 1px solid #dcdee2;
+  padding: 5px;
+  border-radius: 4px;
+  transition: all 0.5s;
+  margin-top: 1px;
+  margin-bottom: 5px;
+  &:hover {
+    border-color: rgb(24, 144, 255);
+    box-shadow: 0 0 4px 1px rgba(24, 144, 255, 0.4);
+  }
+}
+.popover {
+  max-width: 450px;
+  max-height: 150px;
+  overflow: hidden;
+  overflow-y: scroll;
+}
+
+.twoText {
+  text-overflow: -o-ellipsis-lastline;
+  overflow: hidden;
+  text-overflow: ellipsis;
+  display: -webkit-box;
+  -webkit-line-clamp: 2;
+  line-clamp: 2;
+  -webkit-box-orient: vertical;
+}

+ 81 - 21
src/pages/launchSystemNew/launchManage/createAd/index.tsx

@@ -7,11 +7,12 @@ import { getTagsList } from "@/services/launchAdq/global"
 import { getSysAdgroupsInfo } from "@/services/launchAdq/localAd"
 import { getSysAdgroupsInfo } from "@/services/launchAdq/localAd"
 import { getsysTargetingInfo } from "@/services/launchAdq/targeting"
 import { getsysTargetingInfo } from "@/services/launchAdq/targeting"
 import { CloseOutlined, SearchOutlined } from "@ant-design/icons"
 import { CloseOutlined, SearchOutlined } from "@ant-design/icons"
-import { Button, Card, Col, Empty, Row, Select, Space, Spin, Tooltip, Image, message } from "antd"
+import { Button, Card, Col, Empty, Row, Select, Space, Spin, Tooltip, Image, message, Popover } from "antd"
 import React, { useEffect, useState } from "react"
 import React, { useEffect, useState } from "react"
 import { useModel } from "umi"
 import { useModel } from "umi"
 import AdModal from "../../components/adModal"
 import AdModal from "../../components/adModal"
 import CreativeModal from "../../components/creativeModal"
 import CreativeModal from "../../components/creativeModal"
+import CrowdPackModal from "../../components/crowdPackModal"
 import DataSourceModal from "../../components/dataSourceModal"
 import DataSourceModal from "../../components/dataSourceModal"
 import GoodsModal from "../../components/goodsModal"
 import GoodsModal from "../../components/goodsModal"
 import IdModal from "../../components/idModal"
 import IdModal from "../../components/idModal"
@@ -35,14 +36,14 @@ const CreateAd: React.FC = () => {
         campaignType: 'CAMPAIGN_TYPE_NORMAL', // 计划类型 CAMPAIGN_TYPE_NORMAL CAMPAIGN_TYPE_SEARCH 
         campaignType: 'CAMPAIGN_TYPE_NORMAL', // 计划类型 CAMPAIGN_TYPE_NORMAL CAMPAIGN_TYPE_SEARCH 
         promotedObjectType: 'PROMOTED_OBJECT_TYPE_WECHAT_OFFICIAL_ACCOUNT', // 推广目标类型
         promotedObjectType: 'PROMOTED_OBJECT_TYPE_WECHAT_OFFICIAL_ACCOUNT', // 推广目标类型
         speedMode: 'SPEED_MODE_STANDARD', // 投放速度模式
         speedMode: 'SPEED_MODE_STANDARD', // 投放速度模式
-        sysAdgroupsId: undefined,  // 广告组内容
+        sysAdgroupId: undefined,  // 广告组内容
         sysTargetingId: undefined,  // 定向包 id
         sysTargetingId: undefined,  // 定向包 id
         adName: undefined,  // 广告名称
         adName: undefined,  // 广告名称
         configuredStatus: 'AD_STATUS_SUSPEND',  // 广告状态
         configuredStatus: 'AD_STATUS_SUSPEND',  // 广告状态
         sysAdcreativeId: undefined, // 创意ID
         sysAdcreativeId: undefined, // 创意ID
         sysPageId: undefined, // 落地页Id
         sysPageId: undefined, // 落地页Id
     })
     })
-    const [accountCreateLogs, setAccountCreateLogs] = useState<{ adAccountId: number, id: number, userActionSetsList?: number, productList?: any, conversionList?: any }[]>([])  // 账户
+    const [accountCreateLogs, setAccountCreateLogs] = useState<{ adAccountId: number, id: number, userActionSetsList?: number, productList?: any, conversionList?: any, customAudienceList?: any, excludedCustomAudienceList?: any }[]>([])  // 账户
 
 
     const [adVisible, setAdVisible] = useState<boolean>(false) // 选择广告弹窗控制
     const [adVisible, setAdVisible] = useState<boolean>(false) // 选择广告弹窗控制
     const [dxVisible, setDxVisible] = useState<boolean>(false) // 选择定向弹窗控制
     const [dxVisible, setDxVisible] = useState<boolean>(false) // 选择定向弹窗控制
@@ -53,6 +54,7 @@ const CreateAd: React.FC = () => {
     const [selectImgVisible, setSelectImgVisible] = useState<boolean>(false) // 选择转化ID弹窗控制
     const [selectImgVisible, setSelectImgVisible] = useState<boolean>(false) // 选择转化ID弹窗控制
     const [lookVisible, setLookVisible] = useState<boolean>(false) // 选择转化ID弹窗控制
     const [lookVisible, setLookVisible] = useState<boolean>(false) // 选择转化ID弹窗控制
     const [subVisible, setSubVisible] = useState<boolean>(false) // 选择设置名称弹窗控制
     const [subVisible, setSubVisible] = useState<boolean>(false) // 选择设置名称弹窗控制
+    const [cpVisible, setCpVisible] = useState<boolean>(false) // 选择设置名称弹窗控制
     const [wxButtonList, setWxButtonList] = useState<WxAutoButton[]>([])
     const [wxButtonList, setWxButtonList] = useState<WxAutoButton[]>([])
     const [tableData, setTableData] = useState<any[]>([])   // 预览表格
     const [tableData, setTableData] = useState<any[]>([])   // 预览表格
     const [tableSelect, setTableSelect] = useState<any[]>([])
     const [tableSelect, setTableSelect] = useState<any[]>([])
@@ -108,10 +110,10 @@ const CreateAd: React.FC = () => {
 
 
     /** 获取广告详情 */
     /** 获取广告详情 */
     useEffect(() => {
     useEffect(() => {
-        if (queryForm?.sysAdgroupsId) {
-            getSysAdgroups.run(queryForm?.sysAdgroupsId)
+        if (queryForm?.sysAdgroupId) {
+            getSysAdgroups.run(queryForm?.sysAdgroupId)
         }
         }
-    }, [queryForm?.sysAdgroupsId])
+    }, [queryForm?.sysAdgroupId])
 
 
     /** 获取创意详情 */
     /** 获取创意详情 */
     useEffect(() => {
     useEffect(() => {
@@ -147,12 +149,18 @@ const CreateAd: React.FC = () => {
 
 
     /** 删除数据源 */
     /** 删除数据源 */
     const sourceDel = (index: number, num: number) => {
     const sourceDel = (index: number, num: number) => {
-        console.log(index, num);
         let newArr = JSON.parse(JSON.stringify(accountCreateLogs))
         let newArr = JSON.parse(JSON.stringify(accountCreateLogs))
         newArr[index].userActionSetsList?.splice(num, 1)
         newArr[index].userActionSetsList?.splice(num, 1)
         setAccountCreateLogs(newArr)
         setAccountCreateLogs(newArr)
     }
     }
 
 
+    /** 删除人群包 */
+    const cpDel = (index: number, num: number, key: string) => {
+        let newArr = JSON.parse(JSON.stringify(accountCreateLogs))
+        newArr[index][key]?.splice(num, 1)
+        setAccountCreateLogs(newArr)
+    }
+
     /** 设置落地页 */
     /** 设置落地页 */
     const setPage = (e: any) => {
     const setPage = (e: any) => {
         setQueryForm({ ...queryForm, sysPageId: e[0]?.id || undefined })
         setQueryForm({ ...queryForm, sysPageId: e[0]?.id || undefined })
@@ -169,7 +177,7 @@ const CreateAd: React.FC = () => {
             message.error('请选择推广目标')
             message.error('请选择推广目标')
             return
             return
         }
         }
-        if (!queryForm.sysAdgroupsId) {
+        if (!queryForm.sysAdgroupId) {
             message.error('请先设置广告基本信息')
             message.error('请先设置广告基本信息')
             return
             return
         }
         }
@@ -198,20 +206,27 @@ const CreateAd: React.FC = () => {
         let accountLogs = tableSelect.map((item: any) => {
         let accountLogs = tableSelect.map((item: any) => {
             // userActionSetsList 数据源  productList 商品
             // userActionSetsList 数据源  productList 商品
             let data: any = { adAccountId: item.id }
             let data: any = { adAccountId: item.id }
-            if (item?.userActionSetsList?.length > 0) {
+            if (item?.userActionSetsList?.length > 0) { // 数据源
                 data.userActionSets = item?.userActionSetsList?.map((item: any) => ({ id: item?.id, type: item?.type }))
                 data.userActionSets = item?.userActionSetsList?.map((item: any) => ({ id: item?.id, type: item?.type }))
             }
             }
-            if (item?.productList?.length) {
+            if (item?.productList?.length > 0) { // 商品
                 data.productId = item?.productList[0].productOuterId
                 data.productId = item?.productList[0].productOuterId
                 data.productCatalogId = item?.productList[0].productCatalogId
                 data.productCatalogId = item?.productList[0].productCatalogId
             }
             }
+            if (item?.customAudienceList?.length > 0) {
+                data.customAudience = item?.customAudienceList?.map((item: any) => item.id)
+            }
+            if (item?.excludedCustomAudienceList?.length > 0) {
+                data.excludedCustomAudience = item?.excludedCustomAudienceList?.map((item: any) => item.id)
+            }
             return data
             return data
         })
         })
         params.accountCreateLogs = accountLogs
         params.accountCreateLogs = accountLogs
         createAdBatch.run(params).then(res => {
         createAdBatch.run(params).then(res => {
             if (res) {
             if (res) {
+                sessionStorage.setItem('CAMP', data?.campaignName)
                 message.success('创建成功')
                 message.success('创建成功')
-                window.location.href = '/#/launchSystemNew/launchManage/taskList'
+                // window.location.href = '/#/launchSystemNew/launchManage/taskList'
             }
             }
         })
         })
     }
     }
@@ -241,7 +256,7 @@ const CreateAd: React.FC = () => {
             campaignType: 'CAMPAIGN_TYPE_NORMAL', // 计划类型 CAMPAIGN_TYPE_NORMAL CAMPAIGN_TYPE_SEARCH 
             campaignType: 'CAMPAIGN_TYPE_NORMAL', // 计划类型 CAMPAIGN_TYPE_NORMAL CAMPAIGN_TYPE_SEARCH 
             promotedObjectType: 'PROMOTED_OBJECT_TYPE_WECHAT_OFFICIAL_ACCOUNT', // 推广目标类型
             promotedObjectType: 'PROMOTED_OBJECT_TYPE_WECHAT_OFFICIAL_ACCOUNT', // 推广目标类型
             speedMode: 'SPEED_MODE_STANDARD', // 投放速度模式
             speedMode: 'SPEED_MODE_STANDARD', // 投放速度模式
-            sysAdgroupsId: undefined,  // 广告组内容
+            sysAdgroupId: undefined,  // 广告组内容
             sysTargetingId: undefined,  // 定向包 id
             sysTargetingId: undefined,  // 定向包 id
             adName: undefined,  // 广告名称
             adName: undefined,  // 广告名称
             configuredStatus: 'AD_STATUS_SUSPEND',  // 广告状态
             configuredStatus: 'AD_STATUS_SUSPEND',  // 广告状态
@@ -323,15 +338,58 @@ const CreateAd: React.FC = () => {
                             {/* =============定向包=========== */}
                             {/* =============定向包=========== */}
                             <Col className={style.conRightBorder}>
                             <Col className={style.conRightBorder}>
                                 <div className={style.top}>
                                 <div className={style.top}>
-                                    定向{/* <span>已选:{1}</span> */}
+                                    定向
+                                    {accountCreateLogs?.length > 0 && queryForm?.sysTargetingId ? <Button type="link" style={{ fontSize: 12, padding: 0 }} onClick={() => setCpVisible(true)}>选择定向包</Button> : <Tooltip title={accountCreateLogs?.length > 0 ? `请先添加定向` : `请先选择媒体账户`}>
+                                        <Button type="link" style={{ fontSize: 12, padding: 0 }}>选择定向包</Button>
+                                    </Tooltip>}
                                 </div>
                                 </div>
                                 <div className={style.center}>
                                 <div className={style.center}>
                                     <Spin spinning={getsysTargeting.loading}>
                                     <Spin spinning={getsysTargeting.loading}>
                                         <div className={style.centerContent}>
                                         <div className={style.centerContent}>
-                                            {getsysTargeting?.data ? <>
-                                                <div>定向名称: <span>{getsysTargeting?.data?.targetingName}</span></div>
-                                                <div>定向描述: <span>{getsysTargeting?.data?.description}</span></div>
-                                                <TargetingTooltip data={getsysTargeting?.data} geoLocationList={geoLocationList} modelList={modelList} />
+                                            {queryForm?.sysTargetingId ? <>
+                                                {getsysTargeting?.data && <Popover
+                                                    content={<div className={style.popover}>
+                                                        <TargetingTooltip data={getsysTargeting?.data} geoLocationList={geoLocationList} modelList={modelList} />
+                                                    </div>}
+                                                    trigger="hover"
+                                                    placement="right"
+                                                >
+                                                    <div className={style.popoverContent}>
+                                                        <div>定向名称: <span>{getsysTargeting?.data?.targetingName}</span></div>
+                                                        <div>定向描述: <span>{getsysTargeting?.data?.description || '<空>'}</span></div>
+                                                    </div>
+                                                </Popover>}
+
+                                                {accountCreateLogs?.map((item: any, index: number) => {
+                                                    if (item?.customAudienceList) {
+                                                        return <div className={style.acc} key={index}>
+                                                            <div className={style.accName} style={{ fontWeight: 800 }}>{item.adAccountId}</div>
+                                                            {item?.customAudienceList?.length > 0 && <>
+                                                                <div className={style.accName}>定向用户群</div>
+                                                                {
+                                                                    item?.customAudienceList?.map((pack: { name: string, id: number }, index1: number) => {
+                                                                        return <div className={style.accCon} key={pack.id}>{pack.name}<CloseOutlined className={style.close} onClick={() => {
+                                                                            cpDel(index, index1, 'customAudienceList')
+                                                                        }} /></div>
+                                                                    })
+                                                                }
+                                                            </>}
+                                                            {item?.excludedCustomAudienceList?.length > 0 && <>
+                                                                <div className={style.accName} style={{ marginTop: 5 }}>排除用户群</div>
+                                                                {
+                                                                    item?.excludedCustomAudienceList?.map((pack: { name: string, id: number }, index1: number) => {
+                                                                        return <div className={style.accCon} key={pack.id}>{pack.name}<CloseOutlined className={style.close} onClick={() => {
+                                                                            cpDel(index, index1, 'excludedCustomAudienceList')
+                                                                        }} /></div>
+                                                                    })
+                                                                }
+                                                            </>}
+                                                        </div>
+                                                    } else {
+                                                        return null
+                                                    }
+                                                })}
+
                                             </> : <Empty image={Empty.PRESENTED_IMAGE_SIMPLE} />}
                                             </> : <Empty image={Empty.PRESENTED_IMAGE_SIMPLE} />}
                                         </div>
                                         </div>
                                     </Spin>
                                     </Spin>
@@ -348,7 +406,7 @@ const CreateAd: React.FC = () => {
                                         {accountCreateLogs?.map((item: any, index: number) => {
                                         {accountCreateLogs?.map((item: any, index: number) => {
                                             if (item?.productList) {
                                             if (item?.productList) {
                                                 return <div className={style.acc} key={index}>
                                                 return <div className={style.acc} key={index}>
-                                                    <div className={style.accName}>{item.adAccountId}</div>
+                                                    <div className={style.accName} style={{ fontWeight: 800 }}>{item.adAccountId}</div>
                                                     {
                                                     {
                                                         item?.productList?.map((pack: { productName: string, author: string, id: number }, index: number) => {
                                                         item?.productList?.map((pack: { productName: string, author: string, id: number }, index: number) => {
                                                             return <div className={style.accCon} key={pack.id}>{pack.productName}<CloseOutlined className={style.close} onClick={() => {
                                                             return <div className={style.accCon} key={pack.id}>{pack.productName}<CloseOutlined className={style.close} onClick={() => {
@@ -380,7 +438,7 @@ const CreateAd: React.FC = () => {
                                         {accountCreateLogs?.map((item: any, index: number) => {
                                         {accountCreateLogs?.map((item: any, index: number) => {
                                             if (item?.userActionSetsList && item?.userActionSetsList?.length > 0) {
                                             if (item?.userActionSetsList && item?.userActionSetsList?.length > 0) {
                                                 return <div className={style.acc} key={index}>
                                                 return <div className={style.acc} key={index}>
-                                                    <div className={style.accName}>{item.adAccountId}</div>
+                                                    <div className={style.accName} style={{ fontWeight: 800 }}>{item.adAccountId}</div>
                                                     {
                                                     {
                                                         item?.userActionSetsList?.map((pack: { name: string, type: string, id: number }, index1: number) => {
                                                         item?.userActionSetsList?.map((pack: { name: string, type: string, id: number }, index1: number) => {
                                                             return <div className={style.accCon} key={pack.id}> <span className={style.title}>{pack.name}{' > '}{pack.type}</span> <CloseOutlined className={style.close} onClick={() => {
                                                             return <div className={style.accCon} key={pack.id}> <span className={style.title}>{pack.name}{' > '}{pack.type}</span> <CloseOutlined className={style.close} onClick={() => {
@@ -417,7 +475,7 @@ const CreateAd: React.FC = () => {
                                         </div>
                                         </div>
                                     </Spin>
                                     </Spin>
                                 </div>
                                 </div>
-                                <div className={style.bottom}>{queryForm?.sysAdgroupsId ? <>
+                                <div className={style.bottom}>{queryForm?.sysAdgroupId ? <>
                                     <Button type="link" onClick={() => { setCreativeVisible(true) }}>{queryForm?.sysAdcreativeId ? '修改' : '添加'}</Button>
                                     <Button type="link" onClick={() => { setCreativeVisible(true) }}>{queryForm?.sysAdcreativeId ? '修改' : '添加'}</Button>
                                 </> : <Tooltip title="请先设置广告">
                                 </> : <Tooltip title="请先设置广告">
                                     <Button type="link"><span>添加</span></Button>
                                     <Button type="link"><span>添加</span></Button>
@@ -518,7 +576,7 @@ const CreateAd: React.FC = () => {
 
 
 
 
         {/* 选择广告 */}
         {/* 选择广告 */}
-        {adVisible && <AdModal visible={adVisible} onClose={() => setAdVisible(false)} promotedObjectType={queryForm.promotedObjectType as string} onChange={(e) => { setQueryForm({ ...queryForm, sysAdgroupsId: e, sysAdcreativeId: undefined }); setAdVisible(false); clearData() }} sysAdgroupsId={queryForm?.sysAdgroupsId} />}
+        {adVisible && <AdModal visible={adVisible} onClose={() => setAdVisible(false)} promotedObjectType={queryForm.promotedObjectType as string} onChange={(e) => { setQueryForm({ ...queryForm, sysAdgroupId: e, sysAdcreativeId: undefined }); setAdVisible(false); clearData() }} sysAdgroupId={queryForm?.sysAdgroupId} />}
         {/* 选择定向 */}
         {/* 选择定向 */}
         {dxVisible && <TargetingModal visible={dxVisible} onClose={() => setDxVisible(false)} onChange={(e) => { setQueryForm({ ...queryForm, sysTargetingId: e }); setDxVisible(false); clearData() }} sysTargetingId={queryForm?.sysTargetingId} />}
         {dxVisible && <TargetingModal visible={dxVisible} onClose={() => setDxVisible(false)} onChange={(e) => { setQueryForm({ ...queryForm, sysTargetingId: e }); setDxVisible(false); clearData() }} sysTargetingId={queryForm?.sysTargetingId} />}
         {/* 选择创意 */}
         {/* 选择创意 */}
@@ -529,6 +587,8 @@ const CreateAd: React.FC = () => {
         {sourceVisible && <DataSourceModal visible={sourceVisible} data={accountCreateLogs} onClose={() => setSourceVisible(false)} onChange={(e) => { setAccountCreateLogs(e); setSourceVisible(false); clearData() }} />}
         {sourceVisible && <DataSourceModal visible={sourceVisible} data={accountCreateLogs} onClose={() => setSourceVisible(false)} onChange={(e) => { setAccountCreateLogs(e); setSourceVisible(false); clearData() }} />}
         {/* 选择转化ID */}
         {/* 选择转化ID */}
         {idVisible && <IdModal visible={idVisible} data={accountCreateLogs} onClose={() => setIdVisible(false)} onChange={(e) => { setAccountCreateLogs(e); setSourceVisible(false); clearData() }} />}
         {idVisible && <IdModal visible={idVisible} data={accountCreateLogs} onClose={() => setIdVisible(false)} onChange={(e) => { setAccountCreateLogs(e); setSourceVisible(false); clearData() }} />}
+        {/* 选择定向包 */}
+        {cpVisible && <CrowdPackModal visible={cpVisible} data={accountCreateLogs} onClose={() => setCpVisible(false)} onChange={(e) => { setAccountCreateLogs(e); setCpVisible(false); clearData() }} />}
         {/* 选择素材 */}
         {/* 选择素材 */}
         {selectImgVisible && <SelectCloud visible={selectImgVisible} onClose={() => setSelectImgVisible(false)} onChange={setPage} isBack={false} />}
         {selectImgVisible && <SelectCloud visible={selectImgVisible} onClose={() => setSelectImgVisible(false)} onChange={setPage} isBack={false} />}
         {/* 查看落地页 */}
         {/* 查看落地页 */}

+ 44 - 9
src/pages/launchSystemNew/launchManage/createAd/tableConfig.tsx

@@ -28,7 +28,7 @@ let columns = () => {
             dataIndex: 'promotedObjectType',
             dataIndex: 'promotedObjectType',
             key: 'promotedObjectType',
             key: 'promotedObjectType',
             align: 'center',
             align: 'center',
-            width: 100,
+            width: 85,
             render: (a: any, b: any) => {
             render: (a: any, b: any) => {
                 return <span style={{ fontSize: "12px" }}>{PromotedObjectType[a]}</span>
                 return <span style={{ fontSize: "12px" }}>{PromotedObjectType[a]}</span>
             }
             }
@@ -48,7 +48,7 @@ let columns = () => {
             dataIndex: 'beginDate',
             dataIndex: 'beginDate',
             key: 'beginDate',
             key: 'beginDate',
             align: 'center',
             align: 'center',
-            width: 110,
+            width: 100,
             render: (a: any, b: any) => {
             render: (a: any, b: any) => {
                 return <span style={{ fontSize: "12px" }}>{b?.sysAdGroupData?.endDate ? b?.sysAdGroupData?.beginDate + '~' + b?.sysAdGroupData?.endDate : b?.sysAdGroupData?.beginDate + '~ 长期投放'}</span> 
                 return <span style={{ fontSize: "12px" }}>{b?.sysAdGroupData?.endDate ? b?.sysAdGroupData?.beginDate + '~' + b?.sysAdGroupData?.endDate : b?.sysAdGroupData?.beginDate + '~ 长期投放'}</span> 
             }
             }
@@ -152,7 +152,7 @@ let columns = () => {
             key: 'title',
             key: 'title',
             width: 150,
             width: 150,
             render: (a: any, b: any) => {
             render: (a: any, b: any) => {
-                return <span style={{ fontSize: "12px" }}>{b?.sysAdcreativeData?.adcreativeElements?.title}</span>
+                return <span style={{ fontSize: "12px" }}>{b?.sysAdcreativeData?.adcreativeElements?.title || '<空>'}</span>
             }
             }
         },
         },
         {
         {
@@ -185,20 +185,55 @@ let columns = () => {
                 </div>
                 </div>
             }
             }
         },
         },
+        {
+            title: '定向用户群',
+            dataIndex: 'customAudienceList',
+            key: 'customAudienceList',
+            align: 'center',
+            width: 180,
+            render: (a: any, b: any) => {
+                let names = a?.map((item: any) => item.name)
+                return <div className={style.twoText}>
+                    {
+                        names?.length > 0 ? <Tooltip title={names.toString()}>
+                            <span style={{ fontSize: "12px" }}>{names.toString()}</span>
+                        </Tooltip> : '<空>'
+                    }
+                </div>
+            }
+        },
+        {
+            title: '排除用户群',
+            dataIndex: 'excludedCustomAudienceList',
+            key: 'excludedCustomAudienceList',
+            align: 'center',
+            width: 180,
+            render: (a: any, b: any) => {
+                let names = a?.map((item: any) => item.name)
+                return <div className={style.twoText}>
+                    {
+                        names?.length > 0 ? <Tooltip title={names.toString()}>
+                            <span style={{ fontSize: "12px" }}>{names.toString()}</span>
+                        </Tooltip> : '<空>'
+                    }
+                </div>
+            }
+        },
         {
         {
             title: '商品',
             title: '商品',
             dataIndex: 'productList',
             dataIndex: 'productList',
             key: 'productList',
             key: 'productList',
-            width: 200,
+            width: 180,
+            align: 'center',
             render: (a: any, b: any) => {
             render: (a: any, b: any) => {
                 if (a && a?.length > 0) {
                 if (a && a?.length > 0) {
                     let data = a[0]
                     let data = a[0]
                     if (data) {
                     if (data) {
                         return <span style={{ fontSize: "12px" }}>{data?.productName + '-' + data?.firstCatalogName + '-' + data?.secondCatalogName}</span>
                         return <span style={{ fontSize: "12px" }}>{data?.productName + '-' + data?.firstCatalogName + '-' + data?.secondCatalogName}</span>
                     }
                     }
-                    return '--'
+                    return '<空>'
                 } else {
                 } else {
-                    return '--'
+                    return '<空>'
                 }
                 }
             }
             }
         },
         },
@@ -206,12 +241,12 @@ let columns = () => {
             title: '数据源',
             title: '数据源',
             dataIndex: 'userActionSetsList',
             dataIndex: 'userActionSetsList',
             key: 'userActionSetsList',
             key: 'userActionSetsList',
-            width: 350,
+            width: 320,
             render: (a: any, b: any) => {
             render: (a: any, b: any) => {
                 if (a && a?.length > 0) {
                 if (a && a?.length > 0) {
-                    return <span style={{ fontSize: "12px" }}>{a?.map((item: any) => item?.name + '>' + item?.type)?.toString() || '--'}</span>
+                    return <span style={{ fontSize: "12px" }}>{a?.map((item: any) => item?.name + '>' + item?.type)?.toString() || '<空>'}</span>
                 } else {
                 } else {
-                    return '--'
+                    return '<空>'
                 }
                 }
             }
             }
         }
         }

+ 71 - 26
src/pages/launchSystemNew/launchManage/taskList/index.tsx

@@ -2,9 +2,12 @@ import { useAjax } from "@/Hook/useAjax"
 import { getListByCorpAccount } from "@/services/enterpriseWeChat/userMange"
 import { getListByCorpAccount } from "@/services/enterpriseWeChat/userMange"
 import { PromotedObjectType } from "@/services/launchAdq/enum"
 import { PromotedObjectType } from "@/services/launchAdq/enum"
 import { getTaskListApi, TaskListProps } from "@/services/launchAdq/taskList"
 import { getTaskListApi, TaskListProps } from "@/services/launchAdq/taskList"
-import { Card, Input, Select, Space } from "antd"
+import { Button, Card, Input, Select, Space } from "antd"
 import React, { useEffect, useState } from "react"
 import React, { useEffect, useState } from "react"
-
+import LookLanding from "../../components/lookLanding"
+import TableData from "../../components/TableData"
+import Log from "./log"
+import tableConfig from './tableConfig'
 
 
 
 
 
 
@@ -12,11 +15,21 @@ const TaskList: React.FC = () => {
 
 
     /*************************/
     /*************************/
     const [queryForm, setQueryForm] = useState<TaskListProps>({ pageSize: 20, pageNum: 1 })
     const [queryForm, setQueryForm] = useState<TaskListProps>({ pageSize: 20, pageNum: 1 })
-
+    const [logVisible, setLogVisible] = useState<boolean>(false)
+    const [lookVisible, setLookVisible] = useState<boolean>(false)
+    const [logData, setLogData] = useState<{ taskId: number, campaignName: string } | number>({ taskId: 0, campaignName: '' })
 
 
     const getTaskList = useAjax((params) => getTaskListApi(params), { formatResult: true })
     const getTaskList = useAjax((params) => getTaskListApi(params), { formatResult: true })
     /*************************/
     /*************************/
 
 
+    useEffect(() => {
+        let campaignName = sessionStorage.getItem('CAMP')
+        if (campaignName) {
+            setQueryForm({ ...queryForm, campaignName })
+            sessionStorage.removeItem('CAMP')
+        }
+    }, [])
+
     useEffect(() => {
     useEffect(() => {
         getList()
         getList()
     }, [queryForm])
     }, [queryForm])
@@ -25,29 +38,61 @@ const TaskList: React.FC = () => {
         getTaskList.run(queryForm)
         getTaskList.run(queryForm)
     }
     }
 
 
-    return <Card>
-        <Space style={{ marginBottom: 20 }} wrap={true}>
-            <Input placeholder="计划名称" value={queryForm?.campaignName} onChange={(e) => setQueryForm({ ...queryForm, campaignName: e.target.value, pageNum: 1 })} />
-            <Select
-                placeholder="计划类型"
-                maxTagCount={1}
-                allowClear
-                value={queryForm?.campaignType}
-                onChange={(e) => { setQueryForm({ ...queryForm, campaignType: e }) }}
-            >
-                <Select.Option value='CAMPAIGN_TYPE_NORMAL'>普通展示广告</Select.Option>
-                <Select.Option value='CAMPAIGN_TYPE_WECHAT_MOMENTS'>微信朋友圈广告</Select.Option>
-            </Select>
-            <Select style={{ width: 200 }} value={queryForm?.promotedObjectType} placeholder="推广目标" showSearch filterOption={(input: any, option: any) =>
-                (option!.children as unknown as string).toLowerCase().includes(input.toLowerCase())
-            } onChange={(e) => { setQueryForm({ ...queryForm, promotedObjectType: e }) }}>
-                {Object.keys(PromotedObjectType).map(key => {
-                    return <Select.Option value={key} key={key}>{PromotedObjectType[key]}</Select.Option>
-                })}
-            </Select>
-        </Space>
-        
-    </Card>
+    const callback = (data: any, type: 'log' | 'page') => {
+        switch (type) {
+            case 'log':
+                setLogData({ ...data })
+                setLogVisible(true)
+                break
+            case 'page':
+                setLogData(data)
+                setLookVisible(true)
+                break
+        }
+    }
+
+    return <>
+        <TableData
+            columns={() => tableConfig(callback)}
+            ajax={getTaskList}
+            dataSource={getTaskList?.data?.data?.records}
+            loading={getTaskList?.loading}
+            scroll={{ y: 600 }}
+            total={getTaskList?.data?.data?.total}
+            page={getTaskList?.data?.data?.current}
+            pageSize={getTaskList?.data?.data?.size}
+            leftChild={<Space>
+                <Input placeholder="计划名称" style={{ width: 150 }} allowClear value={queryForm?.campaignName} onChange={(e) => {setQueryForm({ ...queryForm, campaignName: e.target.value, pageNum: 1 }); sessionStorage.removeItem('CAMP')}} />
+                <Select
+                    placeholder="计划类型"
+                    maxTagCount={1}
+                    allowClear
+                    style={{ width: 150 }}
+                    value={queryForm?.campaignType}
+                    onChange={(e) => { setQueryForm({ ...queryForm, campaignType: e }) }}
+                >
+                    <Select.Option value='CAMPAIGN_TYPE_NORMAL'>普通展示广告</Select.Option>
+                    <Select.Option value='CAMPAIGN_TYPE_WECHAT_MOMENTS'>微信朋友圈广告</Select.Option>
+                </Select>
+                <Select style={{ width: 150 }} allowClear value={queryForm?.promotedObjectType} placeholder="推广目标" showSearch filterOption={(input: any, option: any) =>
+                    (option!.children as unknown as string).toLowerCase().includes(input.toLowerCase())
+                } onChange={(e) => { setQueryForm({ ...queryForm, promotedObjectType: e }) }}>
+                    {Object.keys(PromotedObjectType).map(key => {
+                        return <Select.Option value={key} key={key}>{PromotedObjectType[key]}</Select.Option>
+                    })}
+                </Select>
+            </Space>}
+            onChange={(props: any) => {
+                let { sortData, pagination } = props
+                let { current, pageSize } = pagination
+                setQueryForm({ ...queryForm, pageNum: current, pageSize })
+            }}
+        />
+        {/* 日志 */}
+        {logVisible && <Log {...logData as any} visible={logVisible} onClose={() => setLogVisible(false)} />}
+        {/* 查看落地页 */}
+        {lookVisible && <LookLanding visible={lookVisible} onClose={() => setLookVisible(false)} id={logData as any} />}
+    </>
 }
 }
 
 
 export default React.memo(TaskList)
 export default React.memo(TaskList)

+ 81 - 0
src/pages/launchSystemNew/launchManage/taskList/log.tsx

@@ -0,0 +1,81 @@
+import { useAjax } from "@/Hook/useAjax"
+import { getTaskLogListApi, TaskLogListProps } from "@/services/launchAdq/taskList"
+import { Button, Drawer, Select, Space } from "antd"
+import React, { useEffect, useState } from "react"
+import { useModel } from "umi"
+import TableData from "../../components/TableData"
+import tableConfig from './logTableConfig'
+
+interface Props {
+    taskId: number,  // 任务ID
+    campaignName: string, // 计划名称
+    visible?: boolean,
+    onClose?: () => void
+}
+/**
+ * 创建日志
+ * @returns 
+ */
+const Log: React.FC<Props> = (props) => {
+
+    /*****************************/
+    const { taskId, campaignName, visible, onClose } = props
+    const [queryForm, setQueryForm] = useState<TaskLogListProps>({ pageNum: 1, pageSize: 20, taskId })
+
+    const { getAdAccount } = useModel('useLaunchAdq.useAdAuthorize')
+    const getTaskLogList = useAjax((params) => getTaskLogListApi(params), { formatResult: true })
+    /*****************************/
+
+    useEffect(() => {
+        getAdAccount.run()
+    }, [])
+
+    useEffect(() => {
+        getList()
+    }, [queryForm])
+
+    const getList = () => {
+        getTaskLogList.run(queryForm)
+    }
+
+    return <Drawer bodyStyle={{ padding: 0 }} title={campaignName + ' 日志'} width={1000} placement="right" onClose={() => { onClose && onClose() }} visible={visible}>
+        <TableData
+            columns={() => tableConfig()}
+            ajax={getTaskLogList}
+            dataSource={getTaskLogList?.data?.data?.records}
+            loading={getTaskLogList?.loading}
+            scroll={{ y: 600 }}
+            total={getTaskLogList?.data?.data?.total}
+            page={getTaskLogList?.data?.data?.current}
+            pageSize={getTaskLogList?.data?.data?.size}
+            leftChild={<Space>
+                <Select
+                    placeholder="媒体账户"
+                    allowClear
+                    style={{ width: 150 }}
+                    showSearch
+                    value={queryForm?.accountId}
+                    filterOption={(input, option) => {
+                        return (option?.children as unknown as string)?.toString()?.toLowerCase()?.includes(input.toLowerCase())
+                    }}
+                    onChange={(e) => { setQueryForm({ ...queryForm, accountId: e }) }}
+                >
+                    {getAdAccount?.data?.data?.map((item: any) => <Select.Option value={item.accountId} key={item.id}>{item.accountId}</Select.Option>)}
+                </Select>
+                <Select style={{ width: 150 }} allowClear value={queryForm?.createStatus} placeholder="创建状态" showSearch onChange={(e) => { setQueryForm({ ...queryForm, createStatus: e }) }}>
+                    <Select.Option value={-1}>创建失败</Select.Option>
+                    <Select.Option value={0}>创建中</Select.Option>
+                    <Select.Option value={100}>创建成功</Select.Option>
+                </Select>
+            </Space>}
+            onChange={(props: any) => {
+                let { sortData, pagination } = props
+                let { current, pageSize } = pagination
+                setQueryForm({ ...queryForm, pageNum: current, pageSize })
+            }}
+        />
+    </Drawer>
+}
+
+
+export default React.memo(Log)

+ 69 - 0
src/pages/launchSystemNew/launchManage/taskList/logTableConfig.tsx

@@ -0,0 +1,69 @@
+import { Badge } from "antd"
+import React from "react"
+function tableConfig(): any {
+    return [
+        {
+            title: 'ID',
+            dataIndex: 'id',
+            key: 'id',
+            align: 'center',
+            width: 45,
+        },
+        {
+            title: '媒体账户',
+            dataIndex: 'accountId',
+            key: 'accountId',
+            align: 'center',
+            width: 80,
+            render: (a: any, b: any) => {
+                return <span style={{ fontSize: "12px" }}>{a || '--'}</span>
+            }
+        },
+        {
+            title: '商品ID',
+            dataIndex: 'productId',
+            key: 'productId',
+            width: 150,
+            ellipsis: true,
+            render: (a: any, b: any) => {
+                return <span style={{ fontSize: "12px" }}>{a || '--'}</span>
+            }
+        },
+        {
+            title: '创建状态',
+            dataIndex: 'createStatus',
+            key: 'createStatus',
+            align: 'center',
+            width: 90,
+            render: (a: any, b: any) => {
+                if (a) {
+                    return a === 0 ? <Badge status="warning" text={<span style={{ fontSize: "12px" }}>创建中</span>}/> : a === 100 ? <Badge status="success" text={<span style={{ fontSize: "12px" }}>创建成功</span>} /> : <Badge status="error" text={<span style={{ fontSize: "12px" }}>创建失败</span>} />
+                } else {
+                    return <span>--</span>
+                }
+            }
+        },
+        {
+            title: '创建时间',
+            dataIndex: 'createTime',
+            key: 'createTime',
+            align: 'center',
+            width: 130,
+            render: (a: any, b: any) => {
+                return <span style={{ fontSize: "12px" }}>{a || '--'}</span>
+            }
+        },
+        {
+            title: <span style={{ padding: '0 8px' }}>失败原因</span>,
+            dataIndex: 'failMsg',
+            key: 'failMsg',
+            align: 'left',
+            ellipsis: true,
+            render: (a: any, b: any) => {
+                return <span style={{ fontSize: "12px" }}>{a || '--'}</span>
+            }
+        },
+    ]
+}
+
+export default tableConfig

+ 115 - 0
src/pages/launchSystemNew/launchManage/taskList/tableConfig.tsx

@@ -0,0 +1,115 @@
+import React from "react"
+import { Space } from "antd"
+import { AdStatus, PromotedObjectType, SpeedMode } from "@/services/launchAdq/enum"
+import TargetingPopover from "../../components/targetingPopover"
+function tableConfig(callback: (data: any, type: 'log' | 'page') => void): any {
+    return [
+        {
+            title: 'ID',
+            dataIndex: 'id',
+            key: 'id',
+            align: 'center',
+            width: 50,
+        },
+        {
+            title: '计划名称',
+            dataIndex: 'campaignName',
+            key: 'campaignName',
+            align: 'left',
+            width: 180,
+            ellipsis: true,
+            render: (a: any, b: any) => {
+                return <span style={{ fontSize: "12px" }}>{a || '--'}</span>
+            }
+        },
+        {
+            title: '计划类型',
+            dataIndex: 'campaignType',
+            key: 'campaignType',
+            align: 'center',
+            width: 120,
+            render: (a: any, b: any) => {
+                if (a) {
+                    return <span style={{ fontSize: "12px" }}>{a === 'CAMPAIGN_TYPE_NORMAL' ? '普通展示广告' : '微信朋友圈广告'}</span>
+                } else {
+                    return <span>--</span>
+                }
+            }
+        },
+        {
+            title: '广告状态',
+            dataIndex: 'configuredStatus',
+            key: 'configuredStatus',
+            align: 'center',
+            width: 100,
+            render: (a: any, b: any) => {
+                if (a) {
+                    return <span style={{ fontSize: "12px" }}>{AdStatus[a]}</span>
+                } else {
+                    return <span>--</span>
+                }
+            }
+        },
+        {
+            title: '推广目标',
+            dataIndex: 'promotedObjectType',
+            key: 'promotedObjectType',
+            align: 'center',
+            width: 100,
+            render: (a: any, b: any) => {
+                if (a) {
+                    return <span style={{ fontSize: "12px" }}>{PromotedObjectType[a]}</span>
+                } else {
+                    return <span>--</span>
+                }
+            }
+        },
+        {
+            title: '投放速度模式',
+            dataIndex: 'speedMode',
+            key: 'speedMode',
+            align: 'center',
+            width: 100,
+            render: (a: any, b: any) => {
+                if (a) {
+                    return <span style={{ fontSize: "12px" }}>{SpeedMode[a]}</span>
+                } else {
+                    return <span>--</span>
+                }
+            }
+        },
+        {
+            title: '创建时间',
+            dataIndex: 'createTime',
+            key: 'createTime',
+            align: 'center',
+            width: 140,
+            render: (a: any, b: any) => {
+                return <span style={{ fontSize: "12px" }}>{a || '--'}</span>
+            }
+        },
+        {
+            title: <span style={{ marginLeft: 10 }}>操作</span>,
+            dataIndex: 'taskName',
+            key: 'taskName',
+            fixed: 'right',
+            render: (a: any, b: any) => {
+                return <Space style={{ marginLeft: 10 }}>
+                    <a style={{ color: '#1890ff', fontSize: 12 }} onClick={() => { callback({ taskId: b.id, campaignName: b.campaignName }, 'log') }}>日志</a>
+                    <a style={{ color: '#1890ff', fontSize: 12 }} onClick={() => { callback(b.sysPageId, 'page') }}>查看落地页</a>
+                    <TargetingPopover id={b.sysTargetingId}/>
+                    {/* <Popconfirm
+                    title={`你确定删除"${b?.taskName}"这个任务?`}
+                    onConfirm={() => { del(b?.id) }}
+                    okText="Yes"
+                    cancelText="No"
+                >
+                    <a style={{ color: 'red', fontSize: 12 }}>删除</a>
+                </Popconfirm> */}
+                </Space>
+            }
+        }
+    ]
+}
+
+export default tableConfig

+ 1 - 1
src/services/api.ts

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

+ 31 - 3
src/services/launchAdq/createAd.ts

@@ -5,14 +5,14 @@ import { api } from '../api';
 /**
 /**
  * 获取商品库列表
  * 获取商品库列表
  */
  */
- export interface CreateAdProps {
+export interface CreateAdProps {
     campaignName: string, // 计划名称
     campaignName: string, // 计划名称
     campaignType: string, // 计划类型 CAMPAIGN_TYPE_NORMAL CAMPAIGN_TYPE_SEARCH 
     campaignType: string, // 计划类型 CAMPAIGN_TYPE_NORMAL CAMPAIGN_TYPE_SEARCH 
     promotedObjectType: string, // 推广目标类型
     promotedObjectType: string, // 推广目标类型
     dailyBudget?: number,   // 推广计划日预算
     dailyBudget?: number,   // 推广计划日预算
     totalBudget?: number, // 推广计划总预算
     totalBudget?: number, // 推广计划总预算
     speedMode: string, // 投放速度模式
     speedMode: string, // 投放速度模式
-    sysAdgroupsId: number,  // 广告组内容
+    sysAdgroupId: number,  // 广告组内容
     sysTargetingId: number,  // 定向包 id
     sysTargetingId: number,  // 定向包 id
     adName: string,  // 广告名称
     adName: string,  // 广告名称
     configuredStatus: string,  // 广告状态
     configuredStatus: string,  // 广告状态
@@ -28,6 +28,8 @@ import { api } from '../api';
         productCatalogId?: number, // 商品库ID
         productCatalogId?: number, // 商品库ID
         productId?: number, // 商品Id
         productId?: number, // 商品Id
         enterpriseWx?: any[]  // 企业微信客服组
         enterpriseWx?: any[]  // 企业微信客服组
+        customAudience?: number[],  // 定向人群
+        excludedCustomAudience?: number[], // 排除人群
     }[]
     }[]
 }
 }
 export async function createAdBatchApi(data: CreateAdProps) {
 export async function createAdBatchApi(data: CreateAdProps) {
@@ -68,7 +70,7 @@ export async function synGoodsApi(data: number[]) {
  * @param data
  * @param data
  * @returns 
  * @returns 
  */
  */
- export async function getDataSourceApi(data: number[]) {
+export async function getDataSourceApi(data: number[]) {
     return request(api + `/adq/userActionSets/allByAccount`, {
     return request(api + `/adq/userActionSets/allByAccount`, {
         method: 'POST',
         method: 'POST',
         data
         data
@@ -110,4 +112,30 @@ export async function sysIdApi(data: number[]) {
         method: 'PUT',
         method: 'PUT',
         data
         data
     })
     })
+}
+
+
+/**
+ * 获取人群包
+ * @param data 
+ * @returns 
+ */
+export async function getCrowdPackApi(data: number[]) {
+    return request(api + `/adq/customAudiences/allByAccount`, {
+        method: 'POST',
+        data
+    })
+}
+
+
+/**
+ * 同步人群包
+ * @param data 
+ * @returns 
+ */
+ export async function sysCrowdPackApi(data: number[]) {
+    return request(api + `/adq/customAudiences/syncByAdAccountId`, {
+        method: 'PUT',
+        data
+    })
 }
 }

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

@@ -350,4 +350,11 @@ export enum LinkPageNameTypeEnum {
   GET_618_WELFARE = '领 618 福利',
   GET_618_WELFARE = '领 618 福利',
   CONTACT_CUSTOMER_SERVICE = '联系客服',
   CONTACT_CUSTOMER_SERVICE = '联系客服',
   CONTACT_BUSINESS = '联系商家',
   CONTACT_BUSINESS = '联系商家',
+}
+
+/**人群来源*/
+export enum CrowdSourceEnum {
+  ADVERTISER_OWN_DATA = '一方人群',
+  TENCENT_DATA = '二方人群',
+  UNKNOWN = '未知类型',
 }
 }

+ 1 - 1
src/services/launchAdq/taskList.ts

@@ -33,7 +33,7 @@ export interface TaskLogListProps {
     accountId?: number, // 账号id
     accountId?: number, // 账号id
 }
 }
 export async function getTaskLogListApi(data: TaskLogListProps) {
 export async function getTaskLogListApi(data: TaskLogListProps) {
-    return request(api + '/adq/adCreateTask/list', {
+    return request(api + '/adq/adCreateTask/taskLog', {
         method: 'POST',
         method: 'POST',
         data
         data
     });
     });