wjx 10 ماه پیش
والد
کامیت
8afbfaff79
33فایلهای تغییر یافته به همراه1002 افزوده شده و 128 حذف شده
  1. 6 0
      config/routerConfig.ts
  2. 2 2
      src/pages/launchSystemV3/components/BrandImage/index.tsx
  3. 30 5
      src/pages/launchSystemV3/components/DynamicTooltip/index.tsx
  4. 1 0
      src/pages/launchSystemV3/components/GoodsModal/index.less
  5. 5 3
      src/pages/launchSystemV3/components/PageModal/index.tsx
  6. 1 1
      src/pages/launchSystemV3/tencenTasset/brand/index.tsx
  7. 186 0
      src/pages/launchSystemV3/tencenTasset/profiles/index.tsx
  8. 81 0
      src/pages/launchSystemV3/tencenTasset/profiles/tableConfig.tsx
  9. 15 1
      src/pages/launchSystemV3/tencentAdPutIn/const.ts
  10. 3 4
      src/pages/launchSystemV3/tencentAdPutIn/create/Ad/adgroupsMarketingContent.tsx
  11. 25 4
      src/pages/launchSystemV3/tencentAdPutIn/create/Ad/adgroupsPrice.tsx
  12. 16 3
      src/pages/launchSystemV3/tencentAdPutIn/create/Ad/index.tsx
  13. 1 1
      src/pages/launchSystemV3/tencentAdPutIn/create/Ad/newCreateAd.tsx
  14. 89 10
      src/pages/launchSystemV3/tencentAdPutIn/create/Dynamic/creativeConversionAssistant.tsx
  15. 9 4
      src/pages/launchSystemV3/tencentAdPutIn/create/Dynamic/creativeTemplateContent.tsx
  16. 55 16
      src/pages/launchSystemV3/tencentAdPutIn/create/Dynamic/index.tsx
  17. 100 32
      src/pages/launchSystemV3/tencentAdPutIn/create/Dynamic/newDynamic.tsx
  18. 2 1
      src/pages/launchSystemV3/tencentAdPutIn/create/PageList/index.tsx
  19. 11 3
      src/pages/launchSystemV3/tencentAdPutIn/create/Target/addTarget.tsx
  20. 2 0
      src/pages/launchSystemV3/tencentAdPutIn/create/Target/index.tsx
  21. 2 1
      src/pages/launchSystemV3/tencentAdPutIn/create/Target/selectTarget.tsx
  22. 8 2
      src/pages/launchSystemV3/tencentAdPutIn/create/index.tsx
  23. 2 1
      src/pages/launchSystemV3/tencentAdPutIn/create/submitModal.tsx
  24. 5 5
      src/pages/launchSystemV3/tencentAdPutIn/index.less
  25. 63 0
      src/pages/launchSystemV3/tencentAdPutIn/taskList/dynamicLog.tsx
  26. 4 3
      src/pages/launchSystemV3/tencentAdPutIn/taskList/index.tsx
  27. 19 4
      src/pages/launchSystemV3/tencentAdPutIn/taskList/log.tsx
  28. 178 20
      src/pages/launchSystemV3/tencentAdPutIn/taskList/tableConfig.tsx
  29. 5 0
      src/pages/launchSystemV3/tencentAdPutIn/typings.d.ts
  30. 37 0
      src/services/adqV3/global.ts
  31. 12 0
      src/services/adqV3/index.ts
  32. 2 2
      src/services/api.ts
  33. 25 0
      src/utils/utils.ts

+ 6 - 0
config/routerConfig.ts

@@ -232,6 +232,12 @@ const launchSystemV3 = {
                     path: '/launchSystemV3/tencenTasset/brand',
                     access: 'brand',
                     component: './launchSystemV3/tencenTasset/brand',
+                },
+                {
+                    name: '头像昵称跳转页',
+                    path: '/launchSystemV3/tencenTasset/profiles',
+                    access: 'profiles',
+                    component: './launchSystemV3/tencenTasset/profiles',
                 }
             ],
         },

+ 2 - 2
src/pages/launchSystemV3/components/BrandImage/index.tsx

@@ -178,7 +178,7 @@ export const UploadImage: React.FC<ImageProps> = (props) => {
     }
 
     const selectImg = () => {
-        init({ mediaType: 'IMG', cloudSize: [[{ relation: '=', width: 512, height: 512 }]], maxSize: 50 * 1024 })
+        init({ mediaType: 'IMG', cloudSize: [[{ relation: '=', width: 512, height: 512 }]], maxSize: 400 * 1024 })
         setTimeout(() => { setSelectImgVisible(true) }, 50)
     }
 
@@ -186,7 +186,7 @@ export const UploadImage: React.FC<ImageProps> = (props) => {
         {value ? <img src={value} onClick={selectImg} width={100} height={100} /> : <Button onClick={selectImg}>选择图片</Button>}
         <div style={{ fontSize: 12, color: 'rgba(0,0,0,.5)' }}>
             <div>图片尺寸:512×512 像素</div>
-            <div>图片格式:大小要求在 50KB 以内,仅支持 jpg 和 png 格式</div>
+            <div>图片格式:大小要求在 400KB 以内,仅支持 jpg 和 png 格式</div>
         </div>
 
         {/* 选择素材 */}

+ 30 - 5
src/pages/launchSystemV3/components/DynamicTooltip/index.tsx

@@ -1,7 +1,9 @@
-import React from "react"
+import React, { useEffect, useState } from "react"
 import style from '../../tencentAdPutIn/create/index.less'
 import { AD_STATUS_ENUM, CONVERSION_DATA_ENUM, CONVERSION_TARGET_ENUM, DELIVERY_MODE_ENUM, PAGE_TYPE_ENUM, TEXT_LINK_TYPE_ENUM, pageSpecFieldConVertUn } from "../../tencentAdPutIn/const"
 import { Space } from "antd"
+import { getProfilesApi } from "@/services/adqV3/global"
+import { useAjax } from "@/Hook/useAjax"
 
 
 interface Props {
@@ -17,10 +19,22 @@ const DynamicTooltip: React.FC<Props> = ({ data: dynamicData }) => {
 
     /************************************/
     const { deliveryMode, creativeTemplateId, dynamicCreativeName, creativeComponents, configuredStatus } = dynamicData
-    const { textLink, actionButton, showData, brand } = creativeComponents || {}
-    let pageSpec = brand?.[0]?.value?.jumpInfo?.pageSpec
+    const { textLink, actionButton, showData, brand, mainJumpInfo } = creativeComponents || {}
+
+    const [profileData, setprofileData] = useState<any>()
+    const getProfiles = useAjax((params) => getProfilesApi(params))
     /************************************/
 
+    useEffect(() => {
+        if (['PAGE_TYPE_H5_PROFILE'].includes(brand?.[0]?.value?.jumpInfo?.pageType)) {
+            getProfiles.run({}).then(res => {
+                if (res) {
+                    setprofileData(res?.find((item: { id: any }) => item.id === brand?.[0]?.value?.profileId))
+                }
+            })
+        }
+    }, [brand])
+    
     return <div className={style.detail_body} style={{ height: 'auto' }}>
         {dynamicData && Object.keys(dynamicData).length > 0 && <>
             <p>创意名称:{dynamicCreativeName}</p>
@@ -29,12 +43,23 @@ const DynamicTooltip: React.FC<Props> = ({ data: dynamicData }) => {
             <p>创意形式ID:{creativeTemplateId}</p>
             {brand?.length > 0 && <>
                 <p style={{ fontWeight: 'bold', color: '#000' }}>品牌形象跳转:{PAGE_TYPE_ENUM[brand?.[0]?.value?.jumpInfo?.pageType]}</p>
-                {['PAGE_TYPE_H5_PROFILE', 'PAGE_TYPE_NOT_USED'].includes(brand?.[0]?.value?.jumpInfo?.pageType) && <Space align="center">
+                {['PAGE_TYPE_H5_PROFILE'].includes(brand?.[0]?.value?.jumpInfo?.pageType) ? <>
+                    {profileData ? <>
+                        <Space>
+                            <img src={profileData?.headImageUrl} alt="" width={20} style={{ display: 'block' }} />
+                            <span style={{ fontWeight: 'bold', color: '#000', fontSize: 12 }}>{profileData?.profileName}</span>
+                        </Space>
+                        <p>详细描述:{profileData?.description}</p>
+                    </> : <span style={{ color: 'red', fontWeight: 'bold', fontSize: 12 }}>{getProfiles.loading ? '' : '当前头像昵称跳转页被删除'} </span>}
+                </> : ['PAGE_TYPE_NOT_USED'].includes(brand?.[0]?.value?.jumpInfo?.pageType) && <Space align="center">
                     <img src={brand?.[0]?.value?.brandImageId} alt="" width={20} style={{ display: 'block' }} />
                     <span style={{ fontWeight: 'bold', color: '#000', fontSize: 12 }}>{brand?.[0]?.value?.brandName}</span>
                 </Space>}
-                {(pageSpec && Object.keys(pageSpec).length > 0) && <p style={{ fontWeight: 'bold', color: '#000' }}>跳转类型:{PAGE_TYPE_ENUM[pageSpecFieldConVertUn[Object.keys(pageSpec)?.[0]]]}</p>}
             </>}
+            <p style={{ fontWeight: 'bold', color: '#000' }}>跳转类型:{mainJumpInfo?.map((item: any) => {
+                let pageSpec = item.value.pageSpec
+                return PAGE_TYPE_ENUM[pageSpecFieldConVertUn[Object.keys(pageSpec)?.[0]]]
+            }).toString()}</p>
             {textLink?.length > 0 && <>
                 <p style={{ fontWeight: 'bold', color: '#000' }}>朋友圈文字链:开启</p>
                 <p>文字链文案:{TEXT_LINK_TYPE_ENUM[textLink?.[0]?.value?.linkNameType]}</p>

+ 1 - 0
src/pages/launchSystemV3/components/GoodsModal/index.less

@@ -98,6 +98,7 @@
             .marketingAssetName {
                 flex: 1;
                 overflow: hidden;
+                font-size: 12px;
             }
             .close {
                 width: 20px;

+ 5 - 3
src/pages/launchSystemV3/components/PageModal/index.tsx

@@ -17,12 +17,14 @@ interface Props {
     visible?: boolean,
     onClose?: () => void,
     onChange?: (data: PULLIN.AccountCreateLogsProps[]) => void,
+    adgroups: any
     data: PULLIN.AccountCreateLogsProps[]
 }
 const PageModal: React.FC<Props> = (props) => {
 
     /*************************/
-    const { visible, onClose, data: data1, onChange } = props
+    const { visible, onClose, data: data1, adgroups, onChange } = props
+    const { marketingGoal, marketingAssetOuterSpec: { marketingTargetType }, marketingCarrierType, siteSet } = adgroups
     const [selectAdz, setSelectAdz] = useState<number>(1)   // 选择广告主
     const [data, setData] = useState<PULLIN.AccountCreateLogsProps[]>(data1 || [])
     const [queryForm, setQueryForm] = useState<{ accountId?: number, pageName?: string, pageSize: number, pageNum: number }>({ pageNum: 1, pageSize: 20 })
@@ -41,11 +43,11 @@ const PageModal: React.FC<Props> = (props) => {
         if (queryForm?.accountId) {
             getList()
         }
-    }, [queryForm])
+    }, [queryForm, marketingGoal, marketingTargetType, marketingCarrierType, siteSet])
 
     // 获取落地页列表
     const getList = () => {
-        listAjax.run({ ...queryForm, pageStatus: 'NORMAL' })
+        listAjax.run({ ...queryForm, pageStatus: 'NORMAL', marketingGoal, marketingTargetType, marketingCarrierType, siteSet })
     }
 
     const handleOk = () => {

+ 1 - 1
src/pages/launchSystemV3/tencenTasset/brand/index.tsx

@@ -83,7 +83,7 @@ const Brand: React.FC = () => {
             rowKey={'id'}
         />
 
-        {addVisible && <Modal title="上传品牌形象" visible={addVisible} confirmLoading={addSysBrand.loading} onOk={handleOk} onCancel={() => setAddVisible(false)}>
+        {addVisible && <Modal className="modalResetCss" title="上传品牌形象" visible={addVisible} confirmLoading={addSysBrand.loading} onOk={handleOk} onCancel={() => setAddVisible(false)}>
             <Form
                 name="basic"
                 form={form}

+ 186 - 0
src/pages/launchSystemV3/tencenTasset/profiles/index.tsx

@@ -0,0 +1,186 @@
+import { useAjax } from "@/Hook/useAjax";
+import { addProfilesApi, delProfilesApi, delSysBrandApi, getProfilesApi } from "@/services/adqV3/global";
+import { PlusOutlined, SearchOutlined } from "@ant-design/icons";
+import { Button, Card, Form, Input, Modal, Select, Space, Table, message, Image, Divider } from "antd";
+import React, { useEffect, useState } from "react"
+import '../../tencentAdPutIn/index.less'
+import profilesColumns from "./tableConfig";
+import SelectCloud from "@/pages/launchSystemNew/components/selectCloud";
+import { useModel } from "umi";
+
+
+const Profiles: React.FC = () => {
+
+
+    /***************************************/
+    const [addVisible, setAddVisible] = useState<boolean>(false)
+    const [initialValues, setInitialValues] = useState<any>({})
+    const [form] = Form.useForm()
+    const [queryForm, setQueryForm] = useState<{ profileName?: string }>({})
+
+    const getProfiles = useAjax((params) => getProfilesApi(params))
+    const addProfiles = useAjax((params) => addProfilesApi(params))
+    const delProfiles = useAjax((params) => delProfilesApi(params))
+    /***************************************/
+
+    // 获取列表
+    useEffect(() => {
+        getProfiles.run(queryForm)
+    }, [queryForm])
+
+    // 新增修改
+    const handleOk = async () => {
+        form.submit()
+        let { imageData, ...data } = await form.validateFields()
+        addProfiles.run({ ...imageData, ...data }).then(res => {
+            if (res) {
+                message.success('新增成功')
+                setAddVisible(false)
+                getProfiles.refresh()
+            }
+        })
+        setInitialValues({})
+    }
+
+    /** 删除 */
+    const del = (id: number) => {
+        delProfiles.run({ id }).then(res => {
+            if (res) {
+                message.success('删除成功')
+                getProfiles.refresh()
+            }
+        })
+    }
+
+    return <Card
+        className="cardResetCss"
+        title={<div className="flexStart" style={{ gap: 8 }}>
+            <Input style={{ width: 200 }} placeholder="请输入头像昵称跳转页" value={queryForm?.profileName} allowClear onChange={(e) => setQueryForm({ ...queryForm, profileName: e.target.value })} />
+            <Button type="primary" icon={<SearchOutlined />} onClick={() => getProfiles.refresh()}>搜索</Button>
+            <Button type="primary" icon={<PlusOutlined />} onClick={() => { setAddVisible(true); setInitialValues({}), form.resetFields() }}>上传头像昵称跳转页</Button>
+        </div>}
+    >
+        <Table
+            columns={profilesColumns(del)}
+            dataSource={getProfiles?.data}
+            size="small"
+            loading={getProfiles?.loading}
+            scroll={{ y: 300 }}
+            bordered
+            rowKey={'id'}
+        />
+
+        {addVisible && <Modal className="modalResetCss" title="上传头像昵称跳转页" visible={addVisible} confirmLoading={addProfiles.loading} onOk={handleOk} onCancel={() => setAddVisible(false)}>
+            <Form
+                name="basicProfiles"
+                form={form}
+                layout='vertical'
+                autoComplete="off"
+                initialValues={{ ...initialValues }}
+            >
+                <Form.Item label={<strong>头像</strong>} name="imageData" rules={[{ required: true, message: '请选择头像!' }]}>
+                    <UploadImageOrMd5 />
+                </Form.Item>
+                <Form.Item label={<strong>昵称</strong>} name="profileName" rules={[{ required: true, message: '请输入昵称!' }]}>
+                    <Input placeholder="请输入名称" maxLength={12} />
+                </Form.Item>
+                <Form.Item label={<strong>详细描述</strong>} name="description">
+                    <Input.TextArea placeholder="请输入名称" maxLength={120} />
+                </Form.Item>
+            </Form>
+        </Modal>}
+    </Card>
+}
+
+export default React.memo(Profiles)
+
+
+interface ImageProps {
+    onChange?: (data: { imageUrl: string, imageMd5: string }) => void,
+    value?: { imageUrl: string, imageMd5: string }
+}
+/**
+ * 处理选择图片Form
+ * @returns 
+ */
+const UploadImageOrMd5: React.FC<ImageProps> = (props) => {
+
+    /*********************/
+    const { onChange, value } = props
+    const [selectImgVisible, setSelectImgVisible] = useState<boolean>(false)
+    const [sliderImgContent, setSliderImgContent] = useState<{ url: string, width?: number, height?: number }[]>([])  // 保存回填数据
+    const { init } = useModel('useLaunchAdq.useBdMediaPup')
+    /*********************/
+
+    useEffect(() => {
+        if (value && value?.imageUrl) {
+            setSliderImgContent([{ url: value.imageUrl }])
+        } else {
+            setSliderImgContent([])
+        }
+    }, [value])
+
+    const setImg = (content: any[]) => {
+        console.log(content)
+        onChange && onChange({ imageUrl: content[0]?.url, imageMd5: content[0]?.fileMd5 })
+        setSelectImgVisible(false)
+    }
+
+    const selectImg = () => {
+        init({ mediaType: 'IMG', cloudSize: [[{ relation: '=', width: 512, height: 512 }]], maxSize: 400 * 1024 })
+        setTimeout(() => { setSelectImgVisible(true) }, 50)
+    }
+
+    return <>
+        {value?.imageUrl ? <img src={value?.imageUrl} onClick={selectImg} width={100} height={100} /> : <Button onClick={selectImg}>选择图片</Button>}
+        <div style={{ fontSize: 12, color: 'rgba(0,0,0,.5)' }}>
+            <div>图片尺寸:512×512 像素</div>
+            <div>图片格式:大小要求在 400KB 以内,仅支持 jpg 和 png 格式</div>
+        </div>
+
+        {/* 选择素材 */}
+        {selectImgVisible && <SelectCloud visible={selectImgVisible} sliderImgContent={sliderImgContent} onClose={() => setSelectImgVisible(false)} onChange={setImg} />}
+    </>
+}
+
+
+
+export const SelectProfiles: React.FC<{ value?: number, onChange?: (value?: number) => void }> = ({value, onChange}) => {
+
+    /*******************************/
+    const getProfiles = useAjax((params) => getProfilesApi(params))
+    /*******************************/
+
+    // 获取列表
+    useEffect(() => {
+        getProfiles.run({})
+    }, [])
+
+    return <Select
+        showSearch
+        allowClear
+        placeholder="选择头像昵称跳转页"
+        filterOption={(input, option) =>
+            ((option?.label ?? '') as any).toLowerCase().includes(input.toLowerCase())
+        }
+        style={{ width: 480 }}
+        dropdownRender={menu => <>
+            {menu}
+            <Divider style={{ margin: '8px 0' }} />
+            <div>
+                <Button type="link" onClick={() => {
+                    window.location.href = '/#/launchSystemV3/tencentAdPutIn/create'
+                }}>前往管理</Button>
+            </div>
+        </>}
+        value={value}
+        onChange={(e) => onChange?.(e)}
+    >
+        {getProfiles?.data?.map((item: { id: number; headImageUrl: string; profileName: string; }) => <Select.Option value={item.id} key={item.id}>
+            <Space>
+                <Image width={20} style={{ borderRadius: 4 }} src={item.headImageUrl} />
+                <span>{item.profileName}</span>
+            </Space>
+        </Select.Option>)}
+    </Select>
+}

+ 81 - 0
src/pages/launchSystemV3/tencenTasset/profiles/tableConfig.tsx

@@ -0,0 +1,81 @@
+import { Space, Image, Popconfirm, TableProps } from "antd"
+import React from "react"
+
+
+const profilesColumns = (del: (id: number) => void): TableProps<any>['columns'] => {
+
+
+    const data: any[] = [
+        {
+            title: '操作',
+            dataIndex: 'cz',
+            key: 'cz',
+            align: 'center',
+            width: 100,
+            render: (a: any, b: any) => {
+                return <Space>
+                    <Popconfirm
+                        title="确定删除?"
+                        onConfirm={() => del(b.id)}
+                        okText="是"
+                        cancelText="否"
+                    >
+                        <a style={{ color: 'red' }}>删除</a>
+                    </Popconfirm>
+                </Space>
+            }
+        },
+        {
+            title: 'ID',
+            dataIndex: 'id',
+            key: 'id',
+            width: 60,
+            align: 'center',
+            render: (a: any, b: any) => {
+                return <span style={{ fontSize: "12px" }}>{a}</span>
+            }
+        },
+        {
+            title: '头像预览图',
+            dataIndex: 'headImageUrl',
+            key: 'headImageUrl',
+            width: 120,
+            ellipsis: true,
+            align: 'center',
+            render: (a: any) => {
+                return <Image width={40} style={{ borderRadius: 4 }} src={a} />
+            }
+        },
+        {
+            title: '昵称',
+            dataIndex: 'profileName',
+            key: 'profileName',
+            align: 'center',
+            render: (a: any, b: any) => {
+                return <span style={{ fontSize: "12px" }}>{a}</span>
+            }
+        },
+        {
+            title: '详细描述',
+            dataIndex: 'description',
+            key: 'description',
+            align: 'center',
+            render: (a: any, b: any) => {
+                return <span style={{ fontSize: "12px" }}>{a}</span>
+            }
+        },
+        {
+            title: '创建时间',
+            dataIndex: 'createTime',
+            key: 'createTime',
+            align: 'center',
+            render: (a: any, b: any) => {
+                return <span style={{ fontSize: "12px" }}>{a}</span>
+            }
+        }
+    ]
+
+    return data
+}
+
+export default profilesColumns

+ 15 - 1
src/pages/launchSystemV3/tencentAdPutIn/const.ts

@@ -370,7 +370,7 @@ export enum WECHAT_AD_NEHAVIOR_ENUM {
 	WECHAT_MOMENTS_AD_LIKE = '曾对你的朋友圈广告感兴趣',
 	// WECHAT_OFFICIAL_ACCOUNT_FOLLOWED = '已关注过你的公众号',
 	GDT_WECHAT_OFFICIAL_ACCOUNT_FOLLOWED = '已关注过你的公众号',
-	WECHAT_WORK_CONTACTS_ADDED = '已经添加过企业微信',
+	// WECHAT_WORK_CONTACTS_ADDED = '已经添加过企业微信',
 }
 
 /** 投放模式 */
@@ -379,6 +379,12 @@ export enum DELIVERY_MODE_ENUM {
 	DELIVERY_MODE_CUSTOMIZE = '自定义创意'
 }
 
+/** 创意形式匹配方式  */
+export enum DYNAMIC_CREATIVE_TYPE_ENUM {
+	DYNAMIC_CREATIVE_TYPE_COMMON = '手动指定',
+	DYNAMIC_CREATIVE_TYPE_PROGRAM = '自动匹配'
+}
+
 /** 落地页类型转换 */
 export const pageSpecFieldConVert = {
 	PAGE_TYPE_WECHAT_CANVAS: 'wechatCanvasSpec',  // 原生推广页
@@ -386,6 +392,10 @@ export const pageSpecFieldConVert = {
 	PAGE_TYPE_WECHAT_MINI_PROGRAM: 'wechatMiniProgramSpec', // 微信小程序
 	PAGE_TYPE_XJ_QUICK: 'xjQuickSpec', // "蹊径性能版落地页"
 	PAGE_TYPE_APP_DEEP_LINK: 'appDeepLinkSpec', // 应用直达 等
+	PAGE_TYPE_WECHAT_OFFICIAL_ACCOUNT_DETAIL: 'wechatOfficialAccountDetailSpec',
+	PAGE_TYPE_H5_PROFILE: 'h5ProfileSpec',
+	PAGE_TYPE_H5: 'h5Spec',
+	PAGE_TYPE_WECHAT_CHANNELS_PROFILE: 'wechatChannelsProfileSpec'
 }
 
 export const pageSpecFieldConVertUn = {
@@ -394,6 +404,10 @@ export const pageSpecFieldConVertUn = {
 	wechatMiniProgramSpec: 'PAGE_TYPE_WECHAT_MINI_PROGRAM', // 微信小程序
 	xjQuickSpec: 'PAGE_TYPE_XJ_QUICK', // "蹊径性能版落地页"
 	appDeepLinkSpec: 'PAGE_TYPE_APP_DEEP_LINK', // 应用直达 等
+	wechatOfficialAccountDetailSpec: 'PAGE_TYPE_WECHAT_OFFICIAL_ACCOUNT_DETAIL', // 微信公众号
+	h5ProfileSpec: 'PAGE_TYPE_H5_PROFILE', // 品牌简介页
+	h5Spec: 'PAGE_TYPE_H5',  // 自定义落地页
+	wechatChannelsProfileSpec: 'PAGE_TYPE_WECHAT_CHANNELS_PROFILE',  // 视频号
 }
 
 /** 落地页类型 */

+ 3 - 4
src/pages/launchSystemV3/tencentAdPutIn/create/Ad/adgroupsMarketingContent.tsx

@@ -61,7 +61,6 @@ const AdgroupsMarketingContent: React.FC<{ value?: any }> = ({ value }) => {
 
     useEffect(() => {
         if (OGPParams.marketingCarrierType && OGPParams.marketingTargetType) {
-            console.log('--->', OGPParams)
             getOptimizationGoalPermissions()
         }
     }, [OGPParams])
@@ -132,10 +131,10 @@ const AdgroupsMarketingContent: React.FC<{ value?: any }> = ({ value }) => {
     useEffect(() => {
         let optimizationGoalPermissionList: string[] = queryOptimizationGoalPermissions?.data?.optimizationGoalPermissionList
         // OPTIMIZATIONGOAL_ECOMMERCE_ORDER
-        if (!optimizationGoalPermissionList?.includes(optimizationGoal)) {
+        if (optimizationGoalPermissionList?.length > 0 && !optimizationGoalPermissionList?.includes(optimizationGoal)) {
             form.setFieldsValue({ optimizationGoal: optimizationGoalPermissionList?.includes('OPTIMIZATIONGOAL_ECOMMERCE_ORDER') ? 'OPTIMIZATIONGOAL_ECOMMERCE_ORDER' : optimizationGoalPermissionList?.includes('OPTIMIZATIONGOAL_PAGE_SCAN_CODE') ? 'OPTIMIZATIONGOAL_PAGE_SCAN_CODE' : undefined })
         }
-    }, [queryOptimizationGoalPermissions?.data?.optimizationGoalPermissionList, marketingGoal, marketingTargetType, marketingCarrierType, optimizationGoal])
+    }, [queryOptimizationGoalPermissions?.data?.optimizationGoalPermissionList, marketingGoal, marketingTargetType, marketingCarrierType, optimizationGoal, value])
 
     return <Card
         title={<strong style={{ fontSize: 18 }}>营销内容</strong>}
@@ -168,7 +167,7 @@ const AdgroupsMarketingContent: React.FC<{ value?: any }> = ({ value }) => {
                     allowClear
                     placeholder='请选择'
                 >
-                    {queryOptimizationGoalPermissions?.data?.optimizationGoalPermissionList.map((key: string) => {
+                    {queryOptimizationGoalPermissions?.data?.optimizationGoalPermissionList.filter((key: string) => key !== 'UNKNOWN').map((key: string) => {
                         return <Select.Option value={key} key={key}>{OPTIMIZATIONGOAL_ENUM[key]}</Select.Option>
                     })}
                 </Select>

+ 25 - 4
src/pages/launchSystemV3/tencentAdPutIn/create/Ad/adgroupsPrice.tsx

@@ -1,4 +1,4 @@
-import { Card, Form, Input, Space, Switch, Tooltip } from "antd"
+import { Card, Form, Input, InputNumber, Space, Switch, Tooltip } from "antd"
 import React, { useContext } from "react"
 import { DispatchAd } from "./newCreateAd";
 import New1Radio from "@/pages/launchSystemV3/components/New1Radio";
@@ -41,7 +41,13 @@ const AdgroupsPrice: React.FC = () => {
             rules={[{ required: true, message: '请选择计费方式' }]}
         >
             <New1Radio
-                data={Object.keys(BID_MODE_ENUM).filter(key => { if (siteSet?.some((name: string) => ['SITE_SET_CHANNELS', 'SITE_SET_MOMENTS'].includes(name) || automaticSiteEnabled)) { return key === 'BID_MODE_OCPM' || key === 'BID_MODE_CPM' } else { return true } })?.map(key => ({ label: BID_MODE_ENUM[key], value: key, disabled: optimizationGoal && ['BID_MODE_CPM', 'BID_MODE_CPC', 'BID_MODE_CPA'].includes(key) ? true : false }))}
+                data={Object.keys(BID_MODE_ENUM).filter(key => {
+                    if (siteSet?.some((name: string) => ['SITE_SET_CHANNELS', 'SITE_SET_MOMENTS'].includes(name)) || automaticSiteEnabled) {
+                        return key === 'BID_MODE_OCPM' || key === 'BID_MODE_CPM'
+                    } else {
+                        return true
+                    }
+                })?.map(key => ({ label: BID_MODE_ENUM[key], value: key, disabled: optimizationGoal && ['BID_MODE_CPM', 'BID_MODE_CPC', 'BID_MODE_CPA'].includes(key) ? true : false }))}
                 onChange={(e) => {
                     // form.setFieldsValue({ siteSet: defaultSiteSet })
                     setOGPparams({ ...OGPParams, automaticSiteEnabled: e, bidMode: e as string })
@@ -90,8 +96,23 @@ const AdgroupsPrice: React.FC = () => {
                 </Form.Item>
             </> :
                 deepConversionType === 'DEEP_CONVERSION_WORTH' ? <>
-                    <Form.Item label={<strong>期望ROI</strong>} name={['deepConversionSpec', 'deepConversionWorthSpec', 'expectedRoi']} rules={[{ required: true, message: '请输入期望ROI' }]}>
-                        <Input style={{ width: 480 }} placeholder={`期望ROI目标范围0.001~1000,输入0.05,表示ROI目标为5%`} />
+                    <Form.Item
+                        label={<strong>期望ROI</strong>}
+                        name={['deepConversionSpec', 'deepConversionWorthSpec', 'expectedRoi']}
+                        rules={[
+                            { required: true, message: '请输入期望ROI' },
+                            { type: 'number', min: 0.001, max: 1000, message: '范围0.001~1000' },
+                            {
+                                validator: (_: any, value: string) => {
+                                    if (!value || /^\d+(\.\d{0,3})?$/.test(value)) {
+                                        return Promise.resolve();
+                                    }
+                                    return Promise.reject(new Error('请输入最多三位小数'));
+                                }
+                            }
+                        ]}
+                    >
+                        <InputNumber style={{ width: 480 }} placeholder={`期望ROI目标范围0.001~1000,输入0.05,表示ROI目标为5%`} />
                     </Form.Item>
                 </> : null}
 

+ 16 - 3
src/pages/launchSystemV3/tencentAdPutIn/create/Ad/index.tsx

@@ -6,6 +6,7 @@ import { Button, Typography } from "antd";
 import { EditOutlined } from "@ant-design/icons";
 import { AD_STATUS_ENUM, BID_MODE_ENUM, DEEP_CONVERSION_ENUM, GOAL_ROAS_ENUM, MARKETING_CARRIER_TYPE_ENUM, MARKETING_GOAL_ENUM, MARKETING_TARGET_TYPE_ENUM, OPTIMIZATIONGOAL_ENUM, SITE_SET_ENUM, SMART_BID_TYPE_ENUM } from "../../const";
 import TimeSeriesLook from "@/pages/launchSystemNew/adq/ad/timeSeriesLook";
+import { arraysHaveSameValues } from "@/utils/utils";
 
 
 /**
@@ -15,11 +16,11 @@ import TimeSeriesLook from "@/pages/launchSystemNew/adq/ad/timeSeriesLook";
 const Ad: React.FC = () => {
 
     /*****************************/
-    const { addelivery, setAddelivery, accountCreateLogs, clearData } = useContext(DispatchAddelivery)!;
+    const { addelivery, setAddelivery, accountCreateLogs, clearData, setAccountCreateLogs } = useContext(DispatchAddelivery)!;
     const { adgroups } = addelivery
     const {
         marketingGoal, marketingAssetOuterSpec, marketingCarrierType, automaticSiteEnabled, siteSet, searchExpandTargetingSwitch, bidMode, smartBidType, bidAmount, optimizationGoal,
-        deepConversionSpec, autoAcquisitionEnabled, autoAcquisitionBudget, dailyBudget, endDate, beginDate, timeSeries, firstDayBeginTime, configuredStatus, adgroupName
+        deepConversionSpec, autoAcquisitionEnabled, autoAcquisitionBudget, dailyBudget, endDate, beginDate, timeSeries, firstDayBeginTime, configuredStatus, adgroupName, wechatPosition
     } = adgroups
     const [newVisible, setNewVisible] = useState<boolean>(false)
     /*****************************/
@@ -85,7 +86,19 @@ const Ad: React.FC = () => {
                 setNewVisible(false)
             }}
             onChange={(adgroups) => {
-                setAddelivery({ adgroups, targeting: [], dynamic: {}, dynamicMaterialDTos: {}, dynamicCreativesTextDTOS: {} })
+                if (
+                    adgroups.marketingGoal === marketingGoal &&  // 营销内容
+                    adgroups.marketingCarrierType === marketingCarrierType && // 营销载体
+                    adgroups.marketingAssetOuterSpec.marketingTargetType === marketingAssetOuterSpec.marketingTargetType && // 推广产品
+                    adgroups.automaticSiteEnabled === automaticSiteEnabled &&  // 版位选择
+                    arraysHaveSameValues(adgroups?.siteSet || [], siteSet || []) &&  // 版位
+                    arraysHaveSameValues(adgroups?.wechatPosition || [], wechatPosition || []) // 微信公众号与小程序定投
+                ) {
+                    setAddelivery({ ...addelivery, adgroups })
+                } else {
+                    setAccountCreateLogs(accountCreateLogs.map(item => ({ accountId: item.accountId })))
+                    setAddelivery({ adgroups, targeting: [], dynamic: {}, dynamicMaterialDTos: {}, dynamicCreativesTextDTOS: {} })
+                }
                 setNewVisible(false)
                 clearData()
             }}

+ 1 - 1
src/pages/launchSystemV3/tencentAdPutIn/create/Ad/newCreateAd.tsx

@@ -196,7 +196,7 @@ const NewCreateAd: React.FC<Props> = ({ value, visible, onChange, onClose }) =>
                 deepConversionSpec: {
                     deepConversionType: 'DEEP_CONVERSION_WORTH'
                 },
-                bidAmount: 1000,
+                // bidAmount: 1000,
                 timeSeries: getTimeSeriesList(),
                 autoAcquisitionEnabled: false,
                 configuredStatus: 'AD_STATUS_SUSPEND',

+ 89 - 10
src/pages/launchSystemV3/tencentAdPutIn/create/Dynamic/creativeConversionAssistant.tsx

@@ -1,15 +1,16 @@
-import { Card, Form, Radio, Select, Switch } from "antd"
-import React, { useContext, useMemo, useState } from "react"
+import { Card, Checkbox, Form, Radio, Select, Space, Switch, Tooltip } from "antd"
+import React, { useContext, useEffect, useMemo, useState } from "react"
 import { DispatchDynamic } from "./newDynamic";
 import style from '../index.less'
 import New1Radio from "@/pages/launchSystemV3/components/New1Radio";
 import { useUpdateEffect } from "ahooks";
+import { QuestionCircleFilled } from "@ant-design/icons";
 
 /**
  * 营销组件
  * @returns 
  */
-const CreativeConversionAssistant: React.FC = () => {
+const CreativeConversionAssistant: React.FC<{ automaticSiteEnabled?: boolean }> = ({ automaticSiteEnabled }) => {
 
     /**************************************/
     const { creativeComponents, form, isUpdate, setIsUpdate } = useContext(DispatchDynamic)!;
@@ -20,6 +21,9 @@ const CreativeConversionAssistant: React.FC = () => {
     const linkNameType = Form.useWatch(['textLink', 'value', 'linkNameType'], form)
     const conversionDataType = Form.useWatch(['showData', 'value', 'conversionDataType'], form)
     const conversionTargetType = Form.useWatch(['showData', 'value', 'conversionTargetType'], form)
+    const creativeTemplateId = Form.useWatch('creativeTemplateId', form)
+    const cardType: string[] = Form.useWatch('cardType', form)
+    const [cardData, setCardData] = useState<{ label: string, value: string, disabled?: boolean }[]>([])
     /**************************************/
 
     useUpdateEffect(() => {
@@ -83,7 +87,7 @@ const CreativeConversionAssistant: React.FC = () => {
     /** 微信文字链 */
     const textLinkContent = useMemo(() => {
         let textLink = creativeComponents?.text_link
-        if (textLink) {
+        if (textLink && ![1707, 1708].includes(creativeTemplateId) && !automaticSiteEnabled) {
             let pageSpecPageType = pageSpec?.[0]?.pageType || 'PAGE_TYPE_WECHAT_CANVAS'
             let textLinkRequired, linkNameEnumeration: { label: string, value: string }[] = [];
             let linkNamePageType, linkNamePageTypeEnumeration: PULLIN.DataType[] = [];
@@ -143,10 +147,14 @@ const CreativeConversionAssistant: React.FC = () => {
             </Form.Item>
         }
         return null
-    }, [creativeComponents?.text_link, pageSpec, textLinkShow])
+    }, [creativeComponents?.text_link, pageSpec, textLinkShow, creativeTemplateId, automaticSiteEnabled])
 
     /** 行动按钮 */
     const actionButtonContent = useMemo(() => {
+        // 卡片广告用卡片组件控制
+        if ([1707, 1708].includes(creativeTemplateId) && !cardType?.includes('action_button')) {
+            return null
+        }
         let actionButton = creativeComponents?.action_button
         if (actionButton) {
             let pageSpecPageType = pageSpec?.[0]?.pageType || 'PAGE_TYPE_WECHAT_CANVAS'
@@ -161,15 +169,15 @@ const CreativeConversionAssistant: React.FC = () => {
             }
 
             return <Form.Item style={{ marginBottom: 0 }}>
-                <div className={style.newSpace}>
+                {![1707, 1708].includes(creativeTemplateId) && <div className={style.newSpace}>
                     <div className={style.newSpace_top}>
                         <div className={style.newSpace_title}>行动按钮</div>
                         <Form.Item name={'actionButtonShow'} valuePropName="checked" style={{ marginBottom: 0 }}>
                             <Switch disabled={actionButtonRequired} />
                         </Form.Item>
                     </div>
-                </div>
-                {actionButtonShow && <Card bordered className="cardResetCss newCss" bodyStyle={{ padding: 0 }}>
+                </div>}
+                {(actionButtonShow || cardType?.includes('action_button')) && <Card bordered className="cardResetCss newCss" bodyStyle={{ padding: 0 }}>
                     <div className={style.newSpace}>
                         <div className={style.newSpace_top}>
                             <div className={style.newSpace_title}>按钮文案</div>
@@ -207,7 +215,7 @@ const CreativeConversionAssistant: React.FC = () => {
             </Form.Item>
         }
         return null
-    }, [creativeComponents?.action_button, pageSpec, actionButtonShow])
+    }, [creativeComponents?.action_button, pageSpec, actionButtonShow, cardType, creativeTemplateId])
 
     const showDataContent = useMemo(() => {
         let showData = creativeComponents?.show_data;
@@ -238,6 +246,10 @@ const CreativeConversionAssistant: React.FC = () => {
                         .map(item => ({ label: item.description, value: item.value }))
                 }
             }
+            // 卡片广告去掉商品数据
+            if ([1707, 1708].includes(creativeTemplateId)) {
+                conversionDataTypeEnumeration = conversionDataTypeEnumeration.filter(item => item.value !== "CONVERSION_DATA_PRODUCT_DATA")
+            }
 
             return <Form.Item style={{ marginBottom: 0 }}>
                 <div className={style.newSpace}>
@@ -277,13 +289,80 @@ const CreativeConversionAssistant: React.FC = () => {
             </Form.Item>
         }
         return null
-    }, [creativeComponents?.show_data, linkNameType, showDataShow])
+    }, [creativeComponents?.show_data, linkNameType, showDataShow, creativeTemplateId])
+
+
+    useEffect(() => {
+        let data = [
+            { label: '不使用', value: 'not', disabled: false },
+            { label: '行动按钮', value: 'action_button', disabled: cardType?.some(item => ['chosen_button', 'shop_imag'].includes(item)) },
+            // { label: '选择按钮', value: 'chosen_button', disabled: cardType?.some(item => ['label', 'action_button', 'shop_imag'].includes(item)) },
+            // { label: '卖点图', value: 'shop_imag', disabled: cardType?.some(item => ['chosen_button'].includes(item)) },
+            // { label: '标签', value: 'label', disabled: cardType?.some(item => ['chosen_button', 'count_down'].includes(item)) },
+            // { label: '倒计时', value: 'count_down', disabled: cardType?.some(item => ['living_desc', 'label'].includes(item)) },
+            // { label: '轮播文案', value: 'living_desc', disabled: cardType?.some(item => ['count_down'].includes(item)) }
+        ]
+        if (cardType?.length >= 3) {
+            setCardData(data.map(item => {
+                if (cardType.includes(item.value)) {
+                    return { ...item, disabled: false }
+                } else if (item.value === 'not') {
+                    return { ...item, disabled: false }
+                } else {
+                    return { ...item, disabled: true }
+                }
+            }))
+        } else {
+            setCardData(data)
+        }
+    }, [cardType])
 
     if (Object.keys(creativeComponents).some(key => ['text_link', 'action_button', 'show_data'].includes(key))) {
         return <Card
             title={<strong style={{ fontSize: 18 }}>营销组件</strong>}
             className="cardResetCss"
         >
+            {/* 卡片广告所需 */}
+            {[1707, 1708].includes(creativeTemplateId) && <Form.Item style={{ marginBottom: 0 }}>
+                <div className={style.newSpace}>
+                    <div className={style.newSpace_top}>
+                        <div className={style.newSpace_title}>
+                            <Space>
+                                <strong>卡片组件</strong>
+                                <Tooltip title={<div>
+                                    卡片组件有以下使用条件:<br />
+                                    1.卡片组件最多只能使用 3 个<br />
+                                    2.倒计时不能与标签、轮播文案同时使用<br />
+                                    3.卖点图必须与行动按钮同时使用<br />
+                                    4.选择按钮不能与行动按钮、标签、卖点图同时使用
+                                </div>}>
+                                    <QuestionCircleFilled />
+                                </Tooltip>
+                            </Space>
+                        </div>
+                        <Form.Item
+                            noStyle
+                            name={'cardType'}
+                            rules={[{ required: true, message: '请选择跳转落地页类型' }]}
+                            style={{ marginBottom: 0 }}
+                            getValueFromEvent={(e: string[]) => {
+                                if (e.length > 1 && !cardType.includes('not') && e.includes('not')) {
+                                    return ['not'];
+                                }
+                                if (e.includes('shop_imag') && !e.includes('action_button')) {
+                                    e.push('action_button')
+                                }
+                                return e.length > 0 ? (e.length > 1 && e.includes('not') ? e.filter(item => item !== 'not') : e) : ['not'];
+                            }}
+                        >
+                            <Checkbox.Group options={cardData} onChange={(e) => {
+                                console.log(e)
+                            }} />
+                        </Form.Item>
+                    </div>
+                </div>
+
+            </Form.Item>}
             {textLinkContent}
             {actionButtonContent}
             {showDataContent}

+ 9 - 4
src/pages/launchSystemV3/tencentAdPutIn/create/Dynamic/creativeTemplateContent.tsx

@@ -4,13 +4,14 @@ import { DispatchDynamic } from "./newDynamic";
 import New1Radio from "@/pages/launchSystemV3/components/New1Radio";
 import { MinusCircleOutlined, PlusOutlined } from "@ant-design/icons";
 import BrandImage from "@/pages/launchSystemV3/components/BrandImage";
+import { SelectProfiles } from "@/pages/launchSystemV3/tencenTasset/profiles";
 
 
 /**
  * 创意内容
  * @returns 
  */
-const CreativeTemplateContent: React.FC = () => {
+const CreativeTemplateContent: React.FC<{ automaticSiteEnabled: boolean }> = ({ automaticSiteEnabled }) => {
 
     /******************************************/
     const { creativeComponents, form, adgroups: { siteSet } } = useContext(DispatchDynamic)!;
@@ -46,8 +47,12 @@ const CreativeTemplateContent: React.FC = () => {
                 <Form.Item name={['jumpInfo', 'pageType']} label={<strong>品牌形象跳转</strong>} rules={[{ required: true, message: '请选择品牌形象跳转!' }]} tooltip="品牌形象将在各流量版位下广告外层创意展示。此外,朋友圈广告在此基础上支持跳转,点击品牌形象可跳转到品牌简介页或搜一搜品牌主页">
                     <New1Radio data={enumeration} />
                 </Form.Item>
-                {['PAGE_TYPE_H5_PROFILE', "PAGE_TYPE_NOT_USED"].includes(pageType) && <div style={{ margin: '0 0 10px', backgroundColor: '#fafafb', padding: '8px 16px 8px', borderRadius: 8 }}>
+                {['PAGE_TYPE_H5_PROFILE'].includes(pageType) ? <div style={{ margin: '0 0 10px', backgroundColor: '#fafafb', padding: '8px 16px 8px', borderRadius: 8 }}>
                     <Form.Item name='brand' style={{ marginBottom: 0 }} rules={[{ required: true, message: '请选择一个头像及昵称跳转页,与广告创意一起展示' }]}>
+                        <SelectProfiles />
+                    </Form.Item>
+                </div> : ["PAGE_TYPE_NOT_USED"].includes(pageType) && <div style={{ margin: '0 0 10px', backgroundColor: '#fafafb', padding: '8px 16px 8px', borderRadius: 8 }}>
+                    <Form.Item name='brand' style={{ marginBottom: 0 }} rules={[{ required: true, message: '请选择一个品牌形象,与广告创意一起展示' }]}>
                         <BrandImage />
                     </Form.Item>
                 </div>}
@@ -65,7 +70,7 @@ const CreativeTemplateContent: React.FC = () => {
                                             style={{ marginBottom: 0 }}
                                             rules={[{ required: true, message: '请选择跳转类型!' }]}
                                         >
-                                            <New1Radio 
+                                            <New1Radio
                                                 data={pageTypeList}
                                                 onChange={(pageType) => {
                                                     form.setFieldsValue({ pageSpec: pageSpec.map((item: any) => ({ ...item, pageType })) })
@@ -87,7 +92,7 @@ const CreativeTemplateContent: React.FC = () => {
                                                 }}
                                             />
                                         </Form.Item>
-                                        {siteSet?.some((name: string) => name === 'SITE_SET_MOMENTS') && <div style={{ margin: 0, backgroundColor: '#fafafb', padding: '8px 16px 8px', borderRadius: 8 }}>
+                                        {((siteSet?.some((name: string) => name === 'SITE_SET_MOMENTS') || automaticSiteEnabled) && pageSpec?.[key]?.pageType === 'PAGE_TYPE_WECHAT_CANVAS') && <div style={{ margin: 0, backgroundColor: '#fafafb', padding: '8px 16px 8px', borderRadius: 8 }}>
                                             <Form.Item
                                                 name={[name, 'overrideCanvasHeadOption']}
                                                 style={{ marginBottom: 0 }}

+ 55 - 16
src/pages/launchSystemV3/tencentAdPutIn/create/Dynamic/index.tsx

@@ -5,9 +5,9 @@ import { EditOutlined } from "@ant-design/icons"
 import { DispatchAddelivery } from ".."
 import NewDynamic from "./newDynamic"
 import { AD_STATUS_ENUM, CONVERSION_DATA_ENUM, CONVERSION_TARGET_ENUM, DELIVERY_MODE_ENUM, PAGE_TYPE_ENUM, TEXT_LINK_TYPE_ENUM, pageSpecFieldConVertUn } from "../../const"
-import { getCreativeDetailsApi } from "@/services/adqV3/global"
+import { getCreativeDetailsApi, getProfilesApi } from "@/services/adqV3/global"
 import { useAjax } from "@/Hook/useAjax"
-import { processData } from "@/utils/utils"
+import { arraysHaveSameValues, processData } from "@/utils/utils"
 
 /**
  * 创意
@@ -16,31 +16,37 @@ import { processData } from "@/utils/utils"
 const Dynamic: React.FC = () => {
 
     /***************************************/
-    const { addelivery, setAddelivery, setMaterialData, setTextData, clearData } = useContext(DispatchAddelivery)!;
+    const { addelivery, setAddelivery, setMaterialData, setTextData, clearData, setAccountCreateLogs, accountCreateLogs } = useContext(DispatchAddelivery)!;
     const { adgroups, dynamic: dynamicData } = addelivery;
-    const { marketingGoal, marketingAssetOuterSpec, marketingCarrierType, siteSet, wechatPosition } = adgroups
+    const { marketingGoal, marketingAssetOuterSpec, marketingCarrierType, siteSet, automaticSiteEnabled, wechatPosition } = adgroups
     const { deliveryMode, creativeTemplateId, dynamicCreativeName, creativeComponents, configuredStatus } = dynamicData
-    const { textLink, actionButton, showData, brand } = creativeComponents || {}
-    let pageSpec = brand?.[0]?.value?.jumpInfo?.pageSpec
+    const { textLink, actionButton, showData, brand, mainJumpInfo } = creativeComponents || {}
     const [newVisible, setNewVisible] = useState<boolean>(false);
     const [creativeTemplateAppellation, setCreativeTemplateAppellation] = useState<string>()
     const [creativeTemplateStyle, setCreativeTemplateStyle] = useState<string>()
+    const [profileData, setprofileData] = useState<any>()
 
     const getCreativeDetails = useAjax((params) => getCreativeDetailsApi(params))
+    const getProfiles = useAjax((params) => getProfilesApi(params))
     /***************************************/
 
     useEffect(() => {
         if (creativeTemplateId) {
-            getCreativeDetails.run({
+            let params: any = {
                 marketingGoal,
                 marketingTargetType: marketingAssetOuterSpec.marketingTargetType,
                 marketingCarrierType,
-                siteSet,
                 deliveryMode,
                 creativeTemplateId,
                 wechatSceneSpecPosition: wechatPosition,
                 dynamicCreativeType: deliveryMode === 'DELIVERY_MODE_COMPONENT' ? 'DYNAMIC_CREATIVE_TYPE_PROGRAM' : 'DYNAMIC_CREATIVE_TYPE_COMMON'
-            }).then(res => {
+            }
+            if (automaticSiteEnabled) {
+                params.automaticSiteEnabled = automaticSiteEnabled
+            } else {
+                params.siteSet = siteSet
+            }
+            getCreativeDetails.run(params).then(res => {
                 if (res?.adcreativeTemplateStructAdpermits?.length > 0) {
                     let adcreativeTemplateStructAdpermits = res?.adcreativeTemplateStructAdpermits[0]
                     setCreativeTemplateAppellation(adcreativeTemplateStructAdpermits.creativeTemplateAppellation)
@@ -48,10 +54,10 @@ const Dynamic: React.FC = () => {
 
                     let creativeComponents = adcreativeTemplateStructAdpermits?.creativeComponents || []
                     let result = processData(creativeComponents);
-            
+
                     let newMaterialData = {};
                     let newTextData = {};
-            
+
                     Object.keys(result).forEach(key => {
                         let data = result[key]
                         if ((key === 'image_list' || key === 'short_video' || key === 'video' || key === 'image' || key === 'element_story') && data.required) {
@@ -60,13 +66,23 @@ const Dynamic: React.FC = () => {
                             newTextData[key] = data
                         }
                     })
-            
+
                     setMaterialData(newMaterialData)
                     setTextData(newTextData)
                 }
             })
         }
-    }, [creativeTemplateId, deliveryMode, marketingGoal, marketingAssetOuterSpec, marketingCarrierType, siteSet, wechatPosition])
+    }, [creativeTemplateId, deliveryMode, marketingGoal, marketingAssetOuterSpec, marketingCarrierType, siteSet, wechatPosition, automaticSiteEnabled])
+
+    useEffect(() => {
+        if (['PAGE_TYPE_H5_PROFILE'].includes(brand?.[0]?.value?.jumpInfo?.pageType)) {
+            getProfiles.run({}).then(res => {
+                if (res) {
+                    setprofileData(res?.find((item: { id: any }) => item.id === brand?.[0]?.value?.profileId))
+                }
+            })
+        }
+    }, [brand])
 
     return <div className={`${style.settingsBody_content_row} ${style.row3}`}>
         <div className={style.title}>
@@ -81,12 +97,23 @@ const Dynamic: React.FC = () => {
                     <p>创意形式:{creativeTemplateAppellation || creativeTemplateId}</p>
                     {brand?.length > 0 && <>
                         <p style={{ fontWeight: 'bold', color: '#000' }}>品牌形象跳转:{PAGE_TYPE_ENUM[brand?.[0]?.value?.jumpInfo?.pageType]}</p>
-                        {['PAGE_TYPE_H5_PROFILE', 'PAGE_TYPE_NOT_USED'].includes(brand?.[0]?.value?.jumpInfo?.pageType) && <Space align="center">
+                        {['PAGE_TYPE_H5_PROFILE'].includes(brand?.[0]?.value?.jumpInfo?.pageType) ? <>
+                            {profileData ? <>
+                                <Space>
+                                    <img src={profileData?.headImageUrl} alt="" width={20} style={{ display: 'block' }} />
+                                    <span style={{ fontWeight: 'bold', color: '#000', fontSize: 12 }}>{profileData?.profileName}</span>
+                                </Space>
+                                <p>详细描述:{profileData?.description}</p>
+                            </> : <span style={{ color: 'red', fontWeight: 'bold', fontSize: 12 }}>{getProfiles.loading ? '' : '当前头像昵称跳转页被删除'} </span>}
+                        </> : ['PAGE_TYPE_NOT_USED'].includes(brand?.[0]?.value?.jumpInfo?.pageType) && <Space align="center">
                             <img src={brand?.[0]?.value?.brandImageId} alt="" width={20} style={{ display: 'block' }} />
                             <span style={{ fontWeight: 'bold', color: '#000', fontSize: 12 }}>{brand?.[0]?.value?.brandName}</span>
                         </Space>}
-                        {(pageSpec && Object.keys(pageSpec).length > 0) && <p style={{ fontWeight: 'bold', color: '#000' }}>跳转类型:{PAGE_TYPE_ENUM[pageSpecFieldConVertUn[Object.keys(pageSpec)?.[0]]]}</p>}
                     </>}
+                    <p style={{ fontWeight: 'bold', color: '#000' }}>跳转类型:{mainJumpInfo?.map((item: any) => {
+                        let pageSpec = item.value.pageSpec
+                        return PAGE_TYPE_ENUM[pageSpecFieldConVertUn[Object.keys(pageSpec)?.[0]]]
+                    }).toString()}</p>
                     {textLink?.length > 0 && <>
                         <p style={{ fontWeight: 'bold', color: '#000' }}>朋友圈文字链:开启</p>
                         <p>文字链文案:{TEXT_LINK_TYPE_ENUM[textLink?.[0]?.value?.linkNameType]}</p>
@@ -117,9 +144,21 @@ const Dynamic: React.FC = () => {
                 setNewVisible(false)
             }}
             onChange={(dynamic) => {
-                setAddelivery({ ...addelivery, dynamic, dynamicMaterialDTos: {}, dynamicCreativesTextDTOS: {} })
+                if (
+                    dynamic.deliveryMode === deliveryMode && // 投放模式
+                    dynamic?.creativeTemplateId === creativeTemplateId // 创意形式
+                ) {
+                    setAddelivery({ ...addelivery, dynamic })
+                } else {
+                    setAddelivery({ ...addelivery, dynamic, dynamicMaterialDTos: {}, dynamicCreativesTextDTOS: {} })
+                }
+                let oldPageTypeList = mainJumpInfo.map((item: { value: { pageType: any } }) => item.value.pageType)
+                let newPageTypeList = dynamic?.creativeComponents?.mainJumpInfo.map((item: { value: { pageType: any } }) => item.value.pageType)
                 setNewVisible(false)
                 clearData()
+                if (!arraysHaveSameValues(oldPageTypeList || [], newPageTypeList || [])) {
+                    setAccountCreateLogs(accountCreateLogs.map(item => ({ ...item, pageList: [] })))
+                }
             }}
         />}
     </div>

+ 100 - 32
src/pages/launchSystemV3/tencentAdPutIn/create/Dynamic/newDynamic.tsx

@@ -42,7 +42,7 @@ const NewDynamic: React.FC<Props> = ({ value, visible, onClose, onChange, creati
     const [adcreativeTemplateList, setAdcreativeTemplateList] = useState<PULLIN.AdcreativeTemplateList[]>([])
     const [creativeComponents, setCreativeComponents] = useState<any>({})
     const [isUpdate, setIsUpdate] = useState<boolean>(false)
-    const { marketingGoal, marketingAssetOuterSpec, marketingCarrierType, siteSet, wechatPosition } = adgroups
+    const { marketingGoal, marketingAssetOuterSpec, marketingCarrierType, siteSet, wechatPosition, automaticSiteEnabled } = adgroups
 
     const [newMaterialData, setNewMaterialData] = useState<any>({}) // 素材数据
     const [newTextData, setNewTextData] = useState<any>({})
@@ -53,13 +53,22 @@ const NewDynamic: React.FC<Props> = ({ value, visible, onClose, onChange, creati
 
     useEffect(() => {
         if (deliveryMode === 'DELIVERY_MODE_CUSTOMIZE') { // 自定义创意
-            getCreativeTemplateList.run({ marketingGoal, marketingTargetType: marketingAssetOuterSpec.marketingTargetType, marketingCarrierType, siteSet, wechatSceneSpecPosition: wechatPosition }).then((res: any) => {
+            getCreativeTemplateList.run({
+                marketingGoal,
+                marketingTargetType: marketingAssetOuterSpec.marketingTargetType,
+                marketingCarrierType,
+                siteSet,
+                wechatSceneSpecPosition: wechatPosition || []
+            }).then((res: any) => {
                 let newArr: any = []
                 let newData: any[] = []
                 // 过滤掉相同的和即将下线的
                 if (!res) {
                     return
                 }
+                if (automaticSiteEnabled) {
+                    delete res?.SITE_SET_WECHAT
+                }
                 let creativeTemplateStyle = ''
                 Object.values(res)?.forEach(arr => {
                     newData.push(arr)
@@ -120,7 +129,7 @@ const NewDynamic: React.FC<Props> = ({ value, visible, onClose, onChange, creati
         } else if (deliveryMode === 'DELIVERY_MODE_COMPONENT') {  // 组件化创意
             getTemplate()
         }
-    }, [deliveryMode, marketingGoal, marketingAssetOuterSpec, marketingCarrierType, siteSet, wechatPosition, value])
+    }, [deliveryMode, marketingGoal, marketingAssetOuterSpec, marketingCarrierType, siteSet, wechatPosition, value, automaticSiteEnabled])
 
     useEffect(() => {
         if (!(value && Object.keys(value).length > 0) && adcreativeTemplateList?.length > 0 && marketingGoalTypeList?.length > 0) {
@@ -143,20 +152,29 @@ const NewDynamic: React.FC<Props> = ({ value, visible, onClose, onChange, creati
     const getTemplate = (id?: any, isAntTemplateId?: boolean) => {
         // CAMPAIGN_TYPE_NORMAL
         if (marketingAssetOuterSpec?.marketingTargetType && deliveryMode) {
-            getCreativeDetails.run({
+            let params: any = {
                 marketingGoal,
                 marketingTargetType: marketingAssetOuterSpec.marketingTargetType,
                 marketingCarrierType,
-                siteSet: (id === 910 && siteSet?.includes('SITE_SET_MOMENTS')) ? siteSet.filter((item: string) => item !== 'SITE_SET_MOMENTS') : siteSet,
                 deliveryMode,
                 creativeTemplateId: id,
                 wechatSceneSpecPosition: wechatPosition,
                 dynamicCreativeType: deliveryMode === 'DELIVERY_MODE_COMPONENT' ? 'DYNAMIC_CREATIVE_TYPE_PROGRAM' : 'DYNAMIC_CREATIVE_TYPE_COMMON'
-            }).then(res => {
+            }
+            if (automaticSiteEnabled) {
+                params.automaticSiteEnabled = automaticSiteEnabled
+            } else {
+                params.siteSet = siteSet
+            }
+            getCreativeDetails.run(params).then(res => {
                 if (res?.adcreativeTemplateStructAdpermits?.length > 0) {
                     let adcreativeTemplateStructAdpermits = res?.adcreativeTemplateStructAdpermits[0]
                     templateChange(adcreativeTemplateStructAdpermits, isAntTemplateId)
                 } else {
+                    message.error({
+                        content: '当前所选营销目的,广告版位下不支持该创意形式。或者无此创意形式权限,请联系相关人员开通白名单',
+                        duration: 10
+                    })
                     setCreativeComponents({})
                 }
             })
@@ -166,6 +184,7 @@ const NewDynamic: React.FC<Props> = ({ value, visible, onClose, onChange, creati
     //每次选中创意设置该展示的界面
     const templateChange = (adcreativeTemplateStructAdpermits: any, isAntTemplateId?: boolean) => {
         let creativeComponents = adcreativeTemplateStructAdpermits?.creativeComponents || []
+        let creativeTemplateId = adcreativeTemplateStructAdpermits?.creativeTemplateId
         let creativeTemplateAppellation = adcreativeTemplateStructAdpermits?.creativeTemplateAppellation
         let result = processData(creativeComponents);
         console.log(result);
@@ -186,14 +205,14 @@ const NewDynamic: React.FC<Props> = ({ value, visible, onClose, onChange, creati
 
         setNewMaterialData(newMaterialData)
         setNewTextData(newTextData)
-
         if (!(value && Object.keys(value).length > 0) || isAntTemplateId) {
             let values: any = {
                 dynamicCreativeName: creativeTemplateAppellation ? '自定义创意' + '_' + creativeTemplateAppellation + '_' + localStorage.getItem('userId') + '_' + randomString(true, 3, 5) : '动态创意' + '_' + localStorage.getItem('userId') + '_' + randomString(true, 3, 5),
                 pageSpec: [{
                     pageType: 'PAGE_TYPE_WECHAT_CANVAS',
                     overrideCanvasHeadOption: 'OPTION_CREATIVE_OVERRIDE_CANVAS'
-                }]
+                }],
+                brand: undefined
             }
             Object.keys(result).forEach(key => {
                 switch (key) {
@@ -236,6 +255,10 @@ const NewDynamic: React.FC<Props> = ({ value, visible, onClose, onChange, creati
                         break
                 }
             })
+            if ([1707, 1708].includes(creativeTemplateId)) {
+                delete values?.actionButtonShow
+                values.cardType = ['not']
+            }
             form.setFieldsValue(values)
             setTimeout(() => { setIsUpdate(true) }, 50)
         }
@@ -252,6 +275,7 @@ const NewDynamic: React.FC<Props> = ({ value, visible, onClose, onChange, creati
             textLinkShow,
             textLink,
             actionButtonShow,
+            cardType,
             actionButton,
             showDataShow,
             showData,
@@ -264,7 +288,12 @@ const NewDynamic: React.FC<Props> = ({ value, visible, onClose, onChange, creati
 
         let creativeComponents: any = {}
 
+        let actionButtonJumpInfo = {
+            pageType: undefined
+        }
         if (pageSpec?.length > 0) {
+            let { pageType } = pageSpec?.[0]
+            actionButtonJumpInfo.pageType = pageType
             creativeComponents.mainJumpInfo = pageSpec.map((item: { pageType: string, overrideCanvasHeadOption: string, }) => {
                 return {
                     value: {
@@ -280,13 +309,16 @@ const NewDynamic: React.FC<Props> = ({ value, visible, onClose, onChange, creati
             })
         }
 
-        // 这边没有闪屏视频逻辑
+        // 品牌形象
         if (jumpInfo) {
             let pageType = jumpInfo.pageType
+            console.log('pageType-->', pageType)
             let value = {
                 jumpInfo
             }
-            if (['PAGE_TYPE_H5_PROFILE', "PAGE_TYPE_NOT_USED"].includes(pageType)) {
+            if (['PAGE_TYPE_H5_PROFILE'].includes(pageType)) {
+                value['profileId'] = brand
+            } else if (["PAGE_TYPE_NOT_USED"].includes(pageType)) {
                 let [brandName, brandImageId] = brand.split('_')
                 value['brandName'] = brandName
                 value['brandImageId'] = brandImageId
@@ -294,12 +326,22 @@ const NewDynamic: React.FC<Props> = ({ value, visible, onClose, onChange, creati
                 value['brandName'] = null
                 value['brandImageId'] = null
             }
-            // 处理落地页类型相关
-            let { pageType: pageSpecPageType, overrideCanvasHeadOption } = pageSpec?.[0]
+
             let pageSpecData: any = {}
-            pageSpecData[pageSpecFieldConVert[pageSpecPageType]] = {
-                pageId: null,
-                overrideCanvasHeadOption
+
+            if (pageType === 'PAGE_TYPE_H5_PROFILE') {
+                pageSpecData[pageSpecFieldConVert[pageType]] = {
+                    pageId: null
+                }
+            } else if (pageType === 'PAGE_TYPE_H5') {
+                pageSpecData[pageSpecFieldConVert[pageType]] = {
+                    pageUrl: null,
+                    mpaH5WildcardUrl: null
+                }
+            } else if (pageType === 'PAGE_TYPE_WECHAT_OFFICIAL_ACCOUNT_DETAIL') {
+                pageSpecData[pageSpecFieldConVert[pageType]] = {
+                    appId: null
+                }
             }
             value.jumpInfo = {
                 ...value.jumpInfo,
@@ -314,8 +356,18 @@ const NewDynamic: React.FC<Props> = ({ value, visible, onClose, onChange, creati
         }
 
         // 行动按钮
-        if (actionButtonShow) {
-            creativeComponents.actionButton = [actionButton]
+        if (actionButton && Object.keys(actionButton).length > 0) {
+            let newActionButton = [actionButton]
+            if (!actionButton.value?.jumpInfo) {
+                newActionButton = [{
+                    ...actionButton,
+                    value: {
+                        ...actionButton.value,
+                        jumpInfo: actionButtonJumpInfo
+                    }
+                }]
+            }
+            creativeComponents.actionButton = newActionButton
         }
 
         // 数据外显
@@ -337,40 +389,47 @@ const NewDynamic: React.FC<Props> = ({ value, visible, onClose, onChange, creati
                     brand,
                     textLink,
                     actionButton,
-                    showData
+                    showData,
+                    mainJumpInfo,
                 },
                 ...surplusValues
             } = JSON.parse(JSON.stringify(value))
             let dynamicValues: any = {
                 ...surplusValues
             }
+            // 卡片广告
+            let isCardDynamic = dynamicValues?.creativeTemplateId && [1707, 1708].includes(dynamicValues.creativeTemplateId)
+            let cardType: string[] = []
 
             // 529 闪屏视频 没有品牌 要单独处理
             if (brand && brand?.length > 0) {
-                let { jumpInfo, brandName, brandImageId } = brand[0].value
+                let { jumpInfo, brandName, brandImageId, profileId } = brand[0].value
                 if (jumpInfo) {
-                    let {
-                        pageSpec,
-                        pageType
-                    } = jumpInfo
-                    dynamicValues.jumpInfo = {
-                        pageType
-                    }
-                    let key = Object.keys(pageSpec)[0]
-                    let pageSpecValue = pageSpec[key]
-                    dynamicValues.pageSpec = Array(brand.length).fill('').map(() => ({ ...pageSpecValue, pageType: pageSpecFieldConVertUn[key] }))
+                    let { pageType } = jumpInfo
+                    dynamicValues.jumpInfo = { pageType }
                 }
                 if (brandName && brandImageId) {
                     dynamicValues.brand = brandName + '_' + brandImageId
+                } else if (profileId) {
+                    dynamicValues.brand = profileId
                 }
             }
 
+            if (mainJumpInfo && mainJumpInfo?.length > 0) {
+                dynamicValues.pageSpec = mainJumpInfo.map((item: any) => {
+                    let { pageSpec } = item.value
+                    let key = Object.keys(pageSpec)[0]
+                    let pageSpecValue = pageSpec[key]
+                    return { ...pageSpecValue, pageType: pageSpecFieldConVertUn[key] }
+                })
+            }
+
             // 文字链
             if (textLink && textLink?.length > 0) {
                 dynamicValues = {
                     ...dynamicValues,
                     textLinkShow: true,
-                    textLink
+                    textLink: textLink[0]
                 }
             }
 
@@ -381,6 +440,10 @@ const NewDynamic: React.FC<Props> = ({ value, visible, onClose, onChange, creati
                     actionButtonShow: true,
                     actionButton: actionButton[0]
                 }
+                if (isCardDynamic) {
+                    cardType.push('action_button')
+                    delete dynamicValues.actionButtonShow
+                }
             }
             // 数据外显
             if (showData && showData?.length > 0) {
@@ -390,6 +453,11 @@ const NewDynamic: React.FC<Props> = ({ value, visible, onClose, onChange, creati
                     showData: showData[0]
                 }
             }
+
+            if (cardType.length === 0 && isCardDynamic) {
+                cardType = ['not']
+            }
+            dynamicValues.cardType = cardType
             dynamicValues.creativeTemplateStyle = oldCreativeTemplateStyle === '视频' ? 'video' : 'image'
             form.setFieldsValue({ ...dynamicValues })
         }
@@ -453,9 +521,9 @@ const NewDynamic: React.FC<Props> = ({ value, visible, onClose, onChange, creati
 
                         {Object.keys(creativeComponents).length > 0 && <>
                             {/* 创意内容 */}
-                            <CreativeTemplateContent />
+                            <CreativeTemplateContent automaticSiteEnabled={automaticSiteEnabled}/>
                             {/* 营销组件 */}
-                            <CreativeConversionAssistant />
+                            <CreativeConversionAssistant automaticSiteEnabled={automaticSiteEnabled} />
                             {/* 创意设置 */}
                             <CreativeTemplateSetup />
                         </>}

+ 2 - 1
src/pages/launchSystemV3/tencentAdPutIn/create/PageList/index.tsx

@@ -14,7 +14,7 @@ const PageList: React.FC = () => {
 
     /********************************/
     const { addelivery, accountCreateLogs, setAccountCreateLogs, clearData } = useContext(DispatchAddelivery)!;
-    const { dynamic } = addelivery
+    const { dynamic, adgroups } = addelivery
 
     const [addVisible, setAddVisible] = useState<boolean>(false)
     /********************************/
@@ -41,6 +41,7 @@ const PageList: React.FC = () => {
 
         {addVisible && <PageModal
             data={accountCreateLogs}
+            adgroups={adgroups}
             visible={addVisible}
             onClose={() => {
                 setAddVisible(false)

+ 11 - 3
src/pages/launchSystemV3/tencentAdPutIn/create/Target/addTarget.tsx

@@ -44,6 +44,7 @@ const AddTarget: React.FC<Props> = ({ isBackVal, value, visible, onChange, onClo
     const [regionsList, setRegionsList] = useState<any[]>([])
     const [modelList, setModelList] = useState([])
     const [osList, setOsList] = useState<DefaultOptionType[]>([])
+    const [isAdd, setIsAdd] = useState<boolean>(false)
 
     const getTargetingGags = useAjax((params) => getTargetingGagsApi(params))
     const checkTargeting = useAjax((params) => checkTargetingApi(params))
@@ -234,7 +235,7 @@ const AddTarget: React.FC<Props> = ({ isBackVal, value, visible, onChange, onClo
             targeting: targetValues
         }
 
-        if (isBackVal) {
+        if (isBackVal && !isAdd) {
             delete targetingDTO.accountId
             delete targetingDTO.description
             onChange?.(targetingDTO)
@@ -255,7 +256,13 @@ const AddTarget: React.FC<Props> = ({ isBackVal, value, visible, onChange, onClo
         } else {
             addTargeting.run(targetingDTO).then(res => {
                 message.success('新增成功')
-                onChange?.()
+                if (isBackVal && isAdd) {
+                    delete targetingDTO.accountId
+                    delete targetingDTO.description
+                    onChange?.(targetingDTO)
+                } else {
+                    onChange?.()
+                }
             })
         }
     }
@@ -783,7 +790,7 @@ const AddTarget: React.FC<Props> = ({ isBackVal, value, visible, onChange, onClo
                         }
                     ]}
                 >
-                    <InputName placeholder='定向模板名称' disabled={isBackVal} style={{ width: 480 }} length={30} />
+                    <InputName placeholder='定向模板名称' style={{ width: 480 }} length={30} />
                 </Form.Item>
                 {!isBackVal && <>
                     <Form.Item
@@ -812,6 +819,7 @@ const AddTarget: React.FC<Props> = ({ isBackVal, value, visible, onChange, onClo
             </Card>
             <Form.Item className="submit_pull">
                 <Space>
+                    {isBackVal && !(value && Object.keys(value).length > 0) && <Checkbox checked={isAdd} onChange={(e) => setIsAdd(e.target.checked)}>是否保存到定向模板</Checkbox>}
                     <Button onClick={onClose}>取消</Button>
                     <Button type="primary" htmlType="submit" className="modalResetCss" loading={checkTargeting.loading || updateTargeting.loading || addTargeting.loading}>
                         确定

+ 2 - 0
src/pages/launchSystemV3/tencentAdPutIn/create/Target/index.tsx

@@ -63,6 +63,7 @@ const Target: React.FC = () => {
                         onClick={() => {
                             setModifyDta(undefined)
                             setAddTemVisible(true)
+                            setModifyLength(undefined)
                         }}
                         disabled={!(adgroups && Object.keys(adgroups)?.length > 0)}
                     >
@@ -108,6 +109,7 @@ const Target: React.FC = () => {
                 } else {
                     newTarget.push(newTargeting)
                 }
+                setModifyLength(undefined)
                 console.log('newTarget---->', newTarget)
                 setAddelivery({ ...addelivery, targeting: newTarget })
                 clearData()

+ 2 - 1
src/pages/launchSystemV3/tencentAdPutIn/create/Target/selectTarget.tsx

@@ -164,7 +164,7 @@ const SelectTarget: React.FC<Props> = ({ value = [], visible, onChange, onClose
                     </div>
                     <div className={style.template_right}>
                         <div className={`flexSpaceBetween ${style.header}`}>
-                            <Title level={5} style={{ marginBottom: 0 }}>已选:3</Title>
+                            <Title level={5} style={{ marginBottom: 0 }}>已选:{selectedTargetKeys?.length || 0}</Title>
                             <Button type="link" style={{ padding: 0, fontSize: 12, lineHeight: 'normal' }} onClick={() => setSelectedTargetKeys([])} icon={<UndoOutlined />}>清空</Button>
                         </div>
                         <div className={style.selectTarget}>
@@ -194,6 +194,7 @@ const SelectTarget: React.FC<Props> = ({ value = [], visible, onChange, onClose
             onChange={() => {
                 setAddTemVisible(false)
                 setModifyDta(undefined)
+                getTargetingList.refresh()
             }}
         />}
 

+ 8 - 2
src/pages/launchSystemV3/tencentAdPutIn/create/index.tsx

@@ -1,4 +1,4 @@
-import { Button, Card, Checkbox, Divider, Empty, Modal, Select, Space, Spin, Table, Tabs, Tag, Tooltip, message } from "antd"
+import { Button, Card, Checkbox, Divider, Empty, Modal, Popconfirm, Select, Space, Spin, Table, Tabs, Tag, Tooltip, message } from "antd"
 import React, { useEffect, useState } from "react"
 import style from './index.less'
 import '../index.less'
@@ -53,6 +53,7 @@ const Create: React.FC = () => {
     /*******************************************/
 
     useEffect(() => {
+        console.log('addelivery---->', addelivery)
         // 获取账户组
         getGroupList.run()
         // 获取账户列表
@@ -494,7 +495,12 @@ const Create: React.FC = () => {
                 </div>
                 <Space className={style.bts} wrap>
                     <Button type='primary' onClick={severBd}>存为预设</Button>
-                    <Button onClick={delBdPlan}>清空配置/预设</Button>
+                    <Popconfirm
+                        title="确定清空?"
+                        onConfirm={delBdPlan}
+                    >
+                        <Button>清空配置/预设</Button>
+                    </Popconfirm>
                     <Button type='primary' onClick={preview}><SearchOutlined />预览广告</Button>
                 </Space>
 

+ 2 - 1
src/pages/launchSystemV3/tencentAdPutIn/create/submitModal.tsx

@@ -1,6 +1,7 @@
 import { Form, Input, Modal } from "antd"
 import React, { useState } from "react"
 import moment from "moment"
+import { randomString } from "@/utils/utils"
 
 /**
  * 设置名称
@@ -17,7 +18,7 @@ const SubmitModal: React.FC<Props> = (props) => {
     /********************/
     const { visible, onClose, onChange, ajax } = props
     const [form] = Form.useForm()
-    const [initialValues] = useState<{ taskName: string }>({ taskName: '任务' + moment().format('MM_DD_HH_mm') })
+    const [initialValues] = useState<{ taskName: string }>({ taskName: '任务' + moment().format('MM_DD_HH_mm_ss') + '_' + randomString(true, 3, 5) })
 
     const handleOk = async () => {
         form.submit()

+ 5 - 5
src/pages/launchSystemV3/tencentAdPutIn/index.less

@@ -77,11 +77,11 @@
     }
 }
 
-.ant-radio-button-wrapper {
-    height: 28px;
-    line-height: 28px;
-    padding: 0 6px;
-}
+// .ant-radio-button-wrapper {
+//     height: 28px;
+//     line-height: 28px;
+//     padding: 0 6px;
+// }
 
 .ant-radio-button-wrapper:first-child {
     border-radius: 6px 0 0 6px !important;

+ 63 - 0
src/pages/launchSystemV3/tencentAdPutIn/taskList/dynamicLog.tsx

@@ -0,0 +1,63 @@
+import { useAjax } from "@/Hook/useAjax"
+import { getDynamicListApi } from "@/services/adqV3"
+import { Button, Card, Space, Table, Tag, Typography } from "antd"
+import React, { useEffect, useState } from "react"
+import '../index.less'
+import { columnsDynamicLog } from "./tableConfig"
+const { Title } = Typography;
+
+
+interface Props {
+    record: any
+}
+/**
+ * 创意日志
+ * @returns 
+ */
+const DynamicLog: React.FC<Props> = ({ record }) => {
+
+    /****************************************/
+    const [queryForm, setQueryForm] = useState<PULLIN.GetDynamicV3LogProps>({ pageNum: 1, pageSize: 20 })
+    const getDynamicList = useAjax((params) => getDynamicListApi(params), { formatResult: true })
+    /****************************************/
+
+    useEffect(() => {
+        if (record?.id) {
+            getDynamicList.run({ ...queryForm, adgroupCreateLogId: record?.id })
+        }
+    }, [record?.id, queryForm])
+
+    return <Card
+        hoverable
+        className="cardResetCss"
+    >
+        <Title level={5}>
+            <span>{record?.adgroupName + ' 创意日志'} </span>
+            <Button type="link" onClick={() => getDynamicList.refresh()}>刷新</Button>
+        </Title>
+        <Table
+            columns={columnsDynamicLog()}
+            dataSource={getDynamicList?.data?.data?.records}
+            size="small"
+            loading={getDynamicList?.loading}
+            scroll={{ y: 300 }}
+            bordered
+            rowKey={'dynamicCreativeId'}
+            pagination={{
+                pageSize: queryForm.pageSize,
+                current: queryForm.pageNum,
+                total: getDynamicList?.data?.data?.total || 0,
+                showTotal: (total) => <Tag color="cyan">总共{total}数据</Tag>
+            }}
+            onChange={(pagination) => {
+                let { current, pageSize } = pagination
+                let newQueryForm = JSON.parse(JSON.stringify(queryForm))
+                newQueryForm.pageNum = current
+                newQueryForm.pageSize = pageSize
+                setQueryForm(newQueryForm)
+            }}
+        />
+    </Card>
+}
+
+export default React.memo(DynamicLog)

+ 4 - 3
src/pages/launchSystemV3/tencentAdPutIn/taskList/index.tsx

@@ -1,4 +1,4 @@
-import { Button, Card, DatePicker, Input, Table } from "antd"
+import { Button, Card, DatePicker, Input, Table, Tag } from "antd"
 import React, { useEffect, useState } from "react"
 import '../index.less'
 import { SearchOutlined } from "@ant-design/icons"
@@ -65,13 +65,14 @@ const TaskList: React.FC = () => {
             dataSource={getTaskV3List?.data?.data?.records}
             size="small"
             loading={getTaskV3List?.loading}
-            scroll={{ y: 500 }}
+            scroll={{ y: 600 }}
             bordered
             rowKey={'id'}
             pagination={{
                 pageSize: queryParamsNew.pageSize,
                 current: queryParamsNew.pageNum,
-                total: getTaskV3List?.data?.data?.total || 0
+                total: getTaskV3List?.data?.data?.total || 0,
+                showTotal: (total) => <Tag color="cyan">总共{total}数据</Tag>
             }}
             onChange={(pagination) => {
                 let { current, pageSize } = pagination

+ 19 - 4
src/pages/launchSystemV3/tencentAdPutIn/taskList/log.tsx

@@ -1,8 +1,9 @@
 import { useAjax } from "@/Hook/useAjax"
 import { getTaskV3LogListApi } from "@/services/adqV3"
-import { Drawer, Table } from "antd"
+import { Button, Drawer, Space, Table, Tag } from "antd"
 import React, { useEffect, useState } from "react"
 import { columnsLog } from "./tableConfig"
+import DynamicLog from "./dynamicLog"
 
 interface Props {
     data: any
@@ -35,19 +36,30 @@ const Log: React.FC<Props> = (props) => {
         }
     }
 
-    return <Drawer bodyStyle={{ padding: 0 }} title={taskName + ' 日志'} width={1400} placement="right" onClose={() => { onClose && onClose() }} visible={visible}>
+    return <Drawer
+        bodyStyle={{ padding: 0 }}
+        title={<Space>
+            <span>{taskName + ' 日志'}</span>
+            <Button type="link" onClick={() => getTaskV3LogList.refresh()}>刷新</Button>
+        </Space>}
+        width={1400}
+        placement="right"
+        onClose={() => { onClose && onClose() }}
+        visible={visible}
+    >
         <Table
             columns={columnsLog()}
             dataSource={getTaskV3LogList?.data?.data?.records}
             size="small"
             loading={getTaskV3LogList?.loading}
-            scroll={{ y: 500 }}
+            scroll={{ y: 600 }}
             bordered
             rowKey={'id'}
             pagination={{
                 pageSize: queryForm.pageSize,
                 current: queryForm.pageNum,
-                total: getTaskV3LogList?.data?.data?.total || 0
+                total: getTaskV3LogList?.data?.data?.total || 0,
+                showTotal: (total) => <Tag color="cyan">总共{total}数据</Tag>
             }}
             onChange={(pagination) => {
                 let { current, pageSize } = pagination
@@ -56,6 +68,9 @@ const Log: React.FC<Props> = (props) => {
                 newQueryForm.pageSize = pageSize
                 setQueryForm(newQueryForm)
             }}
+            expandable={{
+                expandedRowRender: record => <DynamicLog record={record} />
+            }}
         />
     </Drawer>
 }

+ 178 - 20
src/pages/launchSystemV3/tencentAdPutIn/taskList/tableConfig.tsx

@@ -1,10 +1,11 @@
 import React from "react"
 import { Badge, Popover, Space, TableProps, Typography } from "antd"
-import { AD_STATUS_ENUM, MARKETING_GOAL_ENUM } from "../const"
+import { AD_STATUS_ENUM, DELIVERY_MODE_ENUM, DYNAMIC_CREATIVE_TYPE_ENUM, MARKETING_GOAL_ENUM } from "../const"
 import TargetingTooltip from "../../components/TargetingTooltip"
 import { QuestionCircleFilled } from "@ant-design/icons"
 import AdgroupTooltip from "../../components/AdgroupTooltip"
 import DynamicTooltip from "../../components/DynamicTooltip"
+import { copy } from "@/utils/utils"
 
 
 const columns = (geoLocationList: any, modelList: any, callback: (data: any, type: 'log' | 'page' | 'copy', allData?: any) => void): TableProps<any>['columns'] => {
@@ -16,6 +17,7 @@ const columns = (geoLocationList: any, modelList: any, callback: (data: any, typ
             key: 'cz',
             width: 80,
             align: 'center',
+            fixed: 'left',
             render: (_, records) => {
                 return <Space>
                     <a style={{ color: '#1890ff', fontSize: 12 }} onClick={() => { callback(records, 'log', records) }}>日志</a>
@@ -23,20 +25,37 @@ const columns = (geoLocationList: any, modelList: any, callback: (data: any, typ
                 </Space>
             }
         },
+        {
+            title: '任务状态',
+            dataIndex: 'status',
+            key: 'status',
+            width: 78,
+            fixed: 'left',
+            render(value) {
+                return { 0: <Badge status="processing" text={<span style={{ fontSize: 12 }} >执行中</span>} />, 1: <Badge style={{ fontSize: 12 }} status="error" text={<span style={{ fontSize: 12 }} >全部失败</span>} />, 2: <Badge style={{ fontSize: 12 }} status="warning" text={<span style={{ fontSize: 12 }} >部分成功</span>} />, 100: <Badge style={{ fontSize: 12 }} status="success" text={<span style={{ fontSize: 12 }} >全部成功</span>} /> }[value]
+            },
+        },
         {
             title: '任务名称',
             dataIndex: 'taskName',
             key: 'taskName',
-            align: 'center',
             width: 120,
-            ellipsis: true
+            ellipsis: true,
+            fixed: 'left',
+            render(value) {
+                return <span style={{ fontSize: 12 }}>{value}</span>
+            }
         },
         {
             title: 'ID',
             dataIndex: 'id',
             key: 'id',
             align: 'center',
-            width: 50,
+            width: 60,
+            ellipsis: true,
+            render(value) {
+                return <span style={{ fontSize: 12 }}>{value}</span>
+            }
         },
         {
             title: '广告状态',
@@ -61,7 +80,7 @@ const columns = (geoLocationList: any, modelList: any, callback: (data: any, typ
             ellipsis: true,
             render(value) {
                 return <div style={{ width: '100%', display: 'flex', alignItems: 'center' }}>
-                    <div style={{ width: 'calc(100% - 20px)' }}><Typography.Text ellipsis={{ tooltip: true }}>{value?.adgroupName}</Typography.Text></div>
+                    <div style={{ width: 'calc(100% - 20px)' }}><Typography.Text style={{ fontSize: 12 }} ellipsis={{ tooltip: true }}>{value?.adgroupName}</Typography.Text></div>
                     <Popover
                         placement="right"
                         overlayInnerStyle={{ maxWidth: 350, maxHeight: 350, overflow: 'hidden', overflowY: 'auto' }}
@@ -70,7 +89,7 @@ const columns = (geoLocationList: any, modelList: any, callback: (data: any, typ
                             data={value}
                         />}
                     >
-                        <QuestionCircleFilled />
+                        <QuestionCircleFilled style={{ fontSize: 12 }} />
                     </Popover>
                 </div>
             }
@@ -93,7 +112,7 @@ const columns = (geoLocationList: any, modelList: any, callback: (data: any, typ
                             modelList={modelList}
                         />}
                     >
-                        <div style={{ width: 80, cursor: 'help' }}><Typography.Text ellipsis>{index + 1}、{item?.targetingName || '--'}</Typography.Text></div>
+                        <div style={{ width: 80, cursor: 'help' }}><Typography.Text style={{ fontSize: 12 }} ellipsis>{index + 1}、{item?.targetingName || '--'}</Typography.Text></div>
                     </Popover>)}
                 </div>
             }
@@ -106,7 +125,7 @@ const columns = (geoLocationList: any, modelList: any, callback: (data: any, typ
             ellipsis: true,
             render(value) {
                 return <div style={{ width: '100%', display: 'flex', alignItems: 'center' }}>
-                    <div style={{ width: 'calc(100% - 20px)' }}><Typography.Text ellipsis={{ tooltip: true }}>{value?.dynamicCreativeName}</Typography.Text></div>
+                    <div style={{ width: 'calc(100% - 20px)' }}><Typography.Text style={{ fontSize: 12 }} ellipsis={{ tooltip: true }}>{value?.dynamicCreativeName}</Typography.Text></div>
                     <Popover
                         placement="right"
                         overlayInnerStyle={{ maxWidth: 350, maxHeight: 350, overflow: 'hidden', overflowY: 'auto' }}
@@ -115,7 +134,7 @@ const columns = (geoLocationList: any, modelList: any, callback: (data: any, typ
                             data={value}
                         />}
                     >
-                        <QuestionCircleFilled />
+                        <QuestionCircleFilled style={{ fontSize: 12 }} />
                     </Popover>
                 </div>
             }
@@ -134,17 +153,21 @@ const columns = (geoLocationList: any, modelList: any, callback: (data: any, typ
             title: <span style={{ marginLeft: 10 }}>任务反馈</span>,
             dataIndex: 'total',
             key: 'total',
+            width: 480,
             render: (value, records) => {
-                return <Space style={{ fontSize: "12px", marginLeft: 10 }} size={20}>
-                    <span><Badge status="processing" />总条数:{value}条</span>
-                    {<span><Badge status="success" />成功数:{records?.successCount || 0}条</span>}
-                    {/* {errCount ? <span><Badge status="error" />创建中:{errCount}条</span> : null} */}
+                return <Space style={{ fontSize: "12px", marginLeft: 10 }} size={10}>
+                    <span style={{ fontSize: 12 }}><Badge status="processing" />广告总数:<span style={{ fontWeight: 'bold', color: '#1890ff' }}>{value}</span>条</span>
+                    {<span style={{ fontSize: 12, fontWeight: 'bold' }}><Badge status="success" />广告成功数:<span style={{ fontWeight: 'bold', color: '#52c41a' }}>{records?.successCount || 0}</span>条</span>}
+                    <span style={{ fontSize: 12, fontWeight: 'bold' }}><Badge status="processing" />创意总数:<span style={{ fontWeight: 'bold', color: '#1890ff' }}>{records?.dynamicCreativeCount || 0}</span>条</span>
+                    {<span style={{ fontSize: 12, fontWeight: 'bold' }}><Badge status="success" />创意成功数:<span style={{ fontWeight: 'bold', color: '#52c41a' }}>{records?.dynamicCreativeSuccessCount || 0}</span>条</span>}
                 </Space>
             }
         }
     ]
 }
 
+export default columns
+
 export const columnsLog = (): TableProps<any>['columns'] => {
     return [
         {
@@ -153,21 +176,30 @@ export const columnsLog = (): TableProps<any>['columns'] => {
             key: 'accountId',
             width: 100,
             ellipsis: true,
-            align: 'center'
+            align: 'center',
+            render(value) {
+                return <span style={{ fontSize: 12 }}>{value}</span>
+            }
         },
         {
             title: '广告名称',
             dataIndex: 'adgroupName',
             key: 'adgroupName',
             width: 160,
-            ellipsis: true
+            ellipsis: true,
+            render(value) {
+                return <span style={{ fontSize: 12 }}>{value}</span>
+            }
         },
         {
             title: '定向名称',
             dataIndex: 'targetingsName',
             key: 'targetingsName',
             width: 150,
-            ellipsis: true
+            ellipsis: true,
+            render(value) {
+                return <span style={{ fontSize: 12 }}>{value}</span>
+            }
         },
         {
             title: '营销目的',
@@ -177,7 +209,7 @@ export const columnsLog = (): TableProps<any>['columns'] => {
             ellipsis: true,
             align: 'center',
             render(value) {
-                return MARKETING_GOAL_ENUM[value]
+                return <span style={{ fontSize: 12 }}>{MARKETING_GOAL_ENUM[value]}</span>
             },
         },
         {
@@ -185,16 +217,142 @@ export const columnsLog = (): TableProps<any>['columns'] => {
             dataIndex: 'bidAmount',
             key: 'bidAmount',
             width: 90,
-            align: 'center'
+            align: 'center',
+            render(value) {
+                return <span style={{ fontSize: 12 }}>{value}</span>
+            }
+        },
+        {
+            title: '广告创建状态',
+            dataIndex: 'adgroupStatus',
+            key: 'adgroupStatus',
+            width: 90,
+            align: 'center',
+            render(value) {
+                return { 0: <Badge status="processing" text={<span style={{ fontSize: 12 }}>执行中</span>} />, 1: <Badge status="error" style={{ fontSize: 12 }} text={<span>失败</span>} />, 100: <Badge style={{ fontSize: 12 }} status="success" text={<span>成功</span>} /> }[value]
+            },
+        },
+        {
+            title: <span style={{ marginLeft: 10 }}>任务反馈</span>,
+            dataIndex: 'dynamicCreativeCount',
+            key: 'dynamicCreativeCount',
+            width: 280,
+            render: (value, records) => {
+                return <Space style={{ fontSize: "12px", marginLeft: 10 }} size={10}>
+                    <span style={{ fontSize: 12, fontWeight: 'bold' }}><Badge status="processing" />创意总数:<span style={{ fontWeight: 'bold', color: '#1890ff' }}>{records?.dynamicCreativeCount || 0}</span>条</span>
+                    {<span style={{ fontSize: 12, fontWeight: 'bold' }}><Badge status="success" />创意成功数:<span style={{ fontWeight: 'bold', color: '#52c41a' }}>{records?.dynamicCreativeSuccessCount || 0}</span>条</span>}
+                </Space>
+            }
         },
         {
             title: '错误信息',
             dataIndex: 'failMsg',
             key: 'failMsg',
             width: 180,
-            ellipsis: true
+            ellipsis: true,
+            render(value) {
+                return <span style={{ fontSize: 12 }}>{value}</span>
+            }
         },
     ]
 }
 
-export default columns
+export const columnsDynamicLog = (): TableProps<any>['columns'] => {
+    return [
+        {
+            title: '创意名称',
+            dataIndex: 'dynamicCreativeName',
+            key: 'dynamicCreativeName',
+            width: 150,
+            ellipsis: true,
+            render(value) {
+                return <span style={{ fontSize: 12 }}>{value}</span>
+            }
+        },
+        {
+            title: '创意ID',
+            dataIndex: 'dynamicCreativeId',
+            key: 'dynamicCreativeId',
+            width: 80,
+            ellipsis: true,
+            align: 'center',
+            render(value) {
+                return <span style={{ fontSize: 12 }}>{value}</span>
+            }
+        },
+        {
+            title: '投放模式',
+            dataIndex: 'deliveryMode',
+            key: 'deliveryMode',
+            width: 80,
+            ellipsis: true,
+            align: 'center',
+            render(value) {
+                return <span style={{ fontSize: 12 }}>{DELIVERY_MODE_ENUM[value]}</span>
+            }
+        },
+        {
+            title: '动态创意类型',
+            dataIndex: 'dynamicCreativeType',
+            key: 'dynamicCreativeType',
+            width: 80,
+            ellipsis: true,
+            align: 'center',
+            render(value) {
+                return <span style={{ fontSize: 12 }}>{DYNAMIC_CREATIVE_TYPE_ENUM[value]}</span>
+            }
+        },
+        {
+            title: '任务ID',
+            dataIndex: 'taskId',
+            key: 'taskId',
+            width: 70,
+            ellipsis: true,
+            align: 'center',
+            render(value) {
+                return <span style={{ fontSize: 12 }}>{value}</span>
+            }
+        },
+        {
+            title: '广告组ID',
+            dataIndex: 'adgroupId',
+            key: 'adgroupId',
+            width: 80,
+            ellipsis: true,
+            align: 'center',
+            render(value) {
+                return <span style={{ fontSize: 12 }}>{value}</span>
+            }
+        },
+        {
+            title: '创意模板ID',
+            dataIndex: 'creativeTemplateId',
+            key: 'creativeTemplateId',
+            width: 75,
+            ellipsis: true,
+            align: 'center',
+            render(value) {
+                return <span style={{ fontSize: 12 }}>{value}</span>
+            }
+        },
+        {
+            title: '创意创建状态',
+            dataIndex: 'creativeStatus',
+            key: 'creativeStatus',
+            width: 80,
+            align: 'center',
+            render(value) {
+                return { 0: <Badge status="processing" text={<span style={{ fontSize: 12 }}>执行中</span>} />, 1: <Badge status="error" style={{ fontSize: 12 }} text={<span>失败</span>} />, 100: <Badge style={{ fontSize: 12 }} status="success" text={<span>成功</span>} /> }[value]
+            },
+        },
+        {
+            title: '失败信息',
+            dataIndex: 'failMsg',
+            key: 'failMsg',
+            width: 280,
+            render: (value) => {
+                return value ? <span style={{ fontSize: 12 }} onClick={() => copy(value)}>{value}</span> : '--'
+            }
+        }
+    ]
+}

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

@@ -105,4 +105,9 @@ declare namespace PULLIN {
         pageSize: number,
         taskId?: string
     }
+    interface GetDynamicV3LogProps {
+        pageNum: number,
+        pageSize: number,
+        adgroupCreateLogId?: string
+    }
 }

+ 37 - 0
src/services/adqV3/global.ts

@@ -233,4 +233,41 @@ export async function delSysBrandApi(data: { sysBrandId: number }) {
     return request(api + `/adq/sysBrand/${sysBrandId}`, {
         method: 'DELETE'
     })
+}
+
+
+/**
+ * 新增头像昵称跳转页
+ * @param data 
+ * @returns 
+ */
+export async function addProfilesApi(data: { profileName: string, imageUrl: string, description: string }) {
+    return request(api + `/adq/v3/marketingAssets/profiles/add`, {
+        method: 'POST',
+        data
+    })
+}
+
+/**
+ * 获取头像昵称跳转页
+ * @param data 
+ * @returns 
+ */
+export async function getProfilesApi(data: { profileName?: string }) {
+    return request(api + `/adq/v3/marketingAssets/profiles/get`, {
+        method: 'POST',
+        data
+    })
+}
+
+/**
+ * 删除头像昵称跳转页
+ * @param data 
+ * @returns 
+ */
+export async function delProfilesApi(params: { id: number }) {
+    return request(api + `/adq/v3/marketingAssets/deleteSysProfiles`, {
+        method: 'DELETE',
+        params
+    })
 }

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

@@ -110,4 +110,16 @@ export async function getTaskV3LogListApi(data: PULLIN.GetTaskV3LogProps) {
         method: 'POST',
         data
     })
+}
+
+/**
+ * 查询创意创建日志
+ * @param data 
+ * @returns 
+ */
+export async function getDynamicListApi(data: PULLIN.GetDynamicV3LogProps) {
+    return request(api + `/adq/v3/adgroup/selectCreativesCreateLog`, {
+        method: 'POST',
+        data
+    })
 }

+ 2 - 2
src/services/api.ts

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

+ 25 - 0
src/utils/utils.ts

@@ -347,4 +347,29 @@ export const processData = (data: string | any[]) => {
  */
 export function cartesianProduct<T, U>(arr1: T[], arr2: U[]): [T, U, string][] {
   return arr1.flatMap((d1, index1) => arr2.map((d2, index2) => [d1, d2, `${index1 + 1}_${index2 + 1}`] as [T, U, string]));
+}
+
+/**
+ * 对比2个数组是否相同,不考虑下表
+ * @param arr1 
+ * @param arr2 
+ * @returns 
+ */
+export const arraysHaveSameValues = (arr1: any[], arr2: any[]): boolean => {
+  // 首先检查数组的长度是否相同
+  if (arr1.length !== arr2.length) {
+    return false;
+  }
+
+  // 使用数组的 sort 方法对两个数组进行排序,然后逐个比较
+  const sortedArr1 = [...arr1].sort();
+  const sortedArr2 = [...arr2].sort();
+
+  for (let i = 0; i < sortedArr1.length; i++) {
+    if (sortedArr1[i] !== sortedArr2[i]) {
+      return false;
+    }
+  }
+
+  return true;
 }