Browse Source

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

shenwu 2 years ago
parent
commit
71196c64a5
100 changed files with 7246 additions and 8101 deletions
  1. 2 2
      config/config.prod.ts
  2. 1 1
      config/proxy.ts
  3. 9 2
      src/components/FileBoxAD/components/imgModal/index.tsx
  4. 111 108
      src/components/FileBoxAD/index.tsx
  5. 4 1
      src/components/Tables/index.tsx
  6. 6 1
      src/global.less
  7. 564 392
      src/models/useLaunchAdq/useBdMediaPup.ts
  8. 1 1
      src/pages/launchSystem/launchManage/components/authLogin/index.tsx
  9. 1 1
      src/pages/launchSystem/launchManage/weChat/components/createPlan/components/AdOriginality/components/ClerkAide/index.tsx
  10. 1 1
      src/pages/launchSystem/launchManageNew/weChatNew/components/createPlan/components/AdOriginality/components/ClerkAide/index.tsx
  11. 1 1
      src/pages/launchSystem/materialManage/adMaterial/components/addCom/index.tsx
  12. 1 1
      src/pages/launchSystem/materialManage/adMaterial/index.tsx
  13. 1 1
      src/pages/launchSystem/materialManage/adOriginality/components/addOriginality/index.tsx
  14. 1 1
      src/pages/launchSystem/materialManage/adOriginality/index.tsx
  15. 1 1
      src/pages/launchSystem/materialManage/adTitle/components/addTitle/index.tsx
  16. 1 1
      src/pages/launchSystem/materialManage/adTitle/index.tsx
  17. 1 1
      src/pages/launchSystem/materialManage/tagManage/index.tsx
  18. 1 1
      src/pages/launchSystem/materialManageBd/adMaterial/components/addCom/index.tsx
  19. 1 1
      src/pages/launchSystem/materialManageBd/adMaterial/index.tsx
  20. 1 1
      src/pages/launchSystem/materialManageBd/adOriginality/components/addOriginality/index.tsx
  21. 1 1
      src/pages/launchSystem/materialManageBd/adOriginality/index.tsx
  22. 1 1
      src/pages/launchSystem/materialManageBd/adTitle/components/addTitle/index.tsx
  23. 1 1
      src/pages/launchSystem/materialManageBd/adTitle/index.tsx
  24. 1 1
      src/pages/launchSystem/materialManageBd/tagManage/index.tsx
  25. 27 3
      src/pages/launchSystemNew/adq/ad/index.tsx
  26. 12 0
      src/pages/launchSystemNew/adq/ad/tableConfig.tsx
  27. 0 1
      src/pages/launchSystemNew/adq/adAccount/index.tsx
  28. 1 1
      src/pages/launchSystemNew/adq/adAccount/tableConfig.tsx
  29. 27 3
      src/pages/launchSystemNew/adq/campaign/index.tsx
  30. 27 3
      src/pages/launchSystemNew/adq/creative/index.tsx
  31. 11 4
      src/pages/launchSystemNew/adq/creative/tableConfig.tsx
  32. 43 14
      src/pages/launchSystemNew/adq/index.tsx
  33. 2 1
      src/pages/launchSystemNew/components/adModal/index.tsx
  34. 4 4
      src/pages/launchSystemNew/components/adPopover/index.tsx
  35. 4 3
      src/pages/launchSystemNew/components/adcreativePopover/index.tsx
  36. 144 0
      src/pages/launchSystemNew/components/addGroup/index.tsx
  37. 55 0
      src/pages/launchSystemNew/components/addGroup/tableConfigAdd.tsx
  38. 40 122
      src/pages/launchSystemNew/components/addLandingPage/content.ts
  39. 92 63
      src/pages/launchSystemNew/components/addLandingPage/index.tsx
  40. 4 4
      src/pages/launchSystemNew/components/addLandingPage/sortable.tsx
  41. 8 12
      src/pages/launchSystemNew/components/bathLauCopy/index.tsx
  42. 1 1
      src/pages/launchSystemNew/components/creativeModal/index.tsx
  43. 11 4
      src/pages/launchSystemNew/components/creativeModal/tableConfig.tsx
  44. 168 0
      src/pages/launchSystemNew/components/customerServiceModal/index.tsx
  45. 44 0
      src/pages/launchSystemNew/components/customerServiceModal/tableConfig.tsx
  46. 21 4
      src/pages/launchSystemNew/components/lookLanding/index.tsx
  47. 143 10
      src/pages/launchSystemNew/components/pageModal/index.tsx
  48. 2 2
      src/pages/launchSystemNew/components/pageModal/tableConfig.tsx
  49. 51 0
      src/pages/launchSystemNew/components/previewAd/index.tsx
  50. 32 0
      src/pages/launchSystemNew/components/previewOrigin/index.tsx
  51. 14 2
      src/pages/launchSystemNew/components/selectCloud/index.tsx
  52. 1 1
      src/pages/launchSystemNew/components/targetingModal/index.tsx
  53. 14 15
      src/pages/launchSystemNew/components/targetingTooltip/index.tsx
  54. 20 0
      src/pages/launchSystemNew/components/textAideInput/index.less
  55. 79 0
      src/pages/launchSystemNew/components/textAideInput/index.tsx
  56. 11 0
      src/pages/launchSystemNew/launchManage/adAuthorize/index.less
  57. 81 17
      src/pages/launchSystemNew/launchManage/adAuthorize/index.tsx
  58. 72 37
      src/pages/launchSystemNew/launchManage/adAuthorize/tableConfig.tsx
  59. 92 0
      src/pages/launchSystemNew/launchManage/createAd/ad/index.tsx
  60. 392 0
      src/pages/launchSystemNew/launchManage/createAd/ad/modal/leadAd.tsx
  61. 372 0
      src/pages/launchSystemNew/launchManage/createAd/ad/modal/wechat.tsx
  62. 44 32
      src/pages/launchSystemNew/launchManage/createAd/adcreativeCol.tsx
  63. 14 12
      src/pages/launchSystemNew/launchManage/createAd/adgroupsCol.tsx
  64. 122 0
      src/pages/launchSystemNew/launchManage/createAd/creative/index.tsx
  65. 196 0
      src/pages/launchSystemNew/launchManage/createAd/creative/modal/brandImage.tsx
  66. 80 0
      src/pages/launchSystemNew/launchManage/createAd/creative/modal/config.ts
  67. 150 0
      src/pages/launchSystemNew/launchManage/createAd/creative/modal/headNickJump.tsx
  68. 93 0
      src/pages/launchSystemNew/launchManage/createAd/creative/modal/index.less
  69. 1103 0
      src/pages/launchSystemNew/launchManage/createAd/creative/modal/index.tsx
  70. 152 0
      src/pages/launchSystemNew/launchManage/createAd/creative/modal/tableConfig.tsx
  71. 11 2
      src/pages/launchSystemNew/launchManage/createAd/index.less
  72. 360 260
      src/pages/launchSystemNew/launchManage/createAd/index.tsx
  73. 19 66
      src/pages/launchSystemNew/launchManage/createAd/submitModal.tsx
  74. 145 0
      src/pages/launchSystemNew/launchManage/createAd/targeting/index.tsx
  75. 647 0
      src/pages/launchSystemNew/launchManage/createAd/targeting/modal/index.tsx
  76. 2 2
      src/pages/launchSystemNew/launchManage/localAd/ad/index.tsx
  77. 1 1
      src/pages/launchSystemNew/launchManage/localAd/ad/modal.tsx
  78. 1 6587
      src/pages/launchSystemNew/launchManage/localAd/adenum.ts
  79. 5 0
      src/pages/launchSystemNew/launchManage/localAd/brand/index.tsx
  80. 2 2
      src/pages/launchSystemNew/launchManage/localAd/creative/index.tsx
  81. 1 2
      src/pages/launchSystemNew/launchManage/localAd/creative/modal.tsx
  82. 2 2
      src/pages/launchSystemNew/launchManage/localAd/targeting/index.tsx
  83. 0 1
      src/pages/launchSystemNew/launchManage/localAd/targeting/modal.tsx
  84. 99 0
      src/pages/launchSystemNew/launchManage/taskList/batchCreativeCopy.tsx
  85. 371 0
      src/pages/launchSystemNew/launchManage/taskList/creativeForm.tsx
  86. 151 0
      src/pages/launchSystemNew/launchManage/taskList/index.less
  87. 7 16
      src/pages/launchSystemNew/launchManage/taskList/index.tsx
  88. 56 5
      src/pages/launchSystemNew/launchManage/taskList/log.tsx
  89. 154 20
      src/pages/launchSystemNew/launchManage/taskList/logTableConfig.tsx
  90. 27 42
      src/pages/launchSystemNew/launchManage/taskList/tableConfig.tsx
  91. 12 28
      src/pages/launchSystemNew/req.ts
  92. 1 20
      src/pages/user/login/components/bg.tsx
  93. 42 8
      src/pages/user/login/index.tsx
  94. 2 2
      src/services/api.ts
  95. 9 0
      src/services/launchAdq/adAuthorize.ts
  96. 81 51
      src/services/launchAdq/createAd.ts
  97. 61 53
      src/services/launchAdq/enum.ts
  98. 172 26
      src/services/launchAdq/global.ts
  99. 1 0
      src/services/launchAdq/material.ts
  100. 14 6
      src/services/login.ts

+ 2 - 2
config/config.prod.ts

@@ -4,6 +4,8 @@ const assetDir = "static"
 export default defineConfig({
   history: { type: 'hash' }, // 默认是 browse
   // devtool: 'source-map',//正式坏境查看报错使用,假如正式版稳定请关闭
+   // map关闭
+   devtool: false,
   //新增
   nodeModulesTransform: {
     type: 'none',
@@ -116,8 +118,6 @@ export default defineConfig({
       drop_console: true,
     },
   },
-  // map关闭
-  devtool: false,
   //替换压缩器为 esbuild
   esbuild: {},
   // 不打包组件使用cdn

+ 1 - 1
config/proxy.ts

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

+ 9 - 2
src/components/FileBoxAD/components/imgModal/index.tsx

@@ -31,8 +31,12 @@ let ImgModal = React.memo((props: { isAll?: boolean }) => {
     }
 
     const getVideo = useMemo(() => {
-        if (queryForm?.file) {
-            return <video src={URL.createObjectURL(queryForm?.file)} style={{ width: '100%' }} controls />
+        if (mediaType === 'VIDEO') {
+            if (queryForm?.file) {
+                return <video src={URL.createObjectURL(queryForm?.file)} style={{ width: '100%' }} controls />
+            } else {
+                return null
+            }
         } else {
             return null
         }
@@ -88,6 +92,9 @@ let ImgModal = React.memo((props: { isAll?: boolean }) => {
                                 setPreviewVisible(true)
                                 setFileUrl(file.thumbUrl)
                             }}
+                            onRemove={() => {
+                                setQueryForm({ ...queryForm, file: null })
+                            }}
                         >
                             {fileList?.length < 1 && '普通上传'}
                         </Upload>

+ 111 - 108
src/components/FileBoxAD/index.tsx

@@ -193,7 +193,7 @@ function FlieBox(props: Props) {
             <div className={style.files} onContextMenu={rightMenu} style={height ? { height } : {}}>
                 {/* 关联公众号筛选 */}
                 <div className={style.wxSelect}>
-                    
+
                 </div>
                 {/* 层级路径 */}
                 <div className={style.path} >
@@ -215,120 +215,122 @@ function FlieBox(props: Props) {
                     }
                 </div>
                 {/* 内容 */}
-                <div className={style.file_content} >
-                    {
-                        listData?.records?.map((item: Item) => {
-                            if (item.folder) {
-                                {/* 文件夹模板 */ }
-                                return <Popconfirm
-                                    title="确定要删除吗?"
-                                    onConfirm={() => { dels(item) }}
-                                    okText="是"
-                                    cancelText="否"
-                                    onCancel={delPupOff}
-                                    visible={delPupId === item.id}
-                                    key={item.id}
-                                >
-                                    <Spin tip='正在请求素材详情,请耐心等待...' spinning={get?.loading}>
-                                        <div
-                                            className={`${style.flex_box} ${selectFile?.some((id: number) => id === item.id) ? style.action : ''}`}
-                                            onContextMenu={(e) => { rightMenu(e, item) }}
-                                            onClick={(e) => { changeClickFile(e, item, isAll, noFile) }}
-                                            onDragStart={(e: any) => {
-                                                e.preventDefault()
-                                            }}
-                                        >
-                                            {/* {isAll && <span className={`${style.select}`} onClick={(e) => { changeClickFile(e, item, isAll, noFile) }}>
+                <Spin spinning={list.loading} style={{ width: '100%' }}>
+                    <div className={style.file_content}>
+                        {
+                            listData?.records?.map((item: Item) => {
+                                if (item.folder) {
+                                    {/* 文件夹模板 */ }
+                                    return <Popconfirm
+                                        title="确定要删除吗?"
+                                        onConfirm={() => { dels(item) }}
+                                        okText="是"
+                                        cancelText="否"
+                                        onCancel={delPupOff}
+                                        visible={delPupId === item.id}
+                                        key={item.id}
+                                    >
+                                        <Spin tip='正在请求素材详情,请耐心等待...' spinning={get?.loading}>
+                                            <div
+                                                className={`${style.flex_box} ${selectFile?.some((id: number) => id === item.id) ? style.action : ''}`}
+                                                onContextMenu={(e) => { rightMenu(e, item) }}
+                                                onClick={(e) => { changeClickFile(e, item, isAll, noFile) }}
+                                                onDragStart={(e: any) => {
+                                                    e.preventDefault()
+                                                }}
+                                            >
+                                                {/* {isAll && <span className={`${style.select}`} onClick={(e) => { changeClickFile(e, item, isAll, noFile) }}>
                                                 <span role="img" aria-label="check" style={{ color: '#fff' }}><svg viewBox="64 64 896 896" focusable="false" data-icon="check" width="1em" height="1em" fill="currentColor" aria-hidden="true"><path d="M912 190h-69.9c-9.8 0-19.1 4.5-25.1 12.2L404.7 724.5 207 474a32 32 0 00-25.1-12.2H112c-6.7 0-10.4 7.7-6.3 12.9l273.9 347c12.8 16.2 37.4 16.2 50.3 0l488.4-618.9c4.1-5.1.4-12.8-6.3-12.8z"></path></svg></span>
                                             </span>} */}
-                                            <img src={fileImg}
-                                                className={style.flex_box_img}
-                                                onClick={(e: any) => { e.stopPropagation(); fileClick(item) }}
-                                                onDragOver={(ev) => {
-                                                    ev.preventDefault()
-                                                }}
-                                                onDrop={() => {
-                                                    if (item.id !== folderId) {
-                                                        setActionId(item.id)
-                                                    }
-                                                }}
-                                            />
-                                            <span className={style.flex_box_name} >{item?.title}</span>
-                                            <span className={style.flex_box_id} onClick={(e) => { copyId(e, item?.number) }} >{item?.number}</span>
-                                        </div>
-                                    </Spin>
-                                </Popconfirm>
-                            } else {
-                                {/* 图片模板 ,视频模板,音频模板*/ }
-                                let topPageElements: any
-                                let topName: string = ""
-                                if (mediaType === 'PAGE' && item?.pageSpecsList) {
-                                    topPageElements = item?.pageSpecsList[0]?.pageElementsSpecList[0]
-                                }
-                                let El = null
-                                if (mediaType === 'IMG') {
-                                    El = <Image src={item.url} onClick={(e) => { e.stopPropagation() }} />
-                                } else if (mediaType === 'VIDEO') {
-                                    El = <video src={item.url} style={{ width: 130, height: 100 }} controls />
-                                } else if (mediaType === 'PAGE') {
-                                    switch (topPageElements?.elementType) {
-                                        case 'TOP_IMAGE':
-                                            topName = "顶部图片"
-                                            El = <Image src={topPageElements?.topImageSpec?.imageUrl} preview={{ visible: false }} onClick={(e) => { e.stopPropagation(); setPage && setPage(1, item.id) }} />
-                                            break
-                                        case 'TOP_SLIDER':
-                                            topName = "顶部轮播图"
-                                            El = <>
-                                                <Carousel autoplay style={{ width: 150, textAlign: 'center' }}>
-                                                    {topPageElements?.topSliderSpec?.imageUrlList?.map((url: string, index: number) => <div key={index}>
-                                                        <Image preview={{ visible: false }} src={url} onClick={(e) => { e.stopPropagation(); /*setImgVisible(true)*/ setPage && setPage(1, item.id) }} />
-                                                    </div>)}
-                                                </Carousel>
-                                                {/* <div style={{ display: 'none' }}>
+                                                <img src={fileImg}
+                                                    className={style.flex_box_img}
+                                                    onClick={(e: any) => { e.stopPropagation(); fileClick(item) }}
+                                                    onDragOver={(ev) => {
+                                                        ev.preventDefault()
+                                                    }}
+                                                    onDrop={() => {
+                                                        if (item.id !== folderId) {
+                                                            setActionId(item.id)
+                                                        }
+                                                    }}
+                                                />
+                                                <span className={style.flex_box_name} >{item?.title}</span>
+                                                <span className={style.flex_box_id} onClick={(e) => { copyId(e, item?.number) }} >{item?.number}</span>
+                                            </div>
+                                        </Spin>
+                                    </Popconfirm>
+                                } else {
+                                    {/* 图片模板 ,视频模板,音频模板*/ }
+                                    let topPageElements: any
+                                    let topName: string = ""
+                                    if (mediaType === 'PAGE' && item?.pageSpecsList) {
+                                        topPageElements = item?.pageSpecsList[0]?.pageElementsSpecList[0]
+                                    }
+                                    let El = null
+                                    if (mediaType === 'IMG') {
+                                        El = <Image src={item.url} onClick={(e) => { e.stopPropagation() }} />
+                                    } else if (mediaType === 'VIDEO') {
+                                        El = <video src={item.url} style={{ width: 130, height: 100 }} controls />
+                                    } else if (mediaType === 'PAGE') {
+                                        switch (topPageElements?.elementType) {
+                                            case 'TOP_IMAGE':
+                                                topName = "顶部图片"
+                                                El = <Image src={topPageElements?.topImageSpec?.imageUrl} preview={{ visible: false }} onClick={(e) => { e.stopPropagation(); setPage && setPage(1, item.id) }} />
+                                                break
+                                            case 'TOP_SLIDER':
+                                                topName = "顶部轮播图"
+                                                El = <>
+                                                    <Carousel autoplay style={{ width: 150, textAlign: 'center' }}>
+                                                        {topPageElements?.topSliderSpec?.imageUrlList?.map((url: string, index: number) => <div key={index}>
+                                                            <Image preview={{ visible: false }} src={url} onClick={(e) => { e.stopPropagation(); /*setImgVisible(true)*/ setPage && setPage(1, item.id) }} />
+                                                        </div>)}
+                                                    </Carousel>
+                                                    {/* <div style={{ display: 'none' }}>
                                                     <Image.PreviewGroup preview={{ visible: imgVisible, onVisibleChange: vis => setImgVisible(vis) }}>
                                                         {topPageElements?.topSliderSpec?.imageUrlList?.map((item: string, index: number) => <Image src={item} key={index} />)}
                                                     </Image.PreviewGroup>
                                                 </div> */}
-                                            </>
-                                            break
-                                        case 'TOP_VIDEO':
-                                            topName = "顶部视频"
-                                            El = <div className={style.pageVideo}>
-                                                <span className={style.pagePreview} onClick={(e) => { e.stopPropagation(); setPage && setPage(1, item.id) }}><EyeOutlined /> 预览</span>
-                                                <video src={topPageElements?.topVideoSpec?.videoUrl} style={{ width: 130, height: 100 }} controls />
-                                            </div>
-                                            break
+                                                </>
+                                                break
+                                            case 'TOP_VIDEO':
+                                                topName = "顶部视频"
+                                                El = <div className={style.pageVideo}>
+                                                    <span className={style.pagePreview} onClick={(e) => { e.stopPropagation(); setPage && setPage(1, item.id) }}><EyeOutlined /> 预览</span>
+                                                    <video src={topPageElements?.topVideoSpec?.videoUrl} style={{ width: 130, height: 100 }} controls />
+                                                </div>
+                                                break
+                                        }
                                     }
+                                    return <Popconfirm
+                                        title="确定要删除吗?"
+                                        onConfirm={() => { dels(item.id) }}
+                                        okText="是"
+                                        cancelText="否"
+                                        onCancel={delPupOff}
+                                        visible={delPupId === item.id}
+                                        key={item.id}
+                                    >
+                                        <Spin tip='正在请求素材详情,请耐心等待...' spinning={get?.loading}>
+                                            <div
+                                                className={`${style.image_box} ${!isBack ? (selectFile?.some((id: number) => id === item.id) ? style.action : '') : (selectItem?.some((item1: { url: string }) => item1.url === item.url) ? style.action : '')}`}
+                                                onContextMenu={(e) => { rightMenu(e, item) }}
+                                                onClick={(e) => { changeClickFile(e, item, isAll) }}
+                                                {...moveConfig(item)}
+                                            >
+                                                <span className={`${style.select}`} onClick={(e) => { changeClickFile(e, item, isAll) }}>
+                                                    <span role="img" aria-label="check" style={{ color: '#fff' }}><svg viewBox="64 64 896 896" focusable="false" data-icon="check" width="1em" height="1em" fill="currentColor" aria-hidden="true"><path d="M912 190h-69.9c-9.8 0-19.1 4.5-25.1 12.2L404.7 724.5 207 474a32 32 0 00-25.1-12.2H112c-6.7 0-10.4 7.7-6.3 12.9l273.9 347c12.8 16.2 37.4 16.2 50.3 0l488.4-618.9c4.1-5.1.4-12.8-6.3-12.8z"></path></svg></span>
+                                                </span>
+                                                {El}
+                                                <span className={style.flex_box_name} onClick={(e) => { copyId(e, item?.videoTitle || item?.title) }}>{item?.videoTitle || item?.title}</span>
+                                                {mediaType === 'PAGE' ? <span>{topName}</span> : <span>{item?.width}*{item.height}</span>}
+                                            </div>
+                                        </Spin>
+                                    </Popconfirm>
                                 }
-                                return <Popconfirm
-                                    title="确定要删除吗?"
-                                    onConfirm={() => { dels(item.id) }}
-                                    okText="是"
-                                    cancelText="否"
-                                    onCancel={delPupOff}
-                                    visible={delPupId === item.id}
-                                    key={item.id}
-                                >
-                                    <Spin tip='正在请求素材详情,请耐心等待...' spinning={get?.loading}>
-                                        <div
-                                            className={`${style.image_box} ${!isBack ? (selectFile?.some((id: number) => id === item.id) ? style.action : '') : (selectItem?.some((item1: { url: string }) => item1.url === item.url) ? style.action : '')}`}
-                                            onContextMenu={(e) => { rightMenu(e, item) }}
-                                            onClick={(e) => { changeClickFile(e, item, isAll) }}
-                                            {...moveConfig(item)}
-                                        >
-                                            <span className={`${style.select}`} onClick={(e) => { changeClickFile(e, item, isAll) }}>
-                                                <span role="img" aria-label="check" style={{ color: '#fff' }}><svg viewBox="64 64 896 896" focusable="false" data-icon="check" width="1em" height="1em" fill="currentColor" aria-hidden="true"><path d="M912 190h-69.9c-9.8 0-19.1 4.5-25.1 12.2L404.7 724.5 207 474a32 32 0 00-25.1-12.2H112c-6.7 0-10.4 7.7-6.3 12.9l273.9 347c12.8 16.2 37.4 16.2 50.3 0l488.4-618.9c4.1-5.1.4-12.8-6.3-12.8z"></path></svg></span>
-                                            </span>
-                                            {El}
-                                            <span className={style.flex_box_name} onClick={(e) => { copyId(e, item?.videoTitle || item?.title) }}>{item?.videoTitle || item?.title}</span>
-                                            {mediaType === 'PAGE' ? <span>{topName}</span> : <span>{item?.width}*{item.height}</span>}
-                                        </div>
-                                    </Spin>
-                                </Popconfirm>
-                            }
-                        })
-                    }
-                </div>
+                            })
+                        }
+                    </div>
+                </Spin>
                 {/* 鼠标右键菜单 */}
                 {rightClickPup.id ? rightClickPup.id === 'all' ? <Menu /> : <Menu isItem /> : null}
                 {/* 新建文件弹窗 */}
@@ -349,8 +351,9 @@ function FlieBox(props: Props) {
                         onShowSizeChange={(current: number, size: number) => {
                             getList({ pageSize: size, pageNum: current })
                         }}
+                        pageSizeOptions={['10', '20', '30', '50', '100']}
                         current={listData?.current}
-                        defaultPageSize={20}
+                        defaultPageSize={30}
                         total={listData?.total}
                     />
                 </div>

+ 4 - 1
src/components/Tables/index.tsx

@@ -120,7 +120,10 @@ function Tables(props: Props) {
             scroll={scroll ? { ...scroll, scrollToFirstRowOnChange: true } : undefined}
             size={size}
             rowKey={(a: any) => {
-                return (JSON.stringify(a?.id) || JSON.stringify(a?.key) || JSON.stringify(a[myKey]))
+                if(myKey){
+                    return JSON.stringify(a[myKey])
+                }
+                return (JSON.stringify(a?.id) || JSON.stringify(a?.key))
             }}
             rowSelection={rowSelection ? rowSelection : undefined}
             onRow={record => {

+ 6 - 1
src/global.less

@@ -376,4 +376,9 @@ body {
 //   td{
 //     background-color: #fff !important;
 //   }
-// }
+// }
+.ad_form_style{
+  .ant-form-item{
+    margin-bottom: 15px;
+  }
+}

+ 564 - 392
src/models/useLaunchAdq/useBdMediaPup.ts

@@ -1,424 +1,596 @@
 import getMD5 from '@/components/MD5';
 import { useAjax } from '@/Hook/useAjax';
-import { bdSysMediaList, bdSysMediaAdd, delMedia, bdSysMediaEdit, getFileUrl, getMedia, configSortApi, getFolderTree, editMediaFolder } from '@/services/launchAdq/material';
+import {
+  bdSysMediaList,
+  bdSysMediaAdd,
+  delMedia,
+  bdSysMediaEdit,
+  getFileUrl,
+  getMedia,
+  configSortApi,
+  getFolderTree,
+  editMediaFolder,
+} from '@/services/launchAdq/material';
 import { blobToBase64, dataURLtoFile, videoMessage } from '@/utils/compress';
 import { getImgSize } from '@/utils/utils';
 import { message } from 'antd';
 import { compressAccurately } from 'image-conversion';
-import { Dispatch, useCallback, useReducer, useState } from 'react'
+import { Dispatch, useCallback, useReducer, useState } from 'react';
 import { request } from 'umi';
 /**新本地素材弹窗 */
 type State = {
-    fileVisible?: boolean,//文件夹弹窗
-    imgVisrible?: boolean,//img,voice,video弹窗
-    newsVisrible?: boolean,//news弹窗
-    knewsVisrible?: boolean,//客服图文弹窗
-    fileName?: string,//文件夹名称
-    sort?: number, // 排序
-    videoTitle?: string,//video文件名称
-    videoDescription?: string,//视频描述
-    belongUser?: any,//0公共本地|1个人本地
-    mediaType?: 'VIDEO' | 'IMG' | 'PAGE', // 类型
-    parentId?: any,//上级目录ID,顶级使用null
-    url?: string,//素材地址
-    pathId?: string,//路径ID
-    selectFile?: number[],//选中的文件列表
-    rightClickPup?: any,// /**右键菜单开关 all为全部 id 为目标文件 空为不显示*/
-    xy?: { x: number, y: number },// /**鼠标位置 菜单弹窗位置使用*/
-    delPupId?: any,//按了单个删除存放的id为了让弹窗区分文件
-    actionItem?: any,//当前选中的Itme
-    path?: any[],//个人路径
-    publicPath?: any[],//本地路径
-    file?: File,//素材文件
-    selectItem?: any[],//单选素材时存放选中的素材
-    knewsdefaultData?: any,//k图文编辑时的默认内容
-    sortVisible?: boolean,//排序弹窗
-    num?: number, //选择数量
-    size?: number,  // 需要上传素材的大小
-    upLoadLoading?: boolean,
-    cloudSize?: any[],
-    maxSize?:number,//素材最大尺寸
-}
+  fileVisible?: boolean; //文件夹弹窗
+  imgVisrible?: boolean; //img,voice,video弹窗
+  newsVisrible?: boolean; //news弹窗
+  knewsVisrible?: boolean; //客服图文弹窗
+  fileName?: string; //文件夹名称
+  sort?: number; // 排序
+  videoTitle?: string; //video文件名称
+  videoDescription?: string; //视频描述
+  belongUser?: any; //0公共本地|1个人本地
+  mediaType?: 'VIDEO' | 'IMG' | 'PAGE'; // 类型
+  parentId?: any; //上级目录ID,顶级使用null
+  url?: string; //素材地址
+  pathId?: string; //路径ID
+  selectFile?: number[]; //选中的文件列表
+  rightClickPup?: any; // /**右键菜单开关 all为全部 id 为目标文件 空为不显示*/
+  xy?: { x: number; y: number }; // /**鼠标位置 菜单弹窗位置使用*/
+  delPupId?: any; //按了单个删除存放的id为了让弹窗区分文件
+  actionItem?: any; //当前选中的Itme
+  path?: any[]; //个人路径
+  publicPath?: any[]; //本地路径
+  file?: File; //素材文件
+  selectItem?: any[]; //单选素材时存放选中的素材
+  knewsdefaultData?: any; //k图文编辑时的默认内容
+  sortVisible?: boolean; //排序弹窗
+  num?: number; //选择数量
+  size?: number; // 需要上传素材的大小
+  upLoadLoading?: boolean;
+  cloudSize?: any[];
+  maxSize?: number; //素材最大尺寸
+  adcreativeTemplateId?: number; //创意模板 id
+  promotedObjectType?: string; //推广目标类型
+  promotedObjectId?: string; //推广目标 id
+  pageType?: string; //落地页类型
+  canvasType?: string; //原生页类型
+  siteSet?: string[]; //版位
+  sourceType?: string; //视频/图片/原生页等素材的创建来源类型
+  marketingScene?: string; //营销场景
+};
 export type Action = {
-    type: 'set' | 'init',
-    params?: any
-}
+  type: 'set' | 'init';
+  params?: any;
+};
 const typeEnum = {
-    'IMG': '图片',
-    'VIDEO': '视频'
-}
+  IMG: '图片',
+  VIDEO: '视频',
+};
 function reducer(state: State, action: Action) {
-    let { type, params } = action
-    let newState = JSON.parse(JSON.stringify(state))
-    newState.file = state.file
-    switch (type) {
-        case 'set':
-            Object.keys(params as State).forEach((key: string) => {
-                newState[key] = (params as State)[key]
-            })
-            return newState
-        case 'init':
-            return { ...initData, ...params }
-        default:
-            return state;
-    }
+  let { type, params } = action;
+  let newState = JSON.parse(JSON.stringify(state));
+  newState.file = state.file;
+  switch (type) {
+    case 'set':
+      Object.keys(params as State).forEach((key: string) => {
+        newState[key] = (params as State)[key];
+      });
+      return newState;
+    case 'init':
+      return { ...initData, ...params };
+    default:
+      return state;
+  }
 }
 const initData: State = {
-    fileVisible: false,
-    knewsVisrible: false,
-    videoTitle: '',
-    videoDescription: '',
-    fileName: '',
-    belongUser: '1',
-    mediaType: 'IMG',
-    parentId: null,
-    selectFile: [],
-    delPupId: '',
-    rightClickPup: { id: '' },
-    publicPath: [{ title: '公共本地', number: '0' }],
-    path: [{ title: '个人本地', number: '0' }],
-    imgVisrible: false,
-    newsVisrible: false,
-    sortVisible: false,
-    sort: 0,
-    num: 1
-}
+  fileVisible: false,
+  knewsVisrible: false,
+  videoTitle: '',
+  videoDescription: '',
+  fileName: '',
+  belongUser: '1',
+  mediaType: 'IMG',
+  parentId: null,
+  selectFile: [],
+  delPupId: '',
+  rightClickPup: { id: '' },
+  publicPath: [{ title: '公共本地', number: '0' }],
+  path: [{ title: '个人本地', number: '0' }],
+  imgVisrible: false,
+  newsVisrible: false,
+  sortVisible: false,
+  sort: 0,
+  num: 1,
+};
 /**本地素材管理器 */
 function useBdMediaPup() {
-    const [state, dispatch]: [State, Dispatch<Action>] = useReducer(reducer, initData)
-    const { fileName, sort, belongUser, mediaType, parentId, selectFile, selectItem, delPupId, cloudSize, num, rightClickPup, actionItem, path, publicPath, videoTitle, videoDescription, size,maxSize } = state
-    const list = useAjax((params) => bdSysMediaList(params))
-    const add = useAjax((params) => bdSysMediaAdd(params), { msgNmae: '新增' })
-    const del = useAjax((params) => delMedia(params), { msgNmae: '删除' })
-    const edit = useAjax((params) => bdSysMediaEdit(params), { msgNmae: '编辑' })
-    const configSort = useAjax((params) => configSortApi(params), { msgNmae: '排序' })
-    const get = useAjax((params) => getMedia(params))//获取图文详情
-    const get_folder_tree = useAjax((params: any) => getFolderTree(params))
-    const edit_media_folder = useAjax((params: any) => editMediaFolder(params))
-    const [isOk, setIsOk] = useState<boolean>(true)
-    //请求上传地址
-    const fileUrl = useAjax((params: { type: string, fileType: 'video' | 'image' }) => getFileUrl(params), {
-        manual: true,
-    })
-    /**初始化数据 */
-    const init = useCallback((params: any) => {
-        console.log('params======>',params)
-        dispatch({ type: 'init', params })
-    }, [])
-    /**设置state */
-    const set = useCallback((params: State) => {
-        if (params) {
-            dispatch({ type: 'set', params })
-        }
-    }, [])
-    /**新增文件夹 */
-    const addFolder = () => {
-        if (fileName) {
-            let obj = { title: fileName, mediaType, folder: true, parentId, belongUser: belongUser === '0' ? false : true, sort }
-            add.run(obj).then((res) => {
-                get_folder_tree.refresh()
-                list.refresh()
-                offEditFile()//关闭弹窗并清空相关数据
-            })
-        }
+  const [state, dispatch]: [State, Dispatch<Action>] = useReducer(reducer, initData);
+  const {
+    fileName,
+    sort,
+    belongUser,
+    mediaType,
+    parentId,
+    selectFile,
+    selectItem,
+    delPupId,
+    cloudSize,
+    num,
+    rightClickPup,
+    actionItem,
+    path,
+    publicPath,
+    videoTitle,
+    videoDescription,
+    size,
+    maxSize,
+    adcreativeTemplateId,
+    promotedObjectType,
+    promotedObjectId,
+    pageType,
+    canvasType,
+    siteSet,
+    sourceType,
+    marketingScene,
+  } = state;
+  const list = useAjax((params) => bdSysMediaList(params));
+  const add = useAjax((params) => bdSysMediaAdd(params), { msgNmae: '新增' });
+  const del = useAjax((params) => delMedia(params), { msgNmae: '删除' });
+  const edit = useAjax((params) => bdSysMediaEdit(params), { msgNmae: '编辑' });
+  const configSort = useAjax((params) => configSortApi(params), { msgNmae: '排序' });
+  const get = useAjax((params) => getMedia(params)); //获取图文详情
+  const get_folder_tree = useAjax((params: any) => getFolderTree(params));
+  const edit_media_folder = useAjax((params: any) => editMediaFolder(params));
+  const [isOk, setIsOk] = useState<boolean>(true);
+  //请求上传地址
+  const fileUrl = useAjax(
+    (params: { type: string; fileType: 'video' | 'image' }) => getFileUrl(params),
+    {
+      manual: true,
+    },
+  );
+  /**初始化数据 */
+  const init = useCallback((params: State) => {
+    console.log('params======>', params);
+    dispatch({ type: 'init', params });
+  }, []);
+  /**设置state */
+  const set = useCallback((params: State) => {
+    if (params) {
+      dispatch({ type: 'set', params });
+    }
+  }, []);
+  /**新增文件夹 */
+  const addFolder = () => {
+    if (fileName) {
+      let obj = {
+        title: fileName,
+        mediaType,
+        folder: true,
+        parentId,
+        belongUser: belongUser === '0' ? false : true,
+        sort,
+      };
+      add.run(obj).then((res) => {
+        get_folder_tree.refresh();
+        list.refresh();
+        offEditFile(); //关闭弹窗并清空相关数据
+      });
     }
-    /** 新增图片 视频 */
-    const addFile = async (data: any) => {
-        if (data) {//存在代表素材
-            if (!data) {
-                return
+  };
+  /** 新增图片 视频 */
+  const addFile = async (data: any) => {
+    if (data) {
+      //存在代表素材
+      if (!data) {
+        return;
+      }
+      if (data?.file) {
+        let file = data.file;
+        let fileSize = size || 0;
+        if (!size) {
+          if (mediaType === 'IMG') {
+            fileSize = 307200;
+          } else {
+            fileSize = 104857600;
+          }
+        }
+
+        if (mediaType === 'IMG') {
+          if (file?.size > fileSize) {
+            // 大于300kb进入压缩
+            let bole = await compressAccurately(file, 250);
+            if (bole?.size > 300000) {
+              bole = await compressAccurately(file, 200);
             }
-            if (data?.file) {
-                let file = data.file
-                let fileSize = size || 0
-                if (!size) {
-                    if (mediaType === 'IMG') {
-                        fileSize = 307200
-                    } else {
-                        fileSize = 104857600
-                    }
-                }
+            if (bole?.size > 300000) {
+              bole = await compressAccurately(file, 150);
+            }
+            if (bole?.size > 300000) {
+              bole = await compressAccurately(file, 100);
+            }
+            let newFile = await blobToBase64(bole);
+            message.warning({
+              content: `选择的图片大于${fileSize / 1024}KB,图片已压缩`,
+              duration: 3,
+            });
+            file = await dataURLtoFile(newFile, file?.name);
+          }
+        } else if (mediaType === 'VIDEO') {
+          if (file?.size > fileSize) {
+            // 大于100mb进入压缩
+            message.error({
+              content: `选择的视频大于${fileSize / 1024 / 1024}MB,请重新选择提交`,
+              duration: 3,
+            });
+            return;
+          }
+        }
+        set({ upLoadLoading: true });
+        let width = 0;
+        let height = 0;
+        if (mediaType === 'IMG') {
+          let imgData = await getImgSize(file);
+          width = imgData.width;
+          height = imgData.height;
+        } else if (mediaType === 'VIDEO') {
+          let videoInfo: any = await videoMessage([file]);
+          width = videoInfo[0].width;
+          height = videoInfo[0].height;
+        }
+        /**修改文件名以用户设置的文件title命名*/
+        let newFile = new File(
+          [file],
+          data?.title ? data?.title + '.' + file?.name?.split('.')[1] : file?.name,
+          { type: file?.type },
+        );
+        let formData = new FormData();
 
-                if (mediaType === 'IMG') {
-                    if (file?.size > fileSize) { // 大于300kb进入压缩
-                        let bole = await compressAccurately(file, 250)
-                        if (bole?.size > 300000) {
-                            bole = await compressAccurately(file, 200)
-                        }
-                        if (bole?.size > 300000) {
-                            bole = await compressAccurately(file, 150)
-                        }
-                        if (bole?.size > 300000) {
-                            bole = await compressAccurately(file, 100)
-                        }
-                        let newFile = await blobToBase64(bole)
-                        message.warning({
-                            content: `选择的图片大于${fileSize / 1024}KB,图片已压缩`,
-                            duration: 3
+        /**向阿里云请求上传地址*/
+        fileUrl
+          .run({ type: newFile.type, fileType: mediaType === 'VIDEO' ? 'video' : 'image' })
+          .then((res1) => {
+            Object.keys(res1).forEach((key: string) => {
+              if (key !== 'url') {
+                formData.append(key, res1[key]);
+              }
+            });
+            formData.append('file', newFile);
+            /**向阿里云返回的上传地址上传文件*/
+            request(res1?.ossUrl, { method: 'post', body: formData })
+              .then(async (res2: { code: number; data: { url: string } }) => {
+                if (res2.code === 200) {
+                  message.success('上传成功');
+                  if (data) {
+                    /**取到返回的文件地址向后端发送具体数据*/
+                    if (res2?.data?.url) {
+                      let fileMd5 = await getMD5(newFile);
+                      let obj = {
+                        title: data.title,
+                        mediaType,
+                        folder: false,
+                        parentId,
+                        width,
+                        height,
+                        fileMd5,
+                        belongUser: belongUser === '0' ? false : true,
+                        url: res2?.data?.url,
+                        sort: data?.sort,
+                        fileSize: newFile?.size,
+                        fileMime: newFile.type,
+                      };
+                      if (mediaType === 'VIDEO') {
+                        obj['videoTitle'] = data?.videoTitle || data?.title;
+                        obj['videoDescription'] = data?.videoDescription;
+                      }
+                      add
+                        .run(obj)
+                        .then((res) => {
+                          list.refresh();
+                          offEditFile(); //关闭弹窗并清空相关数据
+                          set({ upLoadLoading: false });
                         })
-                        file = await dataURLtoFile(newFile, file?.name)
+                        .catch(() => set({ upLoadLoading: false }));
                     }
-                } else if (mediaType === 'VIDEO') {
-                    if (file?.size > fileSize) { // 大于100mb进入压缩
-                        message.error({
-                            content: `选择的视频大于${fileSize / 1024 / 1024}MB,请重新选择提交`,
-                            duration: 3
-                        })
-                        return
-                    }
-                }
-                set({ upLoadLoading: true })
-                let width = 0
-                let height = 0
-                if (mediaType === 'IMG') {
-                    let imgData = await getImgSize(file)
-                    width = imgData.width
-                    height = imgData.height
-                } else if (mediaType === "VIDEO") {
-                    let videoInfo: any = await videoMessage([file])
-                    width = videoInfo[0].width
-                    height = videoInfo[0].height
+                  }
+                } else {
+                  message.error('上传失败!');
                 }
-                /**修改文件名以用户设置的文件title命名*/
-                let newFile = new File([file], data?.title ? data?.title + '.' + file?.name?.split('.')[1] : file?.name, { type: file?.type })
-                let formData = new FormData();
-
-                /**向阿里云请求上传地址*/
-                fileUrl.run({ type: newFile.type, fileType: mediaType === 'VIDEO' ? 'video' : 'image' }).then(res1 => {
-                    Object.keys(res1).forEach((key: string) => {
-                        if (key !== 'url') {
-                            formData.append(key, res1[key])
-                        }
-                    })
-                    formData.append('file', newFile)
-                    /**向阿里云返回的上传地址上传文件*/
-                    request(res1?.ossUrl, { method: 'post', body: formData }).then(async (res2: { code: number, data: { url: string } }) => {
-                        if (res2.code === 200) {
-                            message.success('上传成功')
-                            if (data) {
-                                /**取到返回的文件地址向后端发送具体数据*/
-                                if (res2?.data?.url) {
-                                    let fileMd5 = await getMD5(newFile)
-                                    let obj = { title: data.title, mediaType, folder: false, parentId, width, height, fileMd5, belongUser: belongUser === '0' ? false : true, url: res2?.data?.url, sort: data?.sort, fileSize: newFile?.size, fileMime: newFile.type }
-                                    if (mediaType === 'VIDEO') {
-                                        obj['videoTitle'] = data?.videoTitle || data?.title
-                                        obj['videoDescription'] = data?.videoDescription
-                                    }
-                                    add.run(obj).then((res) => {
-                                        list.refresh()
-                                        offEditFile()//关闭弹窗并清空相关数据
-                                        set({ upLoadLoading: false })
-                                    }).catch(() => set({ upLoadLoading: false }))
-                                }
-                            }
-                        } else {
-                            message.error('上传失败!')
-                        }
-                    }).catch(() => set({ upLoadLoading: false }))
-                }).catch(() => set({ upLoadLoading: false }))
-            }
-        }
+              })
+              .catch(() => set({ upLoadLoading: false }));
+          })
+          .catch(() => set({ upLoadLoading: false }));
+      }
     }
-    /**编辑非图文素材名称*/
-    const nameOk = useCallback((selectWx: any) => {
-        if (fileName && actionItem) {
-            let obj = { title: fileName, belongUser: belongUser === '0' ? false : true, sysMediaId: actionItem?.id, mediaType: actionItem?.mediaType, folder: actionItem?.folder, url: actionItem?.url, sort }
-            if (mediaType === 'VIDEO') {
-                obj['videoTitle'] = videoTitle
-                obj['videoDescription'] = videoDescription
-            }
-            edit.run(obj).then((res) => {
-                list.refresh()
-                offEditFile()//关闭弹窗并清空相关数据
-            })
-        }
-    }, [fileName, actionItem, edit, belongUser, mediaType, videoTitle, videoDescription])
-    /**删除文件 */
-    const dels = useCallback((id?: any) => {
-        let arr = typeof id === 'number' ? [id] : selectFile
-        let len = arr?.length || 0
-        if (len) {
-            arr?.map((id, index) => {
-                del.run({ sysMediaId: id, mediaType }).then(() => {
-                    set({ selectFile: selectFile?.filter(i => i !== id) })//清理已删除文件
-                    if (index === len - 1) {
-                        list.refresh()
-                        get_folder_tree.refresh()
-                    }
-                })
-            })
+  };
+  /**编辑非图文素材名称*/
+  const nameOk = useCallback(
+    (selectWx: any) => {
+      if (fileName && actionItem) {
+        let obj = {
+          title: fileName,
+          belongUser: belongUser === '0' ? false : true,
+          sysMediaId: actionItem?.id,
+          mediaType: actionItem?.mediaType,
+          folder: actionItem?.folder,
+          url: actionItem?.url,
+          sort,
+        };
+        if (mediaType === 'VIDEO') {
+          obj['videoTitle'] = videoTitle;
+          obj['videoDescription'] = videoDescription;
         }
-    }, [list, selectFile, mediaType])
-    /**获取本地素材数据列表 */
-    const getList = useCallback((props?: any) => {
-        console.log('getList====>',props)
-        let obj = { pageSize: 20, pageNum: 1, belongUser: belongUser === '0' ? false : true, mediaType, parentId, sizeQueries: cloudSize,maxSize, ...props }
-        list.run(obj).then((res) => {
-            setIsOk(true)
-        })
-    }, [list, mediaType, belongUser, parentId, cloudSize,maxSize])
-    /**选中文件 single 开启可单选为了在右键删除选择时只选一个*/
-    const onFile = useCallback((e: any, item: { id: any, folder?: boolean }, isAll?: boolean, single?: boolean) => {
-        let { id } = item
-        e?.stopPropagation()
-        if (isAll && !single) {
-            set({ selectFile: [...new Set([...selectFile as number[], id])] })
-        } else {
-            if (item?.folder && !single) {//假如是文件不让选择
-                message.error('不能选择文件夹')
-                return
+        edit.run(obj).then((res) => {
+          list.refresh();
+          offEditFile(); //关闭弹窗并清空相关数据
+        });
+      }
+    },
+    [fileName, actionItem, edit, belongUser, mediaType, videoTitle, videoDescription],
+  );
+  /**删除文件 */
+  const dels = useCallback(
+    (id?: any) => {
+      let arr = typeof id === 'number' ? [id] : selectFile;
+      let len = arr?.length || 0;
+      if (len) {
+        arr?.map((id, index) => {
+          del.run({ sysMediaId: id, mediaType }).then(() => {
+            set({ selectFile: selectFile?.filter((i) => i !== id) }); //清理已删除文件
+            if (index === len - 1) {
+              list.refresh();
+              get_folder_tree.refresh();
             }
-            set({ selectFile: [item.id], selectItem: [item] })
+          });
+        });
+      }
+    },
+    [list, selectFile, mediaType],
+  );
+  /**获取本地素材数据列表 */
+  const getList = useCallback(
+    (props?: any) => {
+      console.log('getList====>', props);
+      let obj = {
+        pageSize: 20,
+        pageNum: 1,
+        belongUser: belongUser === '0' ? false : true,
+        mediaType,
+        parentId,
+        sizeQueries: cloudSize,
+        maxSize,
+        ...props,
+      };
+      if (mediaType === 'PAGE') {
+        obj = {
+          ...obj,
+          adcreativeTemplateId,
+          promotedObjectType,
+          promotedObjectId,
+          pageType,
+          canvasType,
+          siteSet,
+          sourceType,
+          marketingScene,
+        };
+      }
+      list.run(obj).then((res) => {
+        setIsOk(true);
+      });
+    },
+    [list, mediaType, belongUser, parentId, cloudSize, maxSize,adcreativeTemplateId,promotedObjectType,promotedObjectId,pageType,canvasType,siteSet,sourceType,marketingScene],
+  );
+  /**选中文件 single 开启可单选为了在右键删除选择时只选一个*/
+  const onFile = useCallback(
+    (e: any, item: { id: any; folder?: boolean }, isAll?: boolean, single?: boolean) => {
+      let { id } = item;
+      e?.stopPropagation();
+      if (isAll && !single) {
+        set({ selectFile: [...new Set([...(selectFile as number[]), id])] });
+      } else {
+        if (item?.folder && !single) {
+          //假如是文件不让选择
+          message.error('不能选择文件夹');
+          return;
         }
-    }, [selectFile])
-    /**点击文件夹 */
-    const fileClick = useCallback((item) => {
-        if (isOk) {
-            setIsOk(false)
-            if (belongUser == '1' && path) {
-                set({ path: [...path, item] })
-            }
-            if (belongUser == '0' && publicPath) {
-                set({ publicPath: [...publicPath, item] })
-            }
-            set({ parentId: item.id })
-            getList({ parentId: item.id })//请求对应文件夹列表
+        set({ selectFile: [item.id], selectItem: [item] });
+      }
+    },
+    [selectFile],
+  );
+  /**点击文件夹 */
+  const fileClick = useCallback(
+    (item) => {
+      if (isOk) {
+        setIsOk(false);
+        if (belongUser == '1' && path) {
+          set({ path: [...path, item] });
         }
-    }, [path, publicPath, mediaType, belongUser, isOk])
-    /**点击目录树*/
-    const treeClick = useCallback((item) => {
-        if (isOk) {
-            setIsOk(false)
-            console.log(item, belongUser == '1')
-            if (belongUser == '1' && path) {
-                set({ path: [path[0], item] })
-            }
-            if (belongUser == '0' && publicPath) {
-                set({ publicPath: [publicPath[0], item] })
-            }
-            set({ parentId: item.id })
-            getList({ parentId: item.id })//请求对应文件夹列表
+        if (belongUser == '0' && publicPath) {
+          set({ publicPath: [...publicPath, item] });
         }
-    }, [path, publicPath, mediaType, belongUser, isOk])
-    /**点击路径 */
-    const pathClick = useCallback((item) => {
-        let newPath: any[] = []
-        if (belongUser == '1') {
-            path?.forEach((paths, index) => {//用传入的index和path循环的index对比小于等于index代表该保留的路径
-                if (index <= item.index) {
-                    newPath.push(paths)
-                }
-            })
-            set({ path: newPath })
-        } else {
-            publicPath?.forEach((paths, index) => {//用传入的index和path循环的index对比小于等于index代表该保留的路径
-                if (index <= item.index) {
-                    newPath.push(paths)
-                }
-            })
-            set({ publicPath: newPath })
+        set({ parentId: item.id });
+        getList({ parentId: item.id }); //请求对应文件夹列表
+      }
+    },
+    [path, publicPath, mediaType, belongUser, isOk],
+  );
+  /**点击目录树*/
+  const treeClick = useCallback(
+    (item) => {
+      if (isOk) {
+        setIsOk(false);
+        console.log(item, belongUser == '1');
+        if (belongUser == '1' && path) {
+          set({ path: [path[0], item] });
+        }
+        if (belongUser == '0' && publicPath) {
+          set({ publicPath: [publicPath[0], item] });
         }
-        set({ parentId: item.parentId })
-        getList({ pageSize: 20, pageNum: 1, mediaType, belongUser: belongUser === '0' ? false : true, parentId: item.id })
-    }, [path, mediaType, belongUser, publicPath])
-    /**取消文件 */
-    const offFile = useCallback((e: any, item: { id: any }) => {
-        let { id } = item
-        set({ selectFile: selectFile?.filter(i => i !== id) })
-    }, [selectFile])
-    /**判断是取消还是选中文件的操作在点击打钩时使用 */
-    const changeClickFile = useCallback((e: any, item: { id: any, folder?: boolean }, isAll?: boolean, noFile?: boolean) => {
-        let { id } = item
-        e?.stopPropagation()//阻止冒泡传递到文件夹被点击事件
-        console.log(111111, num);
-        
-        // if (mediaType === 'PAGE') {
+        set({ parentId: item.id });
+        getList({ parentId: item.id }); //请求对应文件夹列表
+      }
+    },
+    [path, publicPath, mediaType, belongUser, isOk],
+  );
+  /**点击路径 */
+  const pathClick = useCallback(
+    (item) => {
+      let newPath: any[] = [];
+      if (belongUser == '1') {
+        path?.forEach((paths, index) => {
+          //用传入的index和path循环的index对比小于等于index代表该保留的路径
+          if (index <= item.index) {
+            newPath.push(paths);
+          }
+        });
+        set({ path: newPath });
+      } else {
+        publicPath?.forEach((paths, index) => {
+          //用传入的index和path循环的index对比小于等于index代表该保留的路径
+          if (index <= item.index) {
+            newPath.push(paths);
+          }
+        });
+        set({ publicPath: newPath });
+      }
+      set({ parentId: item.parentId });
+      getList({
+        pageSize: 20,
+        pageNum: 1,
+        mediaType,
+        belongUser: belongUser === '0' ? false : true,
+        parentId: item.id,
+      });
+    },
+    [path, mediaType, belongUser, publicPath],
+  );
+  /**取消文件 */
+  const offFile = useCallback(
+    (e: any, item: { id: any }) => {
+      let { id } = item;
+      set({ selectFile: selectFile?.filter((i) => i !== id) });
+    },
+    [selectFile],
+  );
+  /**判断是取消还是选中文件的操作在点击打钩时使用 */
+  const changeClickFile = useCallback(
+    (e: any, item: { id: any; folder?: boolean }, isAll?: boolean, noFile?: boolean) => {
+      let { id } = item;
+      e?.stopPropagation(); //阻止冒泡传递到文件夹被点击事件
+      console.log(111111, num);
 
-        // } else {
-            let state = selectFile?.some((i) => i === id)
-            if (state) {//存在就是删除
-                set({ selectFile: selectFile?.filter(i => i !== id), selectItem: selectItem?.filter((i: { id: number }) => i.id !== id) })
-            } else {//否则新增
-                if (num === 1) {
-                    if (state) {//存在就是删除
-                        set({ selectFile: selectFile?.filter(i => i !== id), selectItem: [] })
-                    } else {//否则新增
-                        console.log(11111)
-                        set({ selectFile: [id], selectItem: [item] })
-                    }
-                } else {
-                    if (selectFile && num && (selectFile?.length >= num)) {
-                        message.error(`只能选择${num}张`)
-                        return
-                    }
-                    let newSelectItem = selectItem || []
-                    newSelectItem.push(item)
-                    set({ selectItem: newSelectItem, selectFile: [...selectFile as number[], id] })
-                }
-            }
-        // }
-    }, [selectFile, mediaType, num])
-    /**开启删除弹窗 */
-    const delPupOn = useCallback((delPupId) => {
-        set({ delPupId })
-    }, [])
-    /**关闭删除弹窗并去除选中 */
-    const delPupOff = useCallback(() => {
-        set({ delPupId: '' })
-        offFile(null, { id: delPupId })
-    }, [delPupId,])
-    /**编辑 */
-    const editFile = useCallback((e?: any,) => {
-        e?.stopPropagation()
-        onFile(null, rightClickPup, true, true)
-        // if (rightClickPup?.mediaType !== 'news') {//不是图文开启编辑名字弹窗
-        let obj = { fileVisible: true, actionItem: rightClickPup, fileName: rightClickPup.title, sort: rightClickPup.sort }
-        if (rightClickPup?.mediaType === 'video') {
-            obj['videoTitle'] = rightClickPup?.videoTitle || rightClickPup?.title
-            obj['videoDescription'] = rightClickPup?.videoDescription
+      // if (mediaType === 'PAGE') {
+
+      // } else {
+      let state = selectFile?.some((i) => i === id);
+      if (state) {
+        //存在就是删除
+        set({
+          selectFile: selectFile?.filter((i) => i !== id),
+          selectItem: selectItem?.filter((i: { id: number }) => i.id !== id),
+        });
+      } else {
+        //否则新增
+        if (num === 1) {
+          if (state) {
+            //存在就是删除
+            set({ selectFile: selectFile?.filter((i) => i !== id), selectItem: [] });
+          } else {
+            //否则新增
+            console.log(11111);
+            set({ selectFile: [id], selectItem: [item] });
+          }
+        } else {
+          if (selectFile && num && selectFile?.length >= num) {
+            message.error(`只能选择${num}张`);
+            return;
+          }
+          let newSelectItem = selectItem || [];
+          newSelectItem.push(item);
+          set({ selectItem: newSelectItem, selectFile: [...(selectFile as number[]), id] });
         }
-        set(obj)
-        // }
-    }, [rightClickPup])
-    /**取消编辑后清空选中存放的数据并关闭弹窗*/
-    const offEditFile = useCallback(() => {
-        set({ fileVisible: false, imgVisrible: false, sortVisible: false, actionItem: '', fileName: '', selectFile: selectFile?.filter(id => id !== actionItem?.id), sort: 0 })
-    }, [selectFile, actionItem])
-    /**全选反选文件*/
-    const allFile = useCallback(() => {
-        let allArr: any[] = []
-        list?.data?.records?.forEach((item: { id: any }) => {
-            allArr.push(item.id)
-        })
-        set({ selectFile: allArr.filter((i) => selectFile?.every(id => id !== i)) })
-    }, [selectFile, list, mediaType])
-    return {
-        state,
-        init,
-        set,
-        addFile,
-        addFolder,
-        getList,
-        dels,
-        onFile,
-        changeClickFile,
-        allFile,
-        delPupOn,
-        delPupOff,
-        editFile,
-        offEditFile,
-        nameOk,
-        fileClick,
-        treeClick,
-        pathClick,
-        configSort,
-        list,
-        add,
-        get,
-        edit,
-        typeEnum,
-        get_folder_tree,
-        edit_media_folder
-    }
+      }
+      // }
+    },
+    [selectFile, mediaType, num],
+  );
+  /**开启删除弹窗 */
+  const delPupOn = useCallback((delPupId) => {
+    set({ delPupId });
+  }, []);
+  /**关闭删除弹窗并去除选中 */
+  const delPupOff = useCallback(() => {
+    set({ delPupId: '' });
+    offFile(null, { id: delPupId });
+  }, [delPupId]);
+  /**编辑 */
+  const editFile = useCallback(
+    (e?: any) => {
+      e?.stopPropagation();
+      onFile(null, rightClickPup, true, true);
+      // if (rightClickPup?.mediaType !== 'news') {//不是图文开启编辑名字弹窗
+      let obj = {
+        fileVisible: true,
+        actionItem: rightClickPup,
+        fileName: rightClickPup.title,
+        sort: rightClickPup.sort,
+      };
+      if (rightClickPup?.mediaType === 'video') {
+        obj['videoTitle'] = rightClickPup?.videoTitle || rightClickPup?.title;
+        obj['videoDescription'] = rightClickPup?.videoDescription;
+      }
+      set(obj);
+      // }
+    },
+    [rightClickPup],
+  );
+  /**取消编辑后清空选中存放的数据并关闭弹窗*/
+  const offEditFile = useCallback(() => {
+    set({
+      fileVisible: false,
+      imgVisrible: false,
+      sortVisible: false,
+      actionItem: '',
+      fileName: '',
+      selectFile: selectFile?.filter((id) => id !== actionItem?.id),
+      sort: 0,
+    });
+  }, [selectFile, actionItem]);
+  /**全选反选文件*/
+  const allFile = useCallback(() => {
+    let allArr: any[] = [];
+    list?.data?.records?.forEach((item: { id: any }) => {
+      allArr.push(item.id);
+    });
+    set({ selectFile: allArr.filter((i) => selectFile?.every((id) => id !== i)) });
+  }, [selectFile, list, mediaType]);
+  return {
+    state,
+    init,
+    set,
+    addFile,
+    addFolder,
+    getList,
+    dels,
+    onFile,
+    changeClickFile,
+    allFile,
+    delPupOn,
+    delPupOff,
+    editFile,
+    offEditFile,
+    nameOk,
+    fileClick,
+    treeClick,
+    pathClick,
+    configSort,
+    list,
+    add,
+    get,
+    edit,
+    typeEnum,
+    get_folder_tree,
+    edit_media_folder,
+  };
 }
-export default useBdMediaPup
+export default useBdMediaPup;

+ 1 - 1
src/pages/launchSystem/launchManage/components/authLogin/index.tsx

@@ -1,4 +1,4 @@
-import { useModel } from "@/.umi/plugin-model/useModel";
+import { useModel } from "umi";
 import { setCookie } from "@/utils/cry";
 import { Modal, Image, message } from "antd";
 import React, { useCallback, useEffect, useState } from "react";

+ 1 - 1
src/pages/launchSystem/launchManage/weChat/components/createPlan/components/AdOriginality/components/ClerkAide/index.tsx

@@ -1,4 +1,4 @@
-import { useModel } from "@/.umi/plugin-model/useModel";
+import { useModel } from "umi";
 import Tables from "@/components/Tables";
 import columns from './tableConfig'
 import { DatePicker, Input, Modal, Select, Space } from "antd";

+ 1 - 1
src/pages/launchSystem/launchManageNew/weChatNew/components/createPlan/components/AdOriginality/components/ClerkAide/index.tsx

@@ -1,4 +1,4 @@
-import { useModel } from "@/.umi/plugin-model/useModel";
+import { useModel } from "umi";
 import Tables from "@/components/Tables";
 import columns from './tableConfig'
 import { DatePicker, Input, Modal, Select, Space } from "antd";

+ 1 - 1
src/pages/launchSystem/materialManage/adMaterial/components/addCom/index.tsx

@@ -1,4 +1,4 @@
-import { useModel } from '@/.umi/plugin-model/useModel'
+import { useModel } from 'umi'
 import { Modal, Button, Form, Select, message, Space, Image as AntImg, Upload } from 'antd'
 import { SelectValue } from 'antd/es/select'
 import Cropprt from '@/components/Cropper'

+ 1 - 1
src/pages/launchSystem/materialManage/adMaterial/index.tsx

@@ -5,7 +5,7 @@ import './index1.less'
 import moment from 'moment'
 import AddCom from './components/addCom'
 import { SelectValue } from 'antd/es/select'
-import { useModel } from '@/.umi/plugin-model/useModel'
+import { useModel } from 'umi'
 import { CheckboxValueType } from 'antd/es/checkbox/Group'
 import { CheckboxChangeEvent } from 'antd/es/checkbox'
 import ImgPreview from '@/components/ImgPreview'

+ 1 - 1
src/pages/launchSystem/materialManage/adOriginality/components/addOriginality/index.tsx

@@ -1,4 +1,4 @@
-import { useModel } from '@/.umi/plugin-model/useModel'
+import { useModel } from 'umi'
 import { Modal, Button, Form, Select, message, Space, Image as AntImg, Row, Col, Upload, Input } from 'antd'
 import { SelectValue } from 'antd/es/select'
 import Cropprt from '@/components/Cropper'

+ 1 - 1
src/pages/launchSystem/materialManage/adOriginality/index.tsx

@@ -6,7 +6,7 @@ import moment from 'moment'
 import AddCom from './components/addOriginality'
 import Details from './components/details'
 import { SelectValue } from 'antd/es/select'
-import { useModel } from '@/.umi/plugin-model/useModel'
+import { useModel } from 'umi'
 import { CheckboxValueType } from 'antd/es/checkbox/Group'
 import { CheckboxChangeEvent } from 'antd/es/checkbox'
 import ImgPreview from '@/components/ImgPreview'

+ 1 - 1
src/pages/launchSystem/materialManage/adTitle/components/addTitle/index.tsx

@@ -1,4 +1,4 @@
-import { useModel } from '@/.umi/plugin-model/useModel'
+import { useModel } from 'umi'
 import { Modal, Button, Form, Select, message, Space } from 'antd'
 import { SelectValue } from 'antd/es/select'
 import React, { useCallback, useEffect, useState } from "react"

+ 1 - 1
src/pages/launchSystem/materialManage/adTitle/index.tsx

@@ -5,7 +5,7 @@ import React, { useCallback, useEffect, useReducer, useState } from 'react'
 import AddTitle from './components/addTitle'
 import Tables from '@/components/Tables'
 import columns from './tableConfig'
-import { useModel } from '@/.umi/plugin-model/useModel'
+import { useModel } from 'umi'
 const { Option } = Select
 const { Search } = Input
 const { TabPane } = Tabs

+ 1 - 1
src/pages/launchSystem/materialManage/tagManage/index.tsx

@@ -3,7 +3,7 @@ import React, {  useCallback, useEffect, useMemo, useState } from 'react'
 import style from './index.less'
 import './index.less'
 import Checkbox from 'antd/lib/checkbox/Checkbox';
-import { useModel } from '@/.umi/plugin-model/useModel';
+import { useModel } from 'umi';
 const { CheckableTag } = Tag;
 
 /**标签管理*/

+ 1 - 1
src/pages/launchSystem/materialManageBd/adMaterial/components/addCom/index.tsx

@@ -1,4 +1,4 @@
-import { useModel } from '@/.umi/plugin-model/useModel'
+import { useModel } from 'umi'
 import { Modal, Button, Form, Select, message, Space, Image as AntImg, Upload, } from 'antd'
 import { SelectValue } from 'antd/es/select'
 import Cropprt from '@/components/Cropper'

+ 1 - 1
src/pages/launchSystem/materialManageBd/adMaterial/index.tsx

@@ -5,7 +5,7 @@ import './index1.less'
 import AddCom from './components/addCom'
 import BatchAddLabel from '@/components/BatchAddLabel'
 import { SelectValue } from 'antd/es/select'
-import { useModel } from '@/.umi/plugin-model/useModel'
+import { useModel } from 'umi'
 import { CheckboxValueType } from 'antd/es/checkbox/Group'
 import { CheckboxChangeEvent } from 'antd/es/checkbox'
 import ImgPreview from '@/components/ImgPreview'

+ 1 - 1
src/pages/launchSystem/materialManageBd/adOriginality/components/addOriginality/index.tsx

@@ -1,4 +1,4 @@
-import { useModel } from '@/.umi/plugin-model/useModel'
+import { useModel } from 'umi'
 import { Modal, Button, Form, Select, message, Space, Image as AntImg, Row, Col, Upload, Input } from 'antd'
 import { SelectValue } from 'antd/es/select'
 import Cropprt from '@/components/Cropper'

+ 1 - 1
src/pages/launchSystem/materialManageBd/adOriginality/index.tsx

@@ -6,7 +6,7 @@ import moment from 'moment'
 import AddCom from './components/addOriginality'
 import Details from './components/details'
 import { SelectValue } from 'antd/es/select'
-import { useModel } from '@/.umi/plugin-model/useModel'
+import { useModel } from 'umi'
 import { CheckboxValueType } from 'antd/es/checkbox/Group'
 import { CheckboxChangeEvent } from 'antd/es/checkbox'
 import ImgPreview from '@/components/ImgPreview'

+ 1 - 1
src/pages/launchSystem/materialManageBd/adTitle/components/addTitle/index.tsx

@@ -1,4 +1,4 @@
-import { useModel } from '@/.umi/plugin-model/useModel'
+import { useModel } from 'umi'
 import { Modal, Button, Form, Select, message, Space } from 'antd'
 import { SelectValue } from 'antd/es/select'
 import TextArea from 'antd/lib/input/TextArea'

+ 1 - 1
src/pages/launchSystem/materialManageBd/adTitle/index.tsx

@@ -6,7 +6,7 @@ import AddTitle from './components/addTitle'
 import Tables from '@/components/Tables'
 import columns from './tableConfig'
 import BatchAddLabel from '@/components/BatchAddLabel'
-import { useModel } from '@/.umi/plugin-model/useModel'
+import { useModel } from 'umi'
 const { Option } = Select
 const { Search } = Input
 const { TabPane } = Tabs

+ 1 - 1
src/pages/launchSystem/materialManageBd/tagManage/index.tsx

@@ -3,7 +3,7 @@ import React, {  useCallback, useEffect, useMemo, useState } from 'react'
 import style from './index.less'
 import './index.less'
 import Checkbox from 'antd/lib/checkbox/Checkbox';
-import { useModel } from '@/.umi/plugin-model/useModel';
+import { useModel } from 'umi';
 const { CheckableTag } = Tag;
 
 /**标签管理*/

+ 27 - 3
src/pages/launchSystemNew/adq/ad/index.tsx

@@ -31,21 +31,22 @@ type Props = {
 }
 
 function Ad(props:Props) {
-    let { accountId, adAccountId,userId,tableIdClick } = props
+    let { accountId, adAccountId,userId,tableIdClick,queryParmas } = props
     // api方法
     const listAjax = useAjax((params) => getAdqAdgroupsList(params), { formatResult: true })
     const syncAjax = useAjax((adAccountId) => putAdqAdgroupsSync(adAccountId))
     const switchAjax = useAjax((params) => putAdqAdgroupsConfigStatus(params))
     console.log('创意=====》')
     useEffect(() => {
-        getList({ pageNum: 1, pageSize: 20 })
-    }, [accountId,userId])
+        getList({ pageNum: 1, pageSize: 20,...queryParmas })
+    }, [accountId,userId,queryParmas])
     // 获取列表
     const getList = useCallback((params: {
         pageNum: number;
         pageSize: number;
         accountId?: string;
         adcreativeName?: string;
+        adgroupId?:string
     }) => {
         if (!params.adcreativeName || params.adcreativeName !== listAjax?.params[0]?.adcreativeName) {
             !params.adcreativeName && delete params.adcreativeName
@@ -111,6 +112,29 @@ function Ad(props:Props) {
                             }}
                         />
                     </Col>
+                    <Col>
+                        <Input
+                            placeholder='广告ID'
+                            allowClear
+                            onBlur={(e) => {
+                                let value = e.target.value
+                                getList({ pageNum: 1, pageSize: 20, adgroupId: value })
+                            }}
+                            onKeyDownCapture={(e: any) => {
+                                let key = e.key
+                                if (key === 'Enter') {
+                                    let value = e.target.value
+                                    getList({ pageNum: 1, pageSize: 20, adgroupId: value })
+                                }
+                            }}
+                            onChange={(e) => {
+                                let value = e.target.value
+                                if (!value) {
+                                    getList({ pageNum: 1, pageSize: 20, adgroupId: value })
+                                }
+                            }}
+                        />
+                    </Col>
                     <Col>
                         <Select placeholder='推广目标选择' style={{ minWidth: 200 }} showSearch filterOption={(input: any, option: any) =>
                             (option!.children as unknown as string).toLowerCase().includes(input.toLowerCase())

+ 12 - 0
src/pages/launchSystemNew/adq/ad/tableConfig.tsx

@@ -1,6 +1,7 @@
 import { AdStatusEnum, OptimizationGoalEnum, PromotedObjectType } from '@/services/launchAdq/enum'
 import React from 'react'
 import { Badge, Switch } from 'antd'
+import PreviewAd from '../../components/previewAd'
 function tableConfig(
     switchHandle: (data: any, Status: any) => void,
     tableIdClick: (props: {
@@ -174,6 +175,17 @@ function tableConfig(
                 return AdStatusEnum[a]
             }
         },
+        // {
+        //     title: '预览',
+        //     dataIndex: 'preview',
+        //     key: 'preview',
+        //     align: 'center',
+        //     width: 40,
+        //     fixed: 'right',
+        //     render: (a: string, b: any) => {
+        //         return <PreviewAd adgroupId={b?.adgroupId} accountId={b?.accountId}/>
+        //     }
+        // },
     ]
 }
 export default tableConfig

+ 0 - 1
src/pages/launchSystemNew/adq/adAccount/index.tsx

@@ -73,7 +73,6 @@ function AdAccount(props:Props) {
             total={listAjax?.data?.data?.total}
             page={listAjax?.data?.data?.current}
             pageSize={listAjax?.data?.data?.size}
-            myKey={'adgroupId'}
             leftChild={<>
                 <Row gutter={[10, 10]}>
                 </Row>

+ 1 - 1
src/pages/launchSystemNew/adq/adAccount/tableConfig.tsx

@@ -53,7 +53,7 @@ function tableConfig(tableIdClick: (props: {
            } 
         },
         {
-            title: '是否启用',
+            title: '是否有效',
             dataIndex: 'enabled',
             key: 'enabled',
             align: 'center',

+ 27 - 3
src/pages/launchSystemNew/adq/campaign/index.tsx

@@ -38,8 +38,8 @@ function Campaign(props: Props) {
     const switchAjax = useAjax((params) => putAdqCampaignConfigStatus(params))
     console.log('创意=====》')
     useEffect(() => {
-        getList({ pageNum: 1, pageSize: 20 })
-    }, [accountId, userId])
+        getList({ pageNum: 1, pageSize: 20,...queryParmas })
+    }, [accountId, userId,queryParmas])
     // 获取列表
     const getList = useCallback((params: {
         pageNum: number;
@@ -47,6 +47,7 @@ function Campaign(props: Props) {
         userId?: string;//用户ID
         accountId?: string;//账号本地ID
         campaignName?: string;//计划名称
+        campaignId?: string;//计划ID
         configuredStatus?: string;//计划状态
         campaignType?: string;//计划类型
         promotedObjectType?: string;//推广目标类型
@@ -94,7 +95,7 @@ function Campaign(props: Props) {
                 <Row gutter={[10, 10]}>
                     <Col>
                         <Input
-                            placeholder='创意名称'
+                            placeholder='计划名称'
                             allowClear
                             onBlur={(e) => {
                                 let value = e.target.value
@@ -115,6 +116,29 @@ function Campaign(props: Props) {
                             }}
                         />
                     </Col>
+                    <Col>
+                        <Input
+                            placeholder='计划ID'
+                            allowClear
+                            onBlur={(e) => {
+                                let value = e.target.value
+                                getList({ pageNum: 1, pageSize: 20, campaignId: value })
+                            }}
+                            onKeyDownCapture={(e: any) => {
+                                let key = e.key
+                                if (key === 'Enter') {
+                                    let value = e.target.value
+                                    getList({ pageNum: 1, pageSize: 20, campaignId: value })
+                                }
+                            }}
+                            onChange={(e) => {
+                                let value = e.target.value
+                                if (!value) {
+                                    getList({ pageNum: 1, pageSize: 20, campaignId: value })
+                                }
+                            }}
+                        />
+                    </Col>
                     <Col>
                         <Select placeholder='推广目标选择' style={{ minWidth: 200 }} showSearch filterOption={(input: any, option: any) =>
                             (option!.children as unknown as string).toLowerCase().includes(input.toLowerCase())

+ 27 - 3
src/pages/launchSystemNew/adq/creative/index.tsx

@@ -30,20 +30,21 @@ type Props = {
     }) => void
 }
 function Creative(props: Props) {
-    let { accountId, adAccountId,userId,tableIdClick } = props
+    let { accountId, adAccountId,userId,tableIdClick ,queryParmas} = props
     // api方法
     const listAjax = useAjax((params) => getAdqAdcreativeList(params), { formatResult: true })
     const syncAjax = useAjax((adAccountId) => putAdqTargetingSyncAll(adAccountId))
     console.log('创意=====》')
     useEffect(() => {
-        getList({ pageNum: 1, pageSize: 20 })
-    }, [accountId,userId])
+        getList({ pageNum: 1, pageSize: 20,...queryParmas })
+    }, [accountId,userId,queryParmas])
     // 获取列表
     const getList = useCallback((params: {
         pageNum: number;
         pageSize: number;
         accountId?: string;
         adcreativeName?: string;
+        adcreativeId?: string;
     }) => {
         if (!params.adcreativeName || params.adcreativeName !== listAjax?.params[0]?.adcreativeName) {
             !params.adcreativeName && delete params.adcreativeName
@@ -100,6 +101,29 @@ function Creative(props: Props) {
                             }}
                         />
                     </Col>
+                    <Col>
+                        <Input
+                            placeholder='创意ID'
+                            allowClear
+                            onBlur={(e) => {
+                                let value = e.target.value
+                                getList({ pageNum: 1, pageSize: 20, adcreativeId: value })
+                            }}
+                            onKeyDownCapture={(e: any) => {
+                                let key = e.key
+                                if (key === 'Enter') {
+                                    let value = e.target.value
+                                    getList({ pageNum: 1, pageSize: 20, adcreativeId: value })
+                                }
+                            }}
+                            onChange={(e) => {
+                                let value = e.target.value
+                                if (!value) {
+                                    getList({ pageNum: 1, pageSize: 20, adcreativeId: value })
+                                }
+                            }}
+                        />
+                    </Col>
                     <Col>
                         <Select placeholder='推广目标选择' style={{ minWidth: 200 }} showSearch filterOption={(input: any, option: any) =>
                             (option!.children as unknown as string).toLowerCase().includes(input.toLowerCase())

+ 11 - 4
src/pages/launchSystemNew/adq/creative/tableConfig.tsx

@@ -1,4 +1,4 @@
-import { LinkPageTypeEnum, PromotedObjectType } from '@/services/launchAdq/enum'
+import { AdcreativeTemplateEnum, LinkPageNameTypeEnum, LinkPageTypeEnum, PromotedObjectType } from '@/services/launchAdq/enum'
 import React from 'react'
 function tableConfig(tableIdClick: (props: {
     activeKey: string,
@@ -73,7 +73,7 @@ function tableConfig(tableIdClick: (props: {
             title: '创意名称',
             dataIndex: 'adcreativeName',
             key: 'adcreativeName',
-            width: 250,
+            width: 350,
             align: 'center',
         },
         // {
@@ -224,10 +224,13 @@ function tableConfig(tableIdClick: (props: {
         //     align: 'center'
         // },
         {
-            title: '创意形式ID',
+            title: '创意形式',
             dataIndex: 'adcreativeTemplateId',
             key: 'adcreativeTemplateId',
             align: 'center',
+            render:(a: string | number)=>{
+                return AdcreativeTemplateEnum[a]
+            }
         },
         // {
         //     title: '是否开启自动版位功能',
@@ -253,7 +256,10 @@ function tableConfig(tableIdClick: (props: {
             key: 'linkNameType',
             align: 'center',
             render: (a: any, b: any) => {
-                return b.linkNameType || b.linkPageType ? '开' : '关'
+                return b.linkNameType || b.linkPageType ? <div>
+                    {b.linkNameType && <div><span style={{ color: "#5a5a5a" }}>{LinkPageNameTypeEnum[b.linkNameType]}</span></div>}
+                    {b.linkPageType && <div><span style={{ color: "#5a5a5a" }}>{LinkPageTypeEnum[b.linkPageType]}</span></div>}
+                </div> : '关'
             }
         },
         // {
@@ -297,6 +303,7 @@ function tableConfig(tableIdClick: (props: {
             dataIndex: 'createdTime',
             key: 'createdTime',
             align: 'center',
+            width:150
         },
     ]
 }

+ 43 - 14
src/pages/launchSystemNew/adq/index.tsx

@@ -28,13 +28,13 @@ function Adq() {
     const [activeKey, setActiveKey] = useState('1')
     const [userId, setUserId] = useState<any>(userInfo?.userId?.toString())
     const [selectedArr, setSelectedArr] = useState([])
-    const [queryParmas, setQueryParmas] = useState({
-        accountId: '',//账户ID
-        campaignId: '',//计划ID
-        adgroupId: '',//广告ID
-        adcreativeId: '',//创意ID
-        pageId: '',//落地页ID
-        targetingId: '',//定向ID
+    const [queryParmas, setQueryParmas] = useState<any>({
+        accountId: undefined,//账户ID
+        campaignId: undefined,//计划ID
+        adgroupId: undefined,//广告ID
+        adcreativeId: undefined,//创意ID
+        pageId: undefined,//落地页ID
+        targetingId: undefined,//定向ID
     })
     const [idS, setIds] = useState({//需要用到的accountId,adAccountId
         accountId: '',
@@ -42,7 +42,8 @@ function Adq() {
     })
     // 点击table中的ID添加对应条件
     const tableIdClick = useCallback((props: {
-        activeKey: string, parma: {
+        activeKey: string,
+        parma: {
             accountId?: string,//账户ID
             campaignId?: string,//计划ID
             adgroupId?: string,//广告ID
@@ -52,9 +53,9 @@ function Adq() {
         }
     }) => {
         // 暂时注释不开放
-        // let { activeKey, parma } = props
-        // setQueryParmas({ ...queryParmas, ...parma })
-        // setActiveKey(activeKey)
+        let { activeKey, parma } = props
+        setQueryParmas({ ...queryParmas, ...parma })
+        setActiveKey(activeKey)
 
     }, [queryParmas, activeKey])
     // 获取组员
@@ -70,7 +71,7 @@ function Adq() {
                     }
                     if (item?.value) {
                         obj['childrenarr'] = item?.value?.map(item => {
-                            return { key: item.accountId + '_' + item.id, label: item.accountId }
+                            return { key: item.accountId + '_' + item.id, label: item?.remark ? item.accountId + '_' + item?.remark : item.accountId }
                         })
                     }
                     useAll.push(obj)
@@ -103,10 +104,38 @@ function Adq() {
             let em: any = document.getElementById('myMenus')
             console.log(topEq)
             if (em) {
-                em.scrollTop = (52-4) * topEq
+                em.scrollTop = (52 - 4) * topEq
             }
         }
     }, [userId, userAll])
+    //判定是否从任务列表跳转过来
+    useEffect(()=>{
+        let data = sessionStorage.getItem('adqQuery')
+        if(data){
+            let obj = JSON.parse(data)
+            Object.keys(obj).forEach(key=>{
+                switch(key){
+                    case 'accountId':
+                        setQueryParmas(obj)
+                        setActiveKey('1')
+                        break
+                    case 'campaignId':
+                        setQueryParmas(obj)
+                        setActiveKey('2')
+                        break
+                    case 'adgroupId':
+                        setQueryParmas(obj)
+                        setActiveKey('3')
+                        break
+                    case 'adcreativeId':
+                        setQueryParmas(obj)
+                        setActiveKey('4')
+                        break
+                }
+            })
+            sessionStorage.removeItem('adqQuery')
+        }
+    },[])
     return <Row style={{ position: 'relative' }}>
         <Col style={{ height: '100%', minHeight: 'calc(100vh - 100px)', overflowY: 'auto', position: 'absolute', left: 0, top: 0, bottom: 0, width: 150, background: '#fff' }}>
             <Select
@@ -118,7 +147,7 @@ function Adq() {
                 }
 
                 } allowClear onChange={(value: any) => {
-                    if(value){
+                    if (value) {
                         setUserId(value.toString())
                     }
                 }}>

+ 2 - 1
src/pages/launchSystemNew/components/adModal/index.tsx

@@ -51,6 +51,7 @@ const AdModal: React.FC<Props> = (props) => {
     const handleOk = () => {
         if (selectedRowKeys?.length) {
             if (sysAdgroupId) {
+                console.log('sysAdgroupIdsysAdgroupId',sysAdgroupId,selectedRowKeys)
                 if (selectedRowKeys?.indexOf(sysAdgroupId) === -1) {
                     onChange && onChange(selectedRowKeys.toString())
                 } else {
@@ -71,7 +72,7 @@ const AdModal: React.FC<Props> = (props) => {
             ajax={sysAdgroupsList}
             dataSource={sysAdgroupsList?.data?.records}
             loading={sysAdgroupsList?.loading}
-            scroll={{ y: 600 }}
+            scroll={{ y: 550 }}
             total={sysAdgroupsList?.data?.total}
             page={sysAdgroupsList?.data?.current}
             pageSize={sysAdgroupsList?.data?.size}

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

@@ -1,13 +1,13 @@
 import { useAjax } from "@/Hook/useAjax"
 import { BidModeEnum, BidStrategyEnum, OptimizationGoalEnum, PromotedObjectType, SiteSetEnum } from "@/services/launchAdq/enum"
 import { getSysAdgroupsInfo } from "@/services/launchAdq/localAd"
-import { EyeOutlined } from "@ant-design/icons"
 import { Popover, Spin } from "antd"
 import React, { useState } from "react"
 import style from '../targetingPopover/index.less'
 
 interface Props {
-    id: number
+    id: number,
+    name: string
 }
 
 /**
@@ -17,7 +17,7 @@ interface Props {
 const AdPopover: React.FC<Props> = (props) => {
 
     /*************************/
-    const { id } = props
+    const { id, name } = props
     const [visible, setVisible] = useState<boolean>(false)
 
     const getSysAdgroups = useAjax((params) => getSysAdgroupsInfo(params))
@@ -55,7 +55,7 @@ const AdPopover: React.FC<Props> = (props) => {
         onVisibleChange={handleVisibleChange}
     >
         {/* 查看广告 */}
-        <a style={{ color: '#1890ff', fontSize: 12 }}><EyeOutlined /></a>
+        <a style={{ color: '#1890ff', fontSize: 12 }}>{name || id}</a>
     </Popover>
 }
 

+ 4 - 3
src/pages/launchSystemNew/components/adcreativePopover/index.tsx

@@ -8,7 +8,8 @@ import style from '../targetingPopover/index.less'
 
 
 interface Props {
-    id: number
+    id: number,
+    name: string
 }
 /**
  * 表格查看创意基本信息
@@ -17,7 +18,7 @@ interface Props {
 const AdcreativePopover: React.FC<Props> = (props) => {
 
     /*************************/
-    const { id } = props
+    const { id, name } = props
     const [visible, setVisible] = useState<boolean>(false)
 
     const getSysAdcreative = useAjax((params) => getSysAdcreativeInfo(params))
@@ -42,7 +43,7 @@ const AdcreativePopover: React.FC<Props> = (props) => {
         onVisibleChange={handleVisibleChange}
     >
         {/* 查看创意 */}
-        <a style={{ color: '#1890ff', fontSize: 12 }}><EyeOutlined /></a>
+        <a style={{ color: '#1890ff', fontSize: 12 }}>{name || id}</a>
     </Popover>
 }
 

+ 144 - 0
src/pages/launchSystemNew/components/addGroup/index.tsx

@@ -0,0 +1,144 @@
+import { PlusOutlined } from "@ant-design/icons"
+import { Button, Form, Input, message, Modal, Select, Table } from "antd"
+import React, { useEffect, useState } from "react"
+import { useModel } from "umi"
+import columnsAdd from "./tableConfigAdd"
+
+
+interface Props {
+    pitcherData: any[],
+    onChange: () => void
+}
+/**
+ * 新增媒体账户组
+ * @returns 
+ */
+const KEY = 'ADQUSERS'
+const AddGroup: React.FC<Props> = (props) => {
+
+    /**********************/
+    const { pitcherData, onChange } = props
+    const [visible, setVisible] = useState<boolean>(false)
+    const [addVisible, setAddVisible] = useState<boolean>(false)
+    const [pitcherDB, setPitcherDB] = useState<any[]>([])
+    const [initialValues, setInitialValues] = useState<any>({})
+
+    const [form] = Form.useForm()
+    const { currentUser: { userId } }: any = useModel('@@initialState', model => ({ currentUser: model.initialState?.currentUser }))
+    /**********************/
+    // 进入查找库
+    useEffect(() => {
+        getList()
+    }, [])
+
+    // 
+    const getList = () => {
+        let data = localStorage.getItem(KEY + userId)
+        if (data) {
+            setPitcherDB(JSON.parse(data))
+        }
+        onChange && onChange()
+    }
+
+    /** 确定新增 */
+    const handleOk = async () => {
+        form.submit()
+        let data = await form.validateFields()
+        console.log(data)
+        let length = pitcherDB.length
+        if (Object.keys(initialValues).length > 0) { // 修改
+            let newPitcherDB = pitcherDB.map((item: { id: number }) => {
+                if (initialValues.id === item.id) {
+                    return { ...data, id: initialValues.id, users: data.pitcher?.map((str: string) => str.split('_')[1]), ids: data.pitcher?.map((str: string) => str.split('_')[0]) }
+                }
+                return item
+            })
+            localStorage.setItem(KEY + userId, JSON.stringify(newPitcherDB))
+            message.success('修改成功')
+        } else { // 新增
+            data.id = length > 0 ? pitcherDB[length - 1].id + 1 : 1
+            if (pitcherDB?.some((item: { name: string }) => item.name === data?.name)) {
+                message.error('组名重复,请重新输入')
+                return
+            }
+            let newData = data
+            newData = { ...data, users: data.pitcher?.map((str: string) => str.split('_')[1]), ids: data.pitcher?.map((str: string) => str.split('_')[0]) }
+            pitcherDB.push(newData)
+            localStorage.setItem(KEY + userId, JSON.stringify(pitcherDB))
+            message.success('新增成功')
+        }
+        getList()
+        setAddVisible(false)
+        setInitialValues({})
+        form.resetFields()
+    }
+
+    /** 删除 */
+    const del = (id: number) => {
+        let newpitcherDB = pitcherDB.filter((item: { id: number }) => item.id !== id)
+        localStorage.setItem(KEY + userId, JSON.stringify(newpitcherDB?.map((item: { id: number }, index: number) => ({ ...item, id: index + 1 }))))
+        getList()
+        message.success('删除成功')
+    }
+
+    /** 修改 */
+    const edit = (value: any) => {
+        setInitialValues(value)
+        form.resetFields()
+        setAddVisible(true)
+    }
+
+    /** 清空 */
+    const clear = () => {
+        setInitialValues({})
+        form.resetFields()
+    }
+
+    return <div>
+        <Button type='primary' onClick={() => { setVisible(true) }}><PlusOutlined />新增媒体账户组</Button>
+
+        {visible && <Modal title="媒体账号组" footer={null} visible={visible} width={900} onCancel={() => { setVisible(false) }}>
+            <Button type='primary' onClick={() => { setAddVisible(true) }} style={{ marginBottom: 10 }}><PlusOutlined />新增</Button>
+            <Table columns={columnsAdd(del, edit)} dataSource={pitcherDB} size='small' bordered rowKey={(e) => { return e.id }} />
+        </Modal>}
+
+        {addVisible && <Modal title="新增媒体账号组" visible={visible} width={450} onOk={() => handleOk()} onCancel={() => { setAddVisible(false); clear() }}>
+            <Form
+                name="basic"
+                form={form}
+                labelCol={{ span: 4 }}
+                wrapperCol={{ span: 20 }}
+                autoComplete="off"
+                initialValues={initialValues}
+            >
+                <Form.Item label="组名" name="name" rules={[{ required: true, message: '请输入组名!' }]}>
+                    <Input placeholder="请输入组名" max={6} disabled={Object.keys(initialValues).length > 0} />
+                </Form.Item>
+                <Form.Item label="账号" name="pitcher" rules={[{ required: true, message: '请选择账号!' }]}>
+                    <Select
+                        placeholder='请输账号ID'
+                        showArrow
+                        showSearch
+                        allowClear
+                        maxTagCount={3}
+                        filterOption={(input: any, option: any) => {
+                            return option!.children?.toString().toLowerCase().includes(input.toLowerCase())
+                        }}
+                        mode="multiple"
+                    >
+                        {
+                            pitcherData?.map((list: any, eq: number) => {
+                                return <Select.Option key={list?.id} value={list?.id + '_' + list.accountId}>
+                                    {list.remark ? list.accountId + '——' + list.remark : list.accountId}
+                                </Select.Option>
+                            })
+                        })
+                    </Select>
+                </Form.Item>
+            </Form>
+        </Modal>}
+    </div>
+}
+
+
+export default React.memo(AddGroup)

+ 55 - 0
src/pages/launchSystemNew/components/addGroup/tableConfigAdd.tsx

@@ -0,0 +1,55 @@
+import { Popconfirm, Space } from "antd";
+import React from "react";
+
+function columnsAdd(del: (id: number) => void, edit: (value: any) => void) {
+
+    const columns: any = [
+        {
+            title: '操作',
+            dataIndex: 'cz',
+            key: 'cz',
+            align: 'center',
+            width: 90,
+            render: (a: any[], b: any) => {
+                return <Space>
+                    <a style={{ fontSize: 12 }} onClick={() => edit(b)}>修改</a>
+                    <Popconfirm
+                        title="确定删除?"
+                        onConfirm={() => { del(b.id) }}
+                        okText="是"
+                        cancelText="否"
+                    >
+                        <a style={{ fontSize: 12, color: 'red' }}>删除</a>
+                    </Popconfirm>
+                </Space>
+            }
+        },
+        {
+            title: '序号',
+            dataIndex: 'id',
+            key: 'id',
+            align: 'center',
+            width: 50
+        },
+        {
+            title: '组名',
+            dataIndex: 'name',
+            key: 'name',
+            align: 'center',
+            width: 85,
+            ellipsis: true
+        },
+        {
+            title: '账号',
+            dataIndex: 'users',
+            key: 'users',
+            render: (a: any[]) => {
+                return <span>{a?.toString()}</span>
+            }
+        }
+    ];
+
+    return columns
+}
+
+export default columnsAdd

+ 40 - 122
src/pages/launchSystemNew/components/addLandingPage/content.ts

@@ -1,4 +1,4 @@
-import { Img, TopImg, TopSlider, TopVideo, Text, GhButton, WxAutoButton } from "../../req"
+import { Img, TopImg, TopSlider, TopVideo, Text, GhButton, WxAutoButton, Floatbutton } from "../../req"
 
 // 头部内容
 export const topsliderContent: TopSlider = {
@@ -27,6 +27,45 @@ export const topvideoNewContent: TopVideo = {
     outerStyle: 0
 }
 
+// 悬浮组件
+export const floatbuttonContent: Floatbutton = {
+    elementType: 'FLOAT_BUTTON',
+    titleColor: "#171717",
+    descColor: "#4c4c4c",
+    title: "",
+    desc: "",
+    styleType: 0,
+    imageUrl: '',
+    appearType: 0,
+    disappearType: 0,
+    componentItem: {
+        elementType: 'GH',
+        btnTitle: '关注公众号',
+        fontColor: '#FFFFFF',
+        btnBgColorTheme: '#07C160',
+        btnFontType: 0,
+        fastFollow: 1,
+    }
+}
+
+
+// 悬浮组件 添加商家微信
+export const floatbuttonBtTypeWxAuto: Omit<WxAutoButton, 'btnBorderColorTheme' | 'useIcon' | 'paddingTop' | 'paddingBottom'> = {
+    elementType: 'ENTERPRISE_WX',
+    btnBgColorTheme: "#07C160",
+    btnFontType: 0,
+    btnTitle: "联系商家",
+    fontColor: "#FFFFFF",
+}
+export const floatbuttonBtTypeGh: Omit<GhButton, 'btnBorderColorTheme' | 'useIcon' | 'paddingTop' | 'paddingBottom'> = {
+    elementType: 'GH',
+    btnTitle: '关注公众号',
+    fontColor: '#FFFFFF',
+    btnBgColorTheme: '#07C160',
+    btnFontType: 0,
+    fastFollow: 1,
+}
+
 export const topvideoContent = {
     id: 'widget_1625551322566_1',
     widgetTypeV2: 'topvideo',
@@ -846,125 +885,4 @@ export const btModelJumpWxAuto103 = {
     id: "", //"widget_1646279296521_3",
     layoutHeight: "542",
     layoutWidth: "320"
-}
-
-// 悬浮组件 添加商家微信
-export const floatbuttonBtTypeWxAuto = {
-    widgetTypeV2: "enterprise_wx_auto",
-    widgetType: "button",
-    type: "21",
-    name: "添加商家微信",
-    btnTitle: "联系商家",
-    subType: "15",
-    fontSize: "28",
-    fontColor: "#FFFFFF",
-    btnType: "0",
-    btnBgColorTheme: "#07C160",
-    btnBorderColorTheme: "#FFFFFF",
-    btnFontType: "0",
-    btnStyle: "1",
-    cornerRadius: "4",
-    useIcon: "0",
-    mpJumpType: "1",
-    origBtnJumpUrl: "",
-    btnJumpUrl: "",
-    corpid: "",
-    groupid: null,
-    h5_config_id: "",
-    wxapp_config_id: "",
-    qrUrl: "https://wework.qpic.cn/wwpic/402461_L-7_oaL7St6-juF_1649837642/0",
-    needUpdateQrUrl: 0,
-    qrExtInfo: "",
-    serviceType: "1",
-    chatGroupName: "",
-    id: "",
-    layoutHeight: "70",
-    layoutWidth: "160",
-    borderSize: "0",
-    custorGroup: []
-}
-export const floatbuttonBtTypeGh = {
-    widgetTypeV2: "gh",
-    widgetType: "button",
-    type: "21",
-    name: "关注公众号",
-    btnTitle: "关注公众号",
-    subType: "17",
-    fontSize: "28",
-    fontColor: "#FFFFFF",
-    btnType: "0",
-    btnBgColorTheme: "#07C160",
-    btnBorderColorTheme: "#FFFFFF",
-    btnFontType: "0",
-    btnStyle: "1",
-    cornerRadius: "4",
-    useIcon: "0",
-    field21_1: {
-        origBtnJumpUrl: "",
-        wxad_guide_group_id: ""
-    },
-    id: "widget_1652153905113_9",
-    layoutHeight: "70",
-    layoutWidth: "160",
-    borderSize: "0",
-    custorGroup: []
-}
-
-// 悬浮组件
-export const floatbuttonContent = {
-    widgetTypeV2: "floatbutton",
-    widgetType: "float_button",
-    type: "134",
-    name: "悬浮组件",
-    wxad_styleType: "1",
-    onlyShowInTimelineAd: "0",
-    backgroundImg: "",
-    backgroundColor: "#F0F0F0",
-    backgroundColorAlpha: "0.96",
-    backgroundBlurEffect: "1",
-    backgroundBlurEffectColor: "#F0F0F0",
-    backgroundBlurEffectColorAlpha: "0.5",
-    titleColor: "#171717",
-    titleColorAlpha: "1",
-    descColor: "#4c4c4c",
-    descColorAlpha: "0.5",
-    iconUrl: "",
-    imageMd5: "",
-    materialId: "",
-    title: "",
-    desc: "",
-    isFullClickable: "1",
-    appearPaddingTop: "0",
-    appearPaddingBottom: "0",
-    paddingTop: 0,
-    paddingBottom: 0,
-    paddingRight: 0,
-    paddingLeft: 0,
-    id: "widget_1652076096083_2",
-    componentItem: {
-        widgetTypeV2: "gh",
-        widgetType: "button",
-        type: "21",
-        name: "关注公众号",
-        btnTitle: "关注公众号",
-        subType: "17",
-        fontSize: "28",
-        fontColor: "#FFFFFF",
-        btnType: "0",
-        btnBgColorTheme: "#07C160",
-        btnBorderColorTheme: "#FFFFFF",
-        btnFontType: "0",
-        btnStyle: "1",
-        cornerRadius: "4",
-        useIcon: "0",
-        field21_1: {
-            origBtnJumpUrl: "",
-            wxad_guide_group_id: ""
-        },
-        id: "widget_1652153905113_9",
-        layoutHeight: "70",
-        layoutWidth: "160",
-        borderSize: "0",
-        custorGroup: []
-    }
 }

+ 92 - 63
src/pages/launchSystemNew/components/addLandingPage/index.tsx

@@ -90,7 +90,7 @@ function AddLandingPage(props: Props) {
         if (id) {
             get.run({ sysMediaId: id, mediaType: 'PAGE' }).then(res => {
                 if (res) {
-                    const { pageSpecsList, shareContentSpec } = res
+                    const { pageSpecsList, shareContentSpec, globalSpec } = res
                     dispatch({ type: 'setPageBackColor', params: { pageBackColor: pageSpecsList[0]?.bgColor } })
                     let pageElementsSpecList = pageSpecsList[0]?.pageElementsSpecList
                     dispatch({
@@ -110,14 +110,31 @@ function AddLandingPage(props: Props) {
                     })
                     setShareDesc(() => shareContentSpec?.shareTitle || '')
                     setShareTittle(() => shareContentSpec?.shareDescription || '')
-                    // global = global?.map((item: any) => ({ ...item, comptActive: false }))
-                    // dispatchGlobal({ type: "setConItem", params: { componentItem: global || [] } })
+                    if (globalSpec && Object.keys(globalSpec).length > 0) {
+                        let globalElementsSpecList = globalSpec.globalElementsSpecList
+                        let newComponentItem = globalElementsSpecList?.map((item: { elementType: string }) => {
+                            let typeKey = getTypeKey(item.elementType)
+                            let { elementType, ...data } = item[typeKey]
+                            let typeKey1 = getTypeKey(elementType)
+                            let componentItem: any = data[typeKey1]
+                            if (componentItem) {
+                                componentItem['elementType'] = elementType
+                            }
+                            data.componentItem = componentItem
+                            data.elementType = item.elementType
+                            delete data[typeKey1]
+                            return data
+                        })
+                        dispatchGlobal({ type: "setConItem", params: { componentItem: newComponentItem || [] } })
+                    }
                 }
             })
         } else {
             // dispatch({ type: 'init', params: { elementType: 'empty' } })
         }
     }, [id])
+    console.log('componentItem------>', componentItem);
+
 
     const config = {
         title: '警告!',
@@ -175,8 +192,7 @@ function AddLandingPage(props: Props) {
             }
         } else if (selectData?.elementType === 'FLOAT_BUTTON') {
             setIsFootlock(() => false)
-            init({ mediaType: 'VIDEO', cloudSize: { minWidth: '96', maxWidth: '96', minHeight: '96', maxHeight: '96', minMediaSize: 0, maxMediaSize: 307200 } })
-            setImgSize(() => ({ minWidth: '96', maxWidth: '96', minHeight: '96', maxHeight: '96', minMediaSize: 0, maxMediaSize: 307200, mediaType: 'IMG' }))
+            init({ mediaType: 'IMG', cloudSize: [[{ relation: '=', width: 96, height: 96 }]], maxSize: 300 * 1024 })
         }
     }, [content])
 
@@ -261,13 +277,13 @@ function AddLandingPage(props: Props) {
         let newCon = content?.map((item: any) => {
             return { ...item, comptActive: false }
         })
-        let newConItem = componentItem?.map((item: { widgetTypeV2: string }) => {
+        let newConItem = componentItem?.map((item: { elementType: string }) => {
             return { ...item, comptActive: false }
         })
         setImgTextButtonShow(false)
         if (index === 99999) {
-            newConItem = newConItem?.map((item: { widgetTypeV2: string }) => {
-                if (item.widgetTypeV2 === 'floatbutton') {
+            newConItem = newConItem?.map((item: { elementType: string }) => {
+                if (item.elementType === 'FLOAT_BUTTON') {
                     return { ...item, comptActive: true }
                 }
                 return item
@@ -342,7 +358,7 @@ function AddLandingPage(props: Props) {
         setImgTextButtonShow(false)
         if (index === 99999) { // 删除悬浮组件
             let newContentItem = JSON.parse(JSON.stringify(componentItem))
-            newContentItem = newContentItem?.filter((item: { widgetTypeV2: string }) => item.widgetTypeV2 !== 'floatbutton')
+            newContentItem = newContentItem?.filter((item: { elementType: string }) => item.elementType !== 'FLOAT_BUTTON')
             dispatchGlobal({ type: 'setConItem', params: { componentItem: JSON.parse(JSON.stringify(newContentItem)) } })
         } else {
             let newContent = JSON.parse(JSON.stringify(content))
@@ -927,24 +943,24 @@ function AddLandingPage(props: Props) {
         if (selectIndex !== -1) {
             let selectCon = oldContent[selectIndex]
             // 设置悬浮窗 转化按钮
-            if (key === 'componentItem' && (value === 'gh' || value === 'enterprise_wx_auto')) {
-                if (value === 'gh') {
+            if (key === 'componentItem' && (value === 'GH' || value === 'ENTERPRISE_WX')) {
+                if (value === 'GH') {
                     selectCon[key] = floatbuttonBtTypeGh
-                } else if (value === 'enterprise_wx_auto') {
+                } else if (value === 'ENTERPRISE_WX') {
                     selectCon[key] = floatbuttonBtTypeWxAuto
                 }
             } else {
                 if (!isDel) {
                     selectCon[key] = value
-                    if (key === 'wxad_styleType') {
-                        if (value === '1') {
-                            selectCon['iconUrl'] = ""
+                    if (key === 'styleType') {
+                        if (value === 0) {
+                            selectCon['imageUrl'] = ""
                             selectCon['desc'] = selectCon?.desc || ""
-                        } else if (value === '2') {
-                            delete selectCon['iconUrl']
+                        } else if (value === 1) {
+                            delete selectCon['imageUrl']
                             selectCon['desc'] = selectCon?.desc || ""
-                        } else if (value === '3') {
-                            delete selectCon['iconUrl']
+                        } else if (value === 2) {
+                            delete selectCon['imageUrl']
                             delete selectCon['desc']
                         }
                         selectCon[key] = value
@@ -953,7 +969,6 @@ function AddLandingPage(props: Props) {
                     delete selectCon[key]
                 }
             }
-
             dispatchGlobal({ type: 'setConItem', params: { componentItem: JSON.parse(JSON.stringify(oldContent)) } })
         }
     }
@@ -965,10 +980,10 @@ function AddLandingPage(props: Props) {
             selectCon = componentItem?.find((item: { comptActive: boolean }) => item.comptActive)
         }
         if (selectCon) {
-            let { elementType, adLocation, outerStyle, imageUrlList, pureImageUrl, imageUrl, text, fontColor, fontSize, fontStyle, textAlignment,
+            let { elementType, adLocation, outerStyle, imageUrlList, imageUrl, text, fontColor, fontSize, fontStyle, textAlignment,
                 paddingTop, paddingBottom, fastFollow, btnTitle, btnFontType, btnBorderColorTheme, btnBgColorTheme, useIcon,
                 styleType, type, initHeight, outerUseTopMaterial, componentCount, activeIndex, componentGroupList, origBtnJumpUrl,
-                layoutItems, borderColor, bgColor, wxad_align, wxad_styleType, iconUrl, title, desc, titleColor, descColor, componentItem, appearPaddingTop, appearPaddingBottom } = selectCon
+                layoutItems, borderColor, bgColor, title, desc, titleColor, descColor, componentItem, appearType, disappearType } = selectCon
             let descType = "text"
             let jumpMode = "btn_jump"
             let shelfnewImgData: { pureImageUrl: string } = { pureImageUrl: '' }  // 图片信息
@@ -1728,7 +1743,7 @@ function AddLandingPage(props: Props) {
                                                         </>} */}
                                                     </div>
                                                         :
-                                                        elementType === 'floatbutton' ? <div style={{ height: '100%' }}>
+                                                        elementType === 'FLOAT_BUTTON' ? <div style={{ height: '100%' }}>
                                                             <div className={`widget ${imgTextButtonShow ? 'widget_back' : ''}`}>
                                                                 <div className="caption section">
                                                                     <div className="caption-title">悬浮按钮</div>
@@ -1744,22 +1759,22 @@ function AddLandingPage(props: Props) {
                                                                     <div className="adui-form-item">
                                                                         <div className="adui-form-label">卡片样式</div>
                                                                         <div className="adui-form-control">
-                                                                            <Radio.Group onChange={(e) => { setGlobalComponentItem('wxad_styleType', e.target.value) }} className="floatType" value={wxad_styleType}>
-                                                                                <Radio.Button value='1'>
+                                                                            <Radio.Group onChange={(e) => { setGlobalComponentItem('styleType', e.target.value) }} className="floatType" value={styleType}>
+                                                                                <Radio.Button value={0}>
                                                                                     <div className='floatTypeInner'>
                                                                                         <i className="floatTypeAvatar"></i>
                                                                                         <i className="floatTypeText_two"></i>
                                                                                         <i className="floatTypeButton"></i>
                                                                                     </div>
                                                                                 </Radio.Button>
-                                                                                <Radio.Button value='2'>
+                                                                                <Radio.Button value={1}>
                                                                                     <div className='floatTypeInner'>
                                                                                         <i style={{ display: 'inline-block', height: 12 }}></i>
                                                                                         <i className="floatTypeText_two"></i>
                                                                                         <i className="floatTypeButton"></i>
                                                                                     </div>
                                                                                 </Radio.Button>
-                                                                                <Radio.Button value='3'>
+                                                                                <Radio.Button value={2}>
                                                                                     <div className='floatTypeInner'>
                                                                                         <i style={{ display: 'inline-block', height: 12 }}></i>
                                                                                         <i className="floatTypeText_one"></i>
@@ -1772,12 +1787,12 @@ function AddLandingPage(props: Props) {
                                                                 </div>
                                                                 <div className="form section">
                                                                     <div className="form-caption">内容设置</div>
-                                                                    {wxad_styleType === '1' && <div className="adui-form-item" style={{ alignItems: 'flex-start' }}>
+                                                                    {styleType === 0 && <div className="adui-form-item" style={{ alignItems: 'flex-start' }}>
                                                                         <div className="adui-form-label">图片</div>
                                                                         <div className="adui-form-control">
-                                                                            <div className={`upload-img-item ${iconUrl ? 'upload-img-item_uploaded' : ''}`}>
+                                                                            <div className={`upload-img-item ${imageUrl ? 'upload-img-item_uploaded' : ''}`}>
                                                                                 {
-                                                                                    iconUrl ? <div className="upload-img-item-inner" style={{ backgroundImage: `url(${iconUrl ? iconUrl : ""})` }}>
+                                                                                    imageUrl ? <div className="upload-img-item-inner" style={{ backgroundImage: `url(${imageUrl ? imageUrl : ""})` }}>
                                                                                         <div className='upload-img-item-action' onClick={() => { setCcType(5); setSelectImgVisible(true); }}>
                                                                                             <RetweetOutlined />
                                                                                         </div>
@@ -1800,7 +1815,7 @@ function AddLandingPage(props: Props) {
                                                                         </div>
                                                                     </div>
 
-                                                                    {(wxad_styleType === '1' || wxad_styleType === '2') && <div className="adui-form-item" style={{ alignItems: 'flex-start', marginBottom: 10 }}>
+                                                                    {(styleType === 1 || styleType === 0) && <div className="adui-form-item" style={{ alignItems: 'flex-start', marginBottom: 10 }}>
                                                                         <div className="adui-form-label" style={{ marginTop: 6 }}>描述</div>
                                                                         <div className="adui-form-control">
                                                                             <Input.TextArea placeholder="请输入描述" onChange={(e) => { setGlobalComponentItem('desc', e.target.value?.replace(/\r|\n/ig, "")) }} value={desc} showCount maxLength={14} autoSize />
@@ -1812,7 +1827,7 @@ function AddLandingPage(props: Props) {
                                                                             <Space><ColorPicker onColor={(color: string) => { setGlobalComponentItem('titleColor', color) }} color={titleColor}></ColorPicker> <div className="colorShow">{titleColor}</div></Space>
                                                                         </div>
                                                                     </div>
-                                                                    {(wxad_styleType === '1' || wxad_styleType === '2') && <div className="adui-form-item" style={{ alignItems: 'center', marginBottom: 10 }}>
+                                                                    {(styleType === 1 || styleType === 0) && <div className="adui-form-item" style={{ alignItems: 'center', marginBottom: 10 }}>
                                                                         <div className="adui-form-label" style={{ marginTop: 6 }}>描述字色</div>
                                                                         <div className="adui-form-control">
                                                                             <Space><ColorPicker onColor={(color: string) => { setGlobalComponentItem('descColor', color) }} color={descColor}></ColorPicker> <div className="colorShow">{descColor}</div></Space>
@@ -1825,18 +1840,18 @@ function AddLandingPage(props: Props) {
                                                                     <div className="adui-form-item">
                                                                         <div className="adui-form-label">出现方式</div>
                                                                         <div className="adui-form-control">
-                                                                            <Radio.Group onChange={(e) => { setGlobalComponentItem('appearPaddingTop', e.target.value) }} value={Number(appearPaddingTop)}>
+                                                                            <Radio.Group onChange={(e) => { setGlobalComponentItem('appearType', e.target.value) }} value={appearType}>
                                                                                 <Radio value={0}>进入页面时出现</Radio>
-                                                                                <Radio value={100}>滑动页面时出现</Radio>
+                                                                                <Radio value={1}>滑动页面时出现</Radio>
                                                                             </Radio.Group>
                                                                         </div>
                                                                     </div>
                                                                     <div className="adui-form-item">
                                                                         <div className="adui-form-label">消失方式</div>
                                                                         <div className="adui-form-control">
-                                                                            <Radio.Group onChange={(e) => { setGlobalComponentItem('appearPaddingBottom', e.target.value) }} value={Number(appearPaddingBottom)}>
+                                                                            <Radio.Group onChange={(e) => { setGlobalComponentItem('disappearType', e.target.value) }} value={disappearType}>
                                                                                 <Radio value={0}>不消失</Radio>
-                                                                                <Radio value={80}>滑至页面底部时消失</Radio>
+                                                                                <Radio value={1}>滑至页面底部时消失</Radio>
                                                                             </Radio.Group>
                                                                         </div>
                                                                     </div>
@@ -1850,16 +1865,16 @@ function AddLandingPage(props: Props) {
                                                                 <div className="form section">
                                                                     <div className="form-caption">按钮类型</div>
                                                                     <div className="adui-form-item" style={{ alignItems: 'center' }}>
-                                                                        <Select style={{ width: 180 }} className="aside-select" dropdownClassName="aside-select" onChange={(e) => { setGlobalComponentItem('componentItem', e) }} value={componentItem?.widgetTypeV2} size="small">
-                                                                            <Option value="gh"><FollowAcc />关注公众号</Option>
-                                                                            <Option value="enterprise_wx_auto"><WxAutoSvg />添加商家微信</Option>
+                                                                        <Select style={{ width: 180 }} className="aside-select" dropdownClassName="aside-select" onChange={(e) => { setGlobalComponentItem('componentItem', e) }} value={componentItem?.elementType} size="small">
+                                                                            <Option value="GH"><FollowAcc />关注公众号</Option>
+                                                                            {/* <Option value="ENTERPRISE_WX"><WxAutoSvg />添加商家微信</Option> */}
                                                                         </Select>
                                                                     </div>
                                                                 </div>
-                                                                {componentItem?.widgetTypeV2 === 'gh' ? <>
+                                                                {componentItem?.elementType === 'GH' ? <>
                                                                     <div className="form section">
                                                                         <Space>
-                                                                            <Switch size="small" checked={componentItem?.subType === '17' ? true : false} onChange={(e) => { setGlobalComponentItem('componentItem', { ...componentItem, subType: e ? '17' : '1' }) }} />
+                                                                            <Switch size="small" checked={componentItem?.fastFollow} onChange={(e) => { setGlobalComponentItem('componentItem', { ...componentItem, fastFollow: e ? 1 : 0 }) }} />
                                                                             一键关注
                                                                             <Tooltip placement="top" title={'唤起公众号简介的半屏面板,点击其中按钮直接关注公众号'}>
                                                                                 <QuestionCircleOutlined />
@@ -1976,9 +1991,12 @@ function AddLandingPage(props: Props) {
                 }
             }
         } else if (scType === 5) { // 设置悬浮组件 
+            let newConItem = JSON.parse(JSON.stringify(componentItem))
+            let selectIndex = newConItem?.findIndex((item: Content) => item.comptActive)
+            let oldContent = newConItem
             if (selectIndex !== -1) {
                 let selectCon = oldContent[selectIndex]
-                selectCon['iconUrl'] = value[0]?.content
+                selectCon['imageUrl'] = value[0]?.url
                 dispatchGlobal({ type: 'setConItem', params: { componentItem: JSON.parse(JSON.stringify(oldContent)) } })
             }
         }
@@ -2055,9 +2073,9 @@ function AddLandingPage(props: Props) {
         })
         if (componentItem?.length > 0) {
             let b = componentItem?.every((item: any) => {
-                if (item?.elementType === "floatbutton") {
-                    if (item?.wxad_styleType === '1') {
-                        if (!item?.iconUrl) {
+                if (item?.elementType === "FLOAT_BUTTON") {
+                    if (item?.styleType === 0) {
+                        if (!item?.imageUrl) {
                             message.error('悬浮组件请上传图片')
                             return false
                         }
@@ -2069,7 +2087,7 @@ function AddLandingPage(props: Props) {
                             message.error('悬浮组件请输入描述')
                             return false
                         }
-                    } else if (item?.wxad_styleType === '2') {
+                    } else if (item?.wxad_styleType === 1) {
                         if (!item?.title) {
                             message.error('悬浮组件请输入标题')
                             return false
@@ -2078,20 +2096,12 @@ function AddLandingPage(props: Props) {
                             message.error('悬浮组件请输入描述')
                             return false
                         }
-                    } else if (item?.wxad_styleType === '3') {
+                    } else if (item?.wxad_styleType === 2) {
                         if (!item?.title) {
                             message.error('悬浮组件请输入标题')
                             return false
                         }
                     }
-                    if (item?.componentItem?.widgetTypeV2 === 'enterprise_wx_auto') {
-                        if (item?.componentItem?.custorData && item?.componentItem?.custorData?.length > 0) {
-                            return true
-                        } else {
-                            message.error('请完善悬浮组件客服组内容')
-                            return false
-                        }
-                    }
                 }
                 return true
             })
@@ -2127,6 +2137,25 @@ function AddLandingPage(props: Props) {
             return newItem
         })
 
+        let globalSpec: any = {}
+        if (componentItem?.length > 0) {
+            let globalElementsSpecList = componentItem?.map((item: { elementType: string, comptActive: boolean, componentItem: { elementType: string } }) => {
+                let { elementType, comptActive, componentItem, ...data } = item
+                let typeKey = getTypeKey(elementType);
+                let newItem = { elementType };
+                (data as any).elementType = componentItem.elementType
+                if (componentItem?.elementType) {
+                    let { elementType, ...data1 } = componentItem
+                    let type1Key = getTypeKey(elementType);
+                    data[type1Key] = data1
+                }
+                newItem[typeKey] = data
+                return newItem
+            })
+            globalSpec.globalElementsSpecList = globalElementsSpecList
+        } else {
+            globalSpec = null
+        }
         let pageSpecs = {
             bgColor: pageBackColor,
             pageElementsSpecList: pageContextList
@@ -2140,7 +2169,7 @@ function AddLandingPage(props: Props) {
             belongUser: belongUser === '0' ? false : true,
             sort,
             pageSpecsList: [pageSpecs],
-            globalSpec: null,
+            globalSpec,
             shareContentSpec: {
                 shareTitle: shareTittle,
                 shareDescription: shareDesc
@@ -2234,13 +2263,13 @@ function AddLandingPage(props: Props) {
                             {/* <div {...getDragPropsCon(`JumpLink`)}> <JumpLink /> <span className="my">跳转链接</span> </div> */}
                             {/* <div {...getDragPropsCon(`ENTERPRISE_WX`)}> <WxAutoSvg /> <span className="my">添加商家微信</span> </div> */}
                         </div>
-                        {/* <div className={style.title}>营销组件</div>
-                    <div className={style.assembly}>
-                        <div {...getDragPropsCon(`shelfnew`)}> <ImgText /> <span className="my">图文复合组件</span> </div>
-                        {componentItem?.some((item: { elementType: string }) => item.elementType === 'FLOAT_BUTTON') ?
-                            <div className={style.disabled}> <FloatbuttonSvg /> <span>悬浮组件</span></div> : <div {...getDragPropsCon(`FLOAT_BUTTON`)}> <FloatbuttonSvg /> <span className="my">悬浮组件</span> </div>
-                        }
-                    </div> */}
+                        <div className={style.title}>营销组件</div>
+                        <div className={style.assembly}>
+                            {/* <div {...getDragPropsCon(`shelfnew`)}> <ImgText /> <span className="my">图文复合组件</span> </div> */}
+                            {componentItem?.some((item: { elementType: string }) => item.elementType === 'FLOAT_BUTTON') ?
+                                <div className={style.disabled}> <FloatbuttonSvg /> <span>悬浮组件</span></div> : <div {...getDragPropsCon(`FLOAT_BUTTON`)}> <FloatbuttonSvg /> <span className="my">悬浮组件</span></div>
+                            }
+                        </div>
                     </Col>
                     <Col flex="auto" className={style.center} onClick={installActiveNull}>
 

+ 4 - 4
src/pages/launchSystemNew/components/addLandingPage/sortable.tsx

@@ -255,20 +255,20 @@ export const SortableItemImgText = SortableElement(({ item, click, del, index, d
 
 /** 悬浮组件 */
 export const SortableItemFloatbutton = SortableElement(({ item, click, del }: any) => {
-    let { titleColor, descColor, componentItem, iconUrl, title, desc, wxad_styleType } = item
+    let { titleColor, descColor, componentItem, imageUrl, title, desc, styleType } = item
     return <div className={`compt componentType134 comptFixedBottom ${item.comptActive && 'comptActive'}`} onClick={(e) => { click(e) }}>
         <div className={'componentWrap'}>
             <div className="componentContent">
                 <div className="floatButtonWrapper">
                     <div className="floatButton">
-                        {wxad_styleType === '1' && (iconUrl ? <img src={iconUrl} className="floatButtonAvatar"/> : <div className="floatButtonAvatarPlaceholder"></div>)}
+                        {styleType === 0 && (imageUrl ? <img src={imageUrl} className="floatButtonAvatar"/> : <div className="floatButtonAvatarPlaceholder"></div>)}
                         <div className="floatButtonTexts">
                             <div className="floatButtonTitle" style={{ color: titleColor || 'rgb(23, 23, 23)' }}>{title || '标题'}</div>
-                            {(wxad_styleType === '1' || wxad_styleType === '2' ) && <div className="floatButtonDesc" style={{ color: descColor || 'rgb(76, 76, 76)' }}>{desc || '描述'}</div>}
+                            {(styleType === 1 || styleType === 0 ) && <div className="floatButtonDesc" style={{ color: descColor || 'rgb(76, 76, 76)' }}>{desc || '描述'}</div>}
                         </div>
                         <div className="floatButtonLink" style={{
                             color: componentItem?.fontColor || 'rgb(255,255,255)', 
-                            fontWeight: componentItem?.btnFontType === '0' ? 'normal' : 'bold', 
+                            fontWeight: componentItem?.btnFontType === 0 ? 'normal' : 'bold', 
                             backgroundColor: componentItem?.btnBgColorTheme || 'rgb(7, 193, 96)', 
                             width: ((componentItem?.layoutWidth || 160) / 2) + 'px',
                             textAlign: 'center', 

+ 8 - 12
src/pages/launchSystemNew/components/bathLauCopy/index.tsx

@@ -38,7 +38,8 @@ function BathLauCopy(props: Props) {
     const [sliderImgContent, setSliderImgContent] = useState<{ url: string, width?: number, height?: number }[]>([])  // 保存回填数据
     const [groupIndex, setGroupIndex] = useState<number>(-1)  // 保存正在操作的组 下标
     const [loading, setLoading] = useState<boolean>(false)  // 确定按钮loading
-    const { init, add, get, state: { parentId, belongUser } } = useModel('useLaunchAdq.useBdMediaPup')
+    const { init, get } = useModel('useLaunchAdq.useBdMediaPup')
+    const { state: { parentId, belongUser } } = useModel('useLaunchAdq.useBdMedia')
     const [data, setData] = useState<any>({})
     const [topData, setTopData] = useState<Array<TopImg | TopVideo | TopSlider>>([])  // 顶部素材数据
     const [sort, setSort] = useState<number>(0) // 排序
@@ -105,7 +106,7 @@ function BathLauCopy(props: Props) {
     // 关闭弹窗
     const hideHandle = () => {
         onClose && onClose()
-    }
+    }    
 
     const handleOk = useCallback(() => {
         if (elementType === 'TOP_SLIDER' && !topData?.every((item1: any) => {
@@ -124,31 +125,26 @@ function BathLauCopy(props: Props) {
             message.error('顶部视频组缺少视频')
             return
         }
-
         setLoading(true)
-
-        // let { descContext, name, novelName, title, lastCanvasType, pageContextList, supportInfoType } = data
         let ajax = topData?.map((item: any, index: number) => {
             const { elementType, ...newItem } = item
             let newTopPage = { elementType }
             let typeKey = getTypeKey(elementType)
-            newTopPage[typeKey] = newItem
-            let pageSpecsList: any[] = data?.pageSpecsList
-            pageSpecsList[0].pageElementsSpecList[0] = newTopPage
+            newTopPage[typeKey] = { ...newItem }
+            let pageSpecsList: any[] = JSON.parse(JSON.stringify(data?.pageSpecsList))
+            pageSpecsList[0].pageElementsSpecList[0] = { ...newTopPage }
             let params = {
                 mediaType: 'PAGE',
                 folder: false,
                 parentId,
-                title: `批量复制推广页` + moment().format("YYYYMMDDHHmmss"),
-                pageName: `批量复制推广页` + moment().format("YYYYMMDDHHmmss"),
+                title: `批量复制` + moment().format("YYYYMMDDHHmmss"),
+                pageName: `批量复制` + moment().format("YYYYMMDDHHmmss"),
                 belongUser: belongUser === '0' ? false : true,
                 sort,
                 pageSpecsList,
                 globalSpec: data?.globalSpec,
                 shareContentSpec: data?.shareContentSpec
             }
-
-            console.log('params---->', params);
             return bdSysMediaAdd(params as any)
         })
         Promise.all(ajax).then((res: any) => {

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

@@ -62,7 +62,7 @@ const CreativeModal: React.FC<Props> = (props) => {
             ajax={sysAdcreativeList}
             dataSource={sysAdcreativeList?.data?.data?.records}
             loading={sysAdcreativeList?.loading}
-            scroll={{ y: 400 }}
+            scroll={{ y: 550}}
             total={sysAdcreativeList?.data?.data?.total}
             page={sysAdcreativeList?.data?.data?.current}
             pageSize={sysAdcreativeList?.data?.data?.size}

+ 11 - 4
src/pages/launchSystemNew/components/creativeModal/tableConfig.tsx

@@ -1,5 +1,6 @@
-import { PageTypeEnum, PromotedObjectType } from '@/services/launchAdq/enum'
-function tableConfig():any{
+import { AdcreativeTemplateEnum, LinkPageNameTypeEnum, LinkPageTypeEnum, PageTypeEnum, PromotedObjectType } from '@/services/launchAdq/enum'
+import React from 'react'
+function tableConfig(): any {
     return [
         {
             title: 'ID',
@@ -35,10 +36,13 @@ function tableConfig():any{
             }
         },
         {
-            title: '创意形式ID',
+            title: '创意形式',
             dataIndex: 'adcreativeTemplateId',
             key: 'adcreativeTemplateId',
             align: 'center',
+            render: (a: any) => {
+                return AdcreativeTemplateEnum[a]
+            }
         },
         {
             title: '数据展示',
@@ -55,7 +59,10 @@ function tableConfig():any{
             key: 'linkNameType',
             align: 'center',
             render: (a: any, b: any) => {
-                return b.linkNameType || b.linkPageType ? '开' : '关'
+                return b.linkNameType || b.linkPageType ? <div>
+                    {b.linkNameType && <div><span style={{ color: "#5a5a5a" }}>{LinkPageNameTypeEnum[b.linkNameType]}</span></div>}
+                    {b.linkPageType && <div><span style={{ color: "#5a5a5a" }}>{LinkPageTypeEnum[b.linkPageType]}</span></div>}
+                </div> : '关'
             }
         },
         {

+ 168 - 0
src/pages/launchSystemNew/components/customerServiceModal/index.tsx

@@ -0,0 +1,168 @@
+import Tables from "@/components/Tables"
+import { useAjax } from "@/Hook/useAjax"
+import { getCropWechatApi, sysCropWechatApi } from "@/services/launchAdq/createAd"
+import { CheckOutlined, SyncOutlined } from "@ant-design/icons"
+import { Button, Input, message, Modal, Space, Tooltip } from "antd"
+import React, { useEffect, useState } from "react"
+import style from '../goodsModal/index.less'
+import columns from "./tableConfig"
+
+/**
+ * 获取客服组
+ * @returns 
+ */
+interface Props {
+    onChange?: (data: any) => void,
+    data: any
+}
+const CustomerServiceModal: React.FC<Props> = (props) => {
+
+    /************************/
+    const { data: data1, onChange } = props
+    const [tableData, setTableData] = useState<any[]>([])//table数据
+    const [selectAdz, setSelectAdz] = useState<number>(1)   // 选择广告主
+    const [selectCrop, setSelectCrop] = useState<number>(1)   // 选择按钮
+    const [data, setData] = useState<any>(data1)
+    const [visible, setVisible] = useState<boolean>(false)
+    const [sysVisible, setSysVisible] = useState<boolean>(false)
+    const [cropId, setCropId] = useState<string>('')
+    const [notConfigured, setNotConfigured] = useState<any>([])
+
+    const getCropWechat = useAjax((params) => getCropWechatApi(params))
+    const sysCropWechat = useAjax((params) => sysCropWechatApi(params))
+    /************************/
+
+    /** 未配置账户获取 */
+    useEffect(() => {
+        setNotConfigured(() => data.filter((item: { data: { cropList: any[] }[] }) => item?.data?.some((item: { cropList: any[] }) => item?.cropList?.length === 0)))
+    }, [data])
+
+    useEffect(() => {
+        if (data?.length > 0) {
+            getList([data[selectAdz - 1].adAccountId])
+        } else {
+            setTableData([])
+        }
+    }, [selectAdz])
+
+
+    // 获取客服组列表
+    const getList = (params: number[]) => {
+        getCropWechat.run(params).then(res => {
+            if (res && Object.keys(res)?.indexOf(params[0].toString()) !== -1) {
+                setTableData(res[params[0]]?.map((item: { groupId: string }) => ({ ...item, id: item.groupId })))
+            } else {
+                setTableData([])
+            }
+        })
+    }
+
+    const handleOk = () => {
+        onChange && onChange(data)
+        setVisible(false)
+    }
+
+    /** 设置选中广告主 */
+    const handleSelectAdz = (value: number, item: any) => {
+        if (value === selectAdz) {
+            return
+        }
+        setSelectAdz(value)
+        setSelectCrop(1)
+    }
+
+    /** 设置选中广告主 */
+    const handleSelectCrop = (value: number, item: any) => {
+        if (value === selectCrop) {
+            return
+        }
+        setSelectCrop(value)
+    }
+
+    /** 表格选折 */
+    const onChangeTable = (selectedRowKeys: React.Key[], selectedRows: any) => {
+        let newData = JSON.parse(JSON.stringify(data))
+        newData[selectAdz - 1].data[selectCrop - 1].cropList = selectedRows
+        setData([...newData])
+    }
+
+    /** 同步 */
+    const handleSys = () => {
+        if (cropId) {
+            console.log(data[selectAdz - 1].id, cropId);
+            sysCropWechat.run({ accountId: data[selectAdz - 1].id, cropId: cropId }).then(res => {
+                if (res) {
+                    getList([data[selectAdz - 1].adAccountId])
+                    message.success('同步成功')
+                    setSysVisible(false)
+                }
+            })
+        } else {
+            message.error('请输入企业微信ID')
+        }
+    }
+
+    return <div>
+        <Button type="link" size="small" onClick={() => setVisible(true)} style={{ fontSize: 12 }}>{data1.some((item: { data: { cropList: any[] }[] }) => item?.data?.some((item: { cropList: any[] }) => item?.cropList?.length > 0)) ? '修改客服' : '配置客服'}</Button>
+        {visible && <Modal
+            title={<Space>
+                <span>客服组</span>
+                <Button size="small" onClick={() => { setSysVisible(true) }} type='link'>同步客服组</Button>
+            </Space>}
+            visible={visible}
+            footer={<Space>
+                <Button onClick={() => setVisible(false)}>取消</Button>
+                {notConfigured?.length > 0 ? <Tooltip title={`${notConfigured?.map((item: { adAccountId: string }) => item.adAccountId)?.toString()}下按钮未全部配置客服`}>
+                    <Button type="primary">确定</Button>
+                </Tooltip> : <Button type="primary" onClick={handleOk}>确定</Button>}
+            </Space>}
+            width={1100}
+            className={style.SelectPackage}
+            bodyStyle={{ padding: '0 10px 0 10px' }}
+        >
+            <div className={style.content}>
+                <div className={style.left}>
+                    <h4 className={style.title}>媒体账户</h4>
+                    {data?.map((item: { adAccountId: number, id: number }, index: number) => (
+                        <div key={index} onClick={() => { handleSelectAdz(index + 1, item) }} className={`${style.accItem} ${selectAdz === index + 1 && style.select} `}>
+                            {item?.adAccountId}
+                            {data[index]?.data?.every((item: { cropList: any[] }) => item?.cropList?.length > 0) && <CheckOutlined style={{ color: '#1890ff' }} />}
+                        </div>))}
+                </div>
+                <div className={style.left}>
+                    <h4 className={style.title}>企微按钮</h4>
+                    {data[selectAdz - 1].data?.map((item: { name: number }, index: number) => (
+                        <div key={index} onClick={() => { handleSelectCrop(index + 1, item) }} className={`${style.accItem} ${selectCrop === index + 1 && style.select} `}>
+                            <div>按钮{index + 1}<span style={{ fontSize: 12 }}>({item.name})</span></div>
+                            {data[selectAdz - 1]?.data[index]?.cropList?.length > 0 && <CheckOutlined style={{ color: '#1890ff' }} />}
+                        </div>))}
+                </div>
+                <div className={style.right}>
+                    <Space style={{ marginBottom: 10 }} align="end">
+                        <Button icon={<SyncOutlined />} type='link' loading={getCropWechat?.loading} onClick={() => { getList([data[selectAdz - 1].adAccountId]) }}></Button>
+                    </Space>
+                    <Tables
+                        columns={columns()}
+                        dataSource={tableData}
+                        size="small"
+                        loading={getCropWechat?.loading}
+                        scroll={{ y: 300 }}
+                        bordered
+                        rowSelection={{
+                            type: 'radio',
+                            selectedRowKeys: data[selectAdz - 1]?.data[selectCrop - 1]?.cropList?.map((item: any) => item?.id?.toString()),
+                            onChange: onChangeTable
+                        }}
+                    />
+                </div>
+            </div>
+        </Modal>}
+
+        {/* 输入企业微信ID同步 */}
+        {sysVisible && <Modal title="输入企业微信ID同步" visible={sysVisible} onOk={handleSys} onCancel={() => setSysVisible(false)} okText='同步' confirmLoading={sysCropWechat.loading}>
+            <Input value={cropId} onChange={(e) => setCropId(e.target.value)} placeholder='输入企业微信ID同步' />
+        </Modal>}
+    </div>
+}
+
+export default React.memo(CustomerServiceModal)

+ 44 - 0
src/pages/launchSystemNew/components/customerServiceModal/tableConfig.tsx

@@ -0,0 +1,44 @@
+import React from "react"
+let columns = () => [
+    {
+        title: '媒体账户',
+        dataIndex: 'accountId',
+        key: 'accountId',
+        width: 120,
+        ellipsis: true,
+        align: 'center',
+        render: (a: any, b: any) => {
+            return <span style={{ fontSize: "12px" }}>{a}</span>
+        }
+    },
+    {
+        title: '客服组名称',
+        dataIndex: 'groupName',
+        key: 'groupName',
+        align: 'center',
+        render: (a: any, b: any) => {
+            return <span style={{ fontSize: "12px" }}>{a}</span>
+        }
+    },
+    {
+        title: '客服组ID',
+        dataIndex: 'groupId',
+        key: 'groupId',
+        align: 'center',
+        render: (a: any, b: any) => {
+            return <span style={{ fontSize: "12px" }}>{a}</span>
+        }
+    },
+    {
+        title: 'cropId',
+        dataIndex: 'cropId',
+        key: 'cropId',
+        align: 'center',
+        ellipsis: true,
+        render: (a: any, b: any) => {
+            return <span style={{ fontSize: "12px" }}>{a}</span>
+        }
+    }
+]
+
+export default columns

+ 21 - 4
src/pages/launchSystemNew/components/lookLanding/index.tsx

@@ -32,7 +32,7 @@ function LookLanding(props: Props) {
         if (id) {
             get.run({ sysMediaId: id, mediaType: 'PAGE' }).then(res => {
                 if (res) {
-                    const { pageSpecsList } = res
+                    const { pageSpecsList, globalSpec } = res
                     setPageBackColor(pageSpecsList[0]?.bgColor)
                     let pageElementsSpecList = pageSpecsList[0]?.pageElementsSpecList
                     setContent(pageElementsSpecList?.map((item: any) => {
@@ -46,6 +46,23 @@ function LookLanding(props: Props) {
                         }
                         return item
                     }))
+                    if (globalSpec && Object.keys(globalSpec).length > 0) {
+                        let globalElementsSpecList = globalSpec.globalElementsSpecList
+                        let newComponentItem = globalElementsSpecList?.map((item: { elementType: string }) => {
+                            let typeKey = getTypeKey(item.elementType)
+                            let { elementType, ...data } = item[typeKey]
+                            let typeKey1 = getTypeKey(elementType)
+                            let componentItem: any = data[typeKey1]
+                            if (componentItem) {
+                                componentItem['elementType'] = elementType
+                            }
+                            data.componentItem = componentItem
+                            data.elementType = item.elementType
+                            delete data[typeKey1]
+                            return data
+                        })
+                        setGlobalData(newComponentItem)
+                    }
                 }
             })
         }
@@ -263,16 +280,16 @@ function LookLanding(props: Props) {
                 })}
                 {globalData.map((value: any, index: number) => {
                     if (value?.elementType === 'FLOAT_BUTTON') {
-                        let { titleColor, descColor, componentItem, iconUrl, title, desc, wxad_styleType } = value
+                        let { titleColor, descColor, componentItem, imageUrl, title, desc, styleType } = value
                         return <div className={`compt componentType134 comptFixedBottom`} key={'floatbutton' + index}>
                             <div className={'componentWrap'}>
                                 <div className="componentContent">
                                     <div className="floatButtonWrapper">
                                         <div className="floatButton">
-                                            {wxad_styleType === '1' && (iconUrl ? <img src={iconUrl} className="floatButtonAvatar" /> : <div className="floatButtonAvatarPlaceholder"></div>)}
+                                            {styleType === 0 && (imageUrl ? <img src={imageUrl} className="floatButtonAvatar" /> : <div className="floatButtonAvatarPlaceholder"></div>)}
                                             <div className="floatButtonTexts">
                                                 <div className="floatButtonTitle" style={{ color: titleColor || 'rgb(23, 23, 23)' }}>{title || '标题'}</div>
-                                                {(wxad_styleType === '1' || wxad_styleType === '2') && <div className="floatButtonDesc" style={{ color: descColor || 'rgb(76, 76, 76)' }}>{desc || '描述'}</div>}
+                                                {(styleType === 1 || styleType === 0) && <div className="floatButtonDesc" style={{ color: descColor || 'rgb(76, 76, 76)' }}>{desc || '描述'}</div>}
                                             </div>
                                             <div className="floatButtonLink" style={{
                                                 color: componentItem?.fontColor || 'rgb(255,255,255)',

+ 143 - 10
src/pages/launchSystemNew/components/pageModal/index.tsx

@@ -1,8 +1,136 @@
+// import Tables from "@/components/Tables"
+// import { useAjax } from "@/Hook/useAjax"
+// import { getAdqLandingPageList, putAdqLandingPage } from "@/services/launchAdq/adq"
+// import { CreateAdProps } from "@/services/launchAdq/createAd"
+// import { CheckOutlined, SyncOutlined } from "@ant-design/icons"
+// import { Button, Col, Modal, Row, Space } from "antd"
+// import React, { useEffect, useState } from "react"
+// import style from '../goodsModal/index.less'
+// import columns from "./tableConfig"
+
+
+// /**
+//  * 获取adq落地页
+//  * @returns 
+//  */
+// interface Props {
+//     visible?: boolean,
+//     onClose?: () => void,
+//     onChange?: (data: any) => void,
+//     data: any,
+// }
+// const PageModal: React.FC<Props> = (props) => {
+
+//     /*************************/
+//     const { visible, onClose, data: data1, onChange } = props
+//     const [selectAdz, setSelectAdz] = useState<number>(data1[0].accountId)   // 选择广告主
+//     const [data, setData] = useState<any>(null)
+//     const [queryForm, setQueryForm] = useState<{ accountId?: number, pageSize: number, pageNum: number }>({ pageNum: 1, pageSize: 20 })
+
+//     const putAdq = useAjax((params) => putAdqLandingPage(params))
+//     const listAjax = useAjax((params) => getAdqLandingPageList(params))
+//     /*************************/
+
+//     useEffect(() => {
+//         if (data1?.length > 0) {
+//             setQueryForm({ ...queryForm, accountId: data1.find((item: { accountId: number })=>item.accountId === selectAdz).accountId })
+//         }
+//     }, [selectAdz])
+
+//     useEffect(() => {
+//         if (queryForm?.accountId) {
+//             getList()
+//         }
+//     }, [queryForm])
+
+//     // 获取落地页列表
+//     const getList = () => {
+//         listAjax.run(queryForm)
+//     }
+
+//     const handleOk = () => {
+//         console.log('data---->', data);
+
+//         onChange && onChange(data)
+//     }
+
+//     /** 设置选中广告主 */
+//     const handleSelectAdz = ( item: any) => {
+//         if (item.accountId === selectAdz) {
+//             return
+//         }
+//         setSelectAdz(item.accountId)
+//     }
+
+//     /** 表格选折 */
+//     const onChangeTable = (selectedRowKeys: React.Key[], selectedRows: any) => {
+//         // setData([...data,selectedRows[0]])
+//     }
+
+//     /** 同步落地页 */
+//     const synPageList = () => {
+//         let ajaxs = data?.map((item: { id: number }) => putAdq.run(item.id))
+//         Promise.all(ajaxs).then(res => {
+//             listAjax.refresh()
+//         })
+//     }
+//     console.log(data,data1)
+//     return <Modal
+//         title={<Space>
+//             <span>ADQ落地页</span>
+//             <Button size="small" onClick={() => { synPageList() }} type="link" loading={putAdq?.loading}>同步落地页</Button>
+//         </Space>}
+//         visible={visible}
+//         onCancel={() => { onClose && onClose() }}
+//         onOk={handleOk}
+//         width={1200}
+//         className={style.SelectPackage}
+//         bodyStyle={{ padding: '0 10px 0 10px' }}
+//     >
+
+//         <div className={style.content}>
+//             <div className={style.left} style={{width:180}}>
+//                 <h4 className={style.title}>媒体账户</h4>
+//                 {data1?.map((item: { accountId: number,remark:string, id: number }, index: number) => (
+//                     <Row key={index} onClick={() => { handleSelectAdz(item) }} className={`${style.accItem} ${selectAdz === item.accountId && style.select} `} >
+//                         {/* {item?.accountId} */}
+//                         <Col span={21} style={{whiteSpace:'nowrap',width:'100%',overflow:'hidden',textOverflow:'ellipsis'}}>{item.remark ? item.accountId + '—' + item.remark : item.accountId}</Col>
+//                         <Col span={3}>{data?.accountId === item.accountId && <CheckOutlined style={{ color: '#1890ff' }} />}</Col>
+//                     </Row>))}
+//             </div>
+//             <div className={style.right}>
+//                 <Space style={{ marginBottom: 10 }} align="end">
+//                     <Button icon={<SyncOutlined />} type='link' loading={listAjax?.loading} onClick={() => { listAjax?.refresh() }}></Button>
+//                 </Space>
+//                 <Tables
+//                     columns={columns()}
+//                     dataSource={listAjax?.data?.records?.map((item: any) => ({ ...item, id: item.pageId }))}
+//                     size="small"
+//                     loading={listAjax?.loading}
+//                     scroll={{ y: 300 }}
+//                     bordered
+//                     defaultPageSize={100}
+//                     pageChange={(page: number, pageSize?: number) => {
+//                         setQueryForm({ ...queryForm, pageNum: page, pageSize: pageSize as number || 20 })
+//                     }}
+//                     rowSelection={{
+//                         type: 'radio',
+//                         selectedRowKeys: data1[selectAdz - 1]?.pageList?.map((item: any) => item?.id?.toString()),
+//                         onChange: onChangeTable
+//                     }}
+//                 />
+//             </div>
+//         </div>
+
+//     </Modal>
+// }
+
+// export default React.memo(PageModal)
 import Tables from "@/components/Tables"
 import { useAjax } from "@/Hook/useAjax"
 import { getAdqLandingPageList, putAdqLandingPage } from "@/services/launchAdq/adq"
 import { CheckOutlined, SyncOutlined } from "@ant-design/icons"
-import { Button, Modal, Space } from "antd"
+import { Button, message, Modal, Space } from "antd"
 import React, { useEffect, useState } from "react"
 import style from '../goodsModal/index.less'
 import columns from "./tableConfig"
@@ -13,6 +141,7 @@ import columns from "./tableConfig"
  * @returns 
  */
 interface Props {
+    cloudParams: { adcreativeTemplateId?: number }
     visible?: boolean,
     onClose?: () => void,
     onChange?: (data: any) => void,
@@ -21,12 +150,12 @@ interface Props {
 const PageModal: React.FC<Props> = (props) => {
 
     /*************************/
-    const { visible, onClose, data: data1, onChange } = props
+    const { cloudParams, visible, onClose, data: data1, onChange } = props
     const [selectAdz, setSelectAdz] = useState<number>(1)   // 选择广告主
     const [data, setData] = useState<any>(data1)
     const [queryForm, setQueryForm] = useState<{ accountId?: number, pageSize: number, pageNum: number }>({ pageNum: 1, pageSize: 20 })
+    const [loading, setLoading] = useState<boolean>(false)
 
-    const putAdq = useAjax((params) => putAdqLandingPage(params))
     const listAjax = useAjax((params) => getAdqLandingPageList(params))
     /*************************/
 
@@ -44,13 +173,16 @@ const PageModal: React.FC<Props> = (props) => {
 
     // 获取落地页列表
     const getList = () => {
-        listAjax.run(queryForm)
+        listAjax.run({ ...queryForm, ...cloudParams })
     }
 
     const handleOk = () => {
         console.log('data---->', data);
-        
-        onChange && onChange(data)
+        if (data?.every((item: { pageList: any }) => item.pageList)) {
+            onChange && onChange(data)
+        } else {
+            message.error('还有账号未选择落地页!')
+        }
     }
 
     /** 设置选中广告主 */
@@ -70,16 +202,17 @@ const PageModal: React.FC<Props> = (props) => {
 
     /** 同步落地页 */
     const synPageList = () => {
-        let ajaxs = data?.map((item: { id: number }) => putAdq.run(item.id))
+        setLoading(true)
+        let ajaxs = data?.map((item: { id: number }) => putAdqLandingPage(item.id))
         Promise.all(ajaxs).then(res => {
+            setLoading(false)
             listAjax.refresh()
-        })
+        }).catch(() => setLoading(false))
     }
-
     return <Modal
         title={<Space>
             <span>ADQ落地页</span>
-            <Button size="small" onClick={() => { synPageList() }} type="link" loading={putAdq?.loading}>同步落地页</Button>
+            <Button size="small" onClick={() => { synPageList() }} type="link" loading={loading}>同步落地页</Button>
         </Space>}
         visible={visible}
         onCancel={() => { onClose && onClose() }}

+ 2 - 2
src/pages/launchSystemNew/components/pageModal/tableConfig.tsx

@@ -43,7 +43,7 @@ let columns = () => [
         dataIndex: 'sourceType',
         key: 'sourceType',
         align: 'center',
-        width: 110,
+        width: 130,
         render: (a: any, b: any) => {
             return SourceTypeEnum[a]
         }
@@ -53,7 +53,7 @@ let columns = () => [
         dataIndex: 'createdTime',
         key: 'createdTime',
         align: 'center',
-        width: 160,
+        width: 145,
     },
 ]
 

+ 51 - 0
src/pages/launchSystemNew/components/previewAd/index.tsx

@@ -0,0 +1,51 @@
+import { useAjax } from "@/Hook/useAjax";
+import { getAdcreativePreviewsQrcodeApi } from "@/services/launchAdq/global";
+import { EyeOutlined } from "@ant-design/icons";
+import { Button, Popover } from "antd";
+import React, { useState } from "react";
+
+
+interface Props {
+    accountId: number,
+    adgroupId: number
+}
+/**
+ * 广告预览二维码
+ * @returns 
+ */
+const PreviewAd: React.FC<Props> = (props) => {
+
+    /*******************/
+    const { accountId, adgroupId } = props
+    const [open, setOpen] = useState(false);
+
+    const getAdcreativePreviewsQrcode = useAjax((params) => getAdcreativePreviewsQrcodeApi(params))
+    /*******************/
+    console.log('adAccountId, adgroupId--->', accountId);
+
+    const handleVisibleChange = (newOpen: boolean) => {
+        setOpen(newOpen);
+        if (newOpen && accountId && adgroupId) {
+            getAdcreativePreviewsQrcode.run({ accountId, adgroupId }).then(res => {
+
+            })
+        }
+    }
+
+    return <>
+        <Popover
+            content={<>
+                12312
+            </>}
+            trigger="click"
+            placement="left"
+            visible={open}
+            onVisibleChange={handleVisibleChange}
+        >
+            <a style={{fontSize: 12, color: '#1890FF'}}><EyeOutlined />广告</a>
+        </Popover>
+    </>
+}
+
+
+export default React.memo(PreviewAd)

+ 32 - 0
src/pages/launchSystemNew/components/previewOrigin/index.tsx

@@ -0,0 +1,32 @@
+import { useAjax } from "@/Hook/useAjax";
+import { getAdcreativeTemplatePreviewsApi } from "@/services/launchAdq/global";
+import { Button } from "antd";
+import React from "react";
+
+
+interface Props {
+    accountId: number,
+    adgroupId: number
+}
+/**
+ * 广告预览二维码
+ * @returns 
+ */
+const PreviewOrigin: React.FC<Props> = (props) => {
+
+    /*******************/
+    const { accountId, adgroupId } = props
+
+    const getAdcreativeTemplatePreviews = useAjax((params) => getAdcreativeTemplatePreviewsApi(params))
+    /*******************/
+
+    const handleVisibleChange = () => {
+        getAdcreativeTemplatePreviews.run({ accountId, adgroupId }).then(res => {
+            window.open(res)
+        })
+    }
+    return <Button style={{ fontSize: 12, color: '#1890FF', padding: 0 }} loading={getAdcreativeTemplatePreviews.loading} type='link' onClick={() => handleVisibleChange()}>创意预览</Button>
+}
+
+
+export default React.memo(PreviewOrigin)

+ 14 - 2
src/pages/launchSystemNew/components/selectCloud/index.tsx

@@ -1,9 +1,10 @@
 import { Button, Image, message, Modal, Space, Tabs, Tooltip } from "antd"
-import React, { useEffect } from "react"
+import React, { useEffect, useState } from "react"
 import { useModel } from "umi"
 import FileBoxAD from "@/components/FileBoxAD"
 import { CloseCircleFilled, QuestionCircleFilled } from "@ant-design/icons"
 import style from './index.less'
+import LookLanding from "../lookLanding"
 
 interface Props {
     visible?: boolean,
@@ -22,6 +23,9 @@ const SelectCloud: React.FC<Props> = (props) => {
     const { visible, onChange, onClose, sliderImgContent, isBack = true } = props
     const { state, set, getList } = useModel('useLaunchAdq.useBdMediaPup')
     const { mediaType, belongUser, parentId, selectItem, num } = state
+
+    const [lookVisible, setLookVisible] = useState<boolean>(false)
+    const [id, setId] = useState<number>(0)
     /**================================**/
 
     useEffect(() => {
@@ -96,7 +100,15 @@ const SelectCloud: React.FC<Props> = (props) => {
             <Tabs.TabPane tab={'个人本地'} key={1} />
             <Tabs.TabPane tab={'公共本地'} key={0} />
         </Tabs>
-        <FileBoxAD isAll={false} noFile={true} isBack={isBack} />
+        <FileBoxAD isAll={false} noFile={true} isBack={isBack} setPage={(type, data) => {
+            setId(data || 0)
+            if (type === 1) {
+                setLookVisible(true)
+            }
+        }} />
+
+        {/* 查看落地页 */}
+        {lookVisible && <LookLanding visible={lookVisible} onClose={() => setLookVisible(false)} id={id} />}
     </Modal>
 }
 

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

@@ -58,7 +58,7 @@ const TargetingModal: React.FC<Props> = (props) => {
             ajax={list}
             dataSource={list?.data?.records}
             loading={list?.loading}
-            scroll={{ y: 600 }}
+            scroll={{ y: 550 }}
             total={list?.data?.total}
             page={list?.data?.current}
             pageSize={list?.data?.size}

+ 14 - 15
src/pages/launchSystemNew/components/targetingTooltip/index.tsx

@@ -55,7 +55,6 @@ const TargetingTooltip: React.FC<Props> = (props) => {
     const { data, geoLocationList, modelList } = props
     const [content, setContent] = useState<ContentProps>({})
     /**********************/
-
     useEffect(() => {
         if (data && geoLocationList && data?.targeting) {
             let newConten: ContentProps = {}
@@ -128,50 +127,50 @@ const TargetingTooltip: React.FC<Props> = (props) => {
 
     return <div className='targetingTooltip'>
         {content?.geoLocation && <div>
-            地域:<span>{(content?.location && content?.location?.length > 0) && `(${content?.location?.map((key: string) => LocationTypes[key]).toString()})`}{content?.geoLocation?.toString()}</span>
+            <strong>地域:</strong><span>{(content?.location && content?.location?.length > 0) && `(${content?.location?.map((key: string) => LocationTypes[key]).toString()})`}{content?.geoLocation?.toString()}</span>
         </div>}
         {content?.age && <div>
-            年龄:<span>{content?.age}</span>
+            <strong>年龄:</strong><span>{content?.age}</span>
         </div>}
         {content?.gender && <div>
-            性别:<span>{content?.gender === 'MALE' ? '男' : '女'}</span>
+            <strong> 性别:</strong><span>{content?.gender === 'MALE' ? '男' : '女'}</span>
         </div>}
         {(content?.education && content?.education?.length > 0) && <div>
-            学历:<span>{content?.education?.map((key: string) => EducationEnum[key]).toString()}</span>
+            <strong>学历:</strong><span>{content?.education?.map((key: string) => EducationEnum[key]).toString()}</span>
         </div>}
         {(content?.networkType && content?.networkType?.length > 0) && <div>
-            联网方式:<span>{content?.networkType?.map((key: string) => NetworkEnum[key]).toString()}</span>
+            <strong>联网方式:</strong><span>{content?.networkType?.map((key: string) => NetworkEnum[key]).toString()}</span>
         </div>}
         {(content?.devicePrice && content?.devicePrice?.length > 0) && <div>
-            手机价格:<span>{content?.devicePrice?.map((key: string) => DevicePriceEnum[key]).toString()}</span>
+           <strong> 手机价格:</strong><span>{content?.devicePrice?.map((key: string) => DevicePriceEnum[key]).toString()}</span>
         </div>}
         {(content?.userOs && content?.userOs?.length > 0) && <div>
-            手机系统:<span>{content?.userOs?.map((key: string) => UserOsEnum[key]).toString()}</span>
+            <strong>手机系统:</strong><span>{content?.userOs?.map((key: string) => UserOsEnum[key]).toString()}</span>
         </div>}
         {(content?.maritalStatus && content?.maritalStatus?.length > 0) && <div>
-            婚恋:<span>{content?.maritalStatus?.map((key: string) => MaritalStatusEnum[key]).toString()}</span>
+            <strong>婚恋:</strong><span>{content?.maritalStatus?.map((key: string) => MaritalStatusEnum[key]).toString()}</span>
         </div>}
         {content?.deviceBrandModel && <>
             {(content?.deviceBrandModel?.includedList && content?.deviceBrandModel?.includedList?.length > 0) && <div>
-                排除品牌型号:<span>{content?.deviceBrandModel?.includedList?.toString()}</span>
+                <strong>排除品牌型号:</strong><span>{content?.deviceBrandModel?.includedList?.toString()}</span>
             </div>}
             {(content?.deviceBrandModel?.excludedList && content?.deviceBrandModel?.excludedList?.length > 0) && <div>
-                品牌型号:<span>{content?.deviceBrandModel?.excludedList?.toString()}</span>
+                <strong>品牌型号:</strong><span>{content?.deviceBrandModel?.excludedList?.toString()}</span>
             </div>}
         </>}
         {content?.wechatAdBehavior && <>
             {(content?.wechatAdBehavior?.actions && content?.wechatAdBehavior?.actions?.length > 0) && <div>
-                再营销:<span>{content?.wechatAdBehavior?.actions?.map((key: string) => WechatAdBehaviorEnum[key]).toString()}</span>
+               <strong> 再营销:</strong><span>{content?.wechatAdBehavior?.actions?.map((key: string) => WechatAdBehaviorEnum[key]).toString()}</span>
             </div>}
             {(content?.wechatAdBehavior?.excludedActions && content?.wechatAdBehavior?.excludedActions?.length > 0) && <div>
-                排除营销:<span>{content?.wechatAdBehavior?.excludedActions?.map((key: string) => WechatAdBehaviorEnum[key]).toString()}</span>
+                <strong>排除营销:</strong><span>{content?.wechatAdBehavior?.excludedActions?.map((key: string) => WechatAdBehaviorEnum[key]).toString()}</span>
             </div>}
         </>}
         {content?.excludedConvertedAudience && <div>
-            排除已转化用户:<span>{ExcludedDimensionEnum[content?.excludedConvertedAudience?.excludedDimension]}{`(自定义转化行为:${OptimizationGoalEnum[content?.excludedConvertedAudience?.conversionBehaviorList[0]]})`}</span>
+            <strong>排除已转化用户:</strong><span>{ExcludedDimensionEnum[content?.excludedConvertedAudience?.excludedDimension]}{`(自定义转化行为:${OptimizationGoalEnum[content?.excludedConvertedAudience?.conversionBehaviorList[0]]})`}</span>
         </div>}
         {content?.unlimited && <div>
-            不限:<span>{!content?.geoLocation && '地域,'}{content?.unlimited}</span>
+            <strong>不限:</strong><span>{!content?.geoLocation && '地域,'}{content?.unlimited}</span>
         </div>}
     </div>
 }

+ 20 - 0
src/pages/launchSystemNew/components/textAideInput/index.less

@@ -0,0 +1,20 @@
+.textAideInputPopover {
+  .ant-popover-inner-content {
+    padding: 0;
+    cursor: pointer;
+  }
+  .crt {
+    display: inline-flex;
+    align-items: center;
+    width: auto;
+    margin-left: 8px;
+    padding: 1px 4px;
+    height: 16px;
+    border-radius: 3px;
+    font-size: 12px;
+    color: #fff;
+    border: 1px solid #296bef;
+    background-color: #296bef;
+    line-height: normal;
+  }
+}

+ 79 - 0
src/pages/launchSystemNew/components/textAideInput/index.tsx

@@ -0,0 +1,79 @@
+import { useAjax } from "@/Hook/useAjax"
+import { getText } from "@/services/launchAdq/global"
+import { Input, List, Popover, Space } from "antd";
+import React, { useEffect } from "react"
+import { useState } from "react";
+import './index.less'
+
+
+interface Props {
+    value?: any,
+    onChange?: (value: any) => void,
+    style?: React.CSSProperties,
+    placeholder?: string;
+    maxTextLength?: number
+}
+/**
+ * 带文案助手输入框
+ * @returns 
+ */
+const TextAideInput: React.FC<Props> = (props) => {
+
+    /************************/
+    const { value, onChange, style, placeholder, maxTextLength = 10 } = props
+    const [text, setText] = useState<any>(value)
+    const [descriptionShow, setDescriptionshow] = useState(false)
+
+    const getTextLsit = useAjax((params) => getText(params))
+    /************************/
+
+    // 文案助手
+    const textList = (keyword?: any) => {
+        getTextLsit.run({ keyword, maxTextLength })
+    }
+
+    return <div className="textAideInput">
+        <Space>
+            <Popover placement="topLeft" overlayClassName="textAideInputPopover" style={{ minWidth: 600 }} visible={descriptionShow} content={<>
+                {
+                    <List
+                        loading={getTextLsit?.loading}
+                        size="small"
+                        style={{ maxHeight: 300, overflowX: 'auto', minWidth: 600 }}
+                        dataSource={getTextLsit?.data?.returnTexts}
+                        renderItem={(item: any) => <List.Item onClick={(e: any) => {
+                            setText(item.text)
+                            onChange && onChange(item.text)
+                            setTimeout(() => { setDescriptionshow(false) }, 50)
+                        }}><span >{item.text}{item.tag && <span className="crt">{'CTR 高'}</span>}</span></List.Item>}
+                    />
+                }
+            </>}>
+                <Input
+                    placeholder={placeholder}
+                    style={style}
+                    value={text}
+                    onFocus={() => {
+                        setDescriptionshow(true)
+                        textList(value)
+                    }}
+                    onBlur={() => {
+                        // setTimeout(() => { setDescriptionshow(false) }, 100)
+                    }}
+                    onChange={(e) => {
+                        let value = e.target.value
+                        setText(value)
+                        textList(value)
+                        onChange && onChange(value)
+                    }}
+                    allowClear
+                />
+            </Popover>
+
+            <span>{`${text?.length ?? 0}/${maxTextLength}`}</span>
+        </Space>
+    </div>
+}
+
+
+export default React.memo(TextAideInput)

+ 11 - 0
src/pages/launchSystemNew/launchManage/adAuthorize/index.less

@@ -10,3 +10,14 @@
   text-overflow: ellipsis;
   white-space: nowrap;
 }
+.boxCol{
+  display: flex;
+  strong{
+    width: 25%;
+    text-align: right;
+  }
+  span{
+    color: #999;
+    width: 75%;
+  }
+}

+ 81 - 17
src/pages/launchSystemNew/launchManage/adAuthorize/index.tsx

@@ -1,33 +1,97 @@
 
 import HocError from '@/Hoc/HocError'
-import { Card, Table, Tag } from 'antd'
-import React, { useEffect } from 'react'
+import { Card, Col, Modal, Row, Table, Tag, Input, message, Space, Button } from 'antd'
+import React, { useCallback, useEffect, useState } from 'react'
 import { columnsMp } from './tableConfig'
 import { useModel } from 'umi'
-
+import { useAjax } from '@/Hook/useAjax'
+import { putAdAccountApi } from '@/services/launchAdq/adAuthorize'
+import style from './index.less'
+import TableData from '../../components/TableData'
 
 /** 投放管理 */
 const AdAuthorize: React.FC = () => {
     const { getAdAccount } = useModel('useLaunchAdq.useAdAuthorize')
-
+    const [tableData, setTableData] = useState<any[]>([])
+    const [remarkData, set_remarkData] = useState<{
+        visible: boolean,
+        remark: string,
+        data: any
+    }>({
+        visible: false,
+        remark: '',
+        data: null
+    })
+    const putRemark = useAjax((adAccountId: any, remark: any) => putAdAccountApi(adAccountId, remark))
     useEffect(() => {
-        // 获取账号列表
-        getAdAccount.run()
+        getList()
     }, [])
+    const getList = () => {
+        // 获取账号列表
+        getAdAccount.run().then(res => {
+            if (res) {
+                setTableData(() => res?.data || [])
+            }
+        })
+    }
+    const remark = useCallback(() => {
+        if (remarkData.remark && remarkData.data) {
+            putRemark.run(remarkData.data.id, remarkData.remark).then(res => {
+                set_remarkData({ ...remarkData, visible: false, remark: '', data: null })
+                getList()
+            })
+        } else {
+            message.error('请输入备注!')
+        }
 
+    }, [getAdAccount, remarkData])
+    const edit = useCallback((data) => {
+        set_remarkData({ ...remarkData, visible: true, data, remark: data.remark })
+    }, [remarkData])
+    
     return <Card>
-        <Table dataSource={getAdAccount?.data?.data} loading={getAdAccount?.loading} columns={columnsMp()} size="small" bordered
-            pagination={{
-                position: ['bottomRight'],
-                total: getAdAccount?.data?.data?.length,//总共多少条数据,服务器给,设置后分页自动计算页数
-                showTotal: (total) => <Tag color="cyan">总共{total}数据</Tag>,
-                showSizeChanger: true,
-                showLessItems: true,
-                defaultCurrent: 1,
-                defaultPageSize: 20,//默认初始的每页条数
-            }}
-            rowKey={(row) => row.id}
+        <TableData
+            // ajax={getAdAccount}
+            dataSource={tableData}
+            loading={getAdAccount?.loading}
+            columns={() => columnsMp(edit)}
+            size="small"
+            scroll={{ x: 2000, y: 600 }}
+            leftChild={<Space>
+                <Input placeholder="广告主ID" style={{ width: 150 }} allowClear  onChange={(e) => {
+                    let value = e.target.value
+                    if (value) {
+                        let newArr = tableData?.filter(item => String(item.accountId).includes(value))
+                        setTableData(newArr)
+                    } else {
+                        setTableData(getAdAccount?.data?.data)
+                    }
+                }} />
+                <Button onClick={getList} type='primary'>搜索</Button>
+            </Space>}
         />
+        {remarkData.visible && <Modal
+            visible={remarkData.visible}
+            title='编辑账户'
+            onCancel={() => { set_remarkData({ ...remarkData, visible: false, data: null }) }}
+            onOk={remark}
+        >
+            <Row gutter={[20, 20]}>
+                <Col span={24} className={style.boxCol}><strong>广告主ID:</strong><span>{remarkData?.data.accountId}</span></Col>
+                <Col span={24} className={style.boxCol}><strong>类型:</strong><span>{remarkData?.data.sourceType === 0 ? '微信' : 'QQ'}</span></Col>
+                <Col span={24} className={style.boxCol}><strong>公众号信息:</strong><span>{remarkData?.data.wechatAccountName || '无'}</span></Col>
+                <Col span={24} className={style.boxCol}><strong>企业名称:</strong><span>{remarkData?.data.corporationName || '无'}</span></Col>
+                <Col span={24} className={style.boxCol}><strong>服务商ID列表:</strong><span>{remarkData?.data.agencyIdList ? remarkData.data.agencyIdList?.join() : '无'}</span></Col>
+                <Col span={24} className={style.boxCol}><strong>行业ID:</strong><span>{remarkData?.data.systemIndustryId || '无'}</span></Col>
+                <Col span={24} className={style.boxCol}><strong>授权状态:</strong><span>{remarkData?.data.authStatus || '无'}</span></Col>
+                <Col span={24} className={style.boxCol}><strong>日限额(分):</strong><span>{remarkData?.data.dailyBudget || '无'}</span></Col>
+                <Col span={24} className={style.boxCol}><strong>授权时间:</strong><span>{remarkData?.data.createTime || '无'}</span></Col>
+                <Col span={24} className={style.boxCol}><strong>备注:</strong><span><Input.TextArea rows={5} maxLength={200} value={remarkData.remark} onChange={(e) => {
+                    let value = e.target.value
+                    set_remarkData({ ...remarkData, remark: value })
+                }} /></span></Col>
+            </Row>
+        </Modal>}
     </Card>
 }
 

+ 72 - 37
src/pages/launchSystemNew/launchManage/adAuthorize/tableConfig.tsx

@@ -1,14 +1,16 @@
-import { Tooltip } from "antd"
+import { FundStatusEnum } from "@/services/launchAdq/enum"
+import { Badge, Space, Tooltip } from "antd"
 import React from "react"
 import './index.less'
-export function columnsMp(): any {
+export function columnsMp(edit:(params: any)=>void): any {
     return [
         {
             title: 'ID',
             dataIndex: 'id',
             key: 'id',
             align: 'center',
-            width: 55
+            width: 55,
+            fixed:'left'
         },
         {
             title: '广告主ID',
@@ -16,6 +18,7 @@ export function columnsMp(): any {
             key: 'accountId',
             align: 'center',
             width: 100,
+            fixed:'left'
         },
         {
             title: '类型',
@@ -28,18 +31,26 @@ export function columnsMp(): any {
             }
         },
         {
-            title: '公众号信息',
-            dataIndex: 'wechatAccountName',
-            key: 'wechatAccountName',
-            width: 150,
+            title: '备注',
+            dataIndex: 'remark',
+            key: 'remark',
             align: 'center',
-            render: (a: any, b: any) => {
-                return <div className="verticalCenter">
-                    <div><strong>{a}</strong></div>
-                    <div style={{ color: "rgb(136, 136, 136)", fontSize: 13 }}>{b?.wechatAccountId}</div>
-                </div>
-            }
+            width: 200,
+            ellipsis:true,
         },
+        // {
+        //     title: '公众号信息',
+        //     dataIndex: 'wechatAccountName',
+        //     key: 'wechatAccountName',
+        //     width: 150,
+        //     align: 'center',
+        //     render: (a: any, b: any) => {
+        //         return <div className="verticalCenter">
+        //             <div><strong>{a}</strong></div>
+        //             <div style={{ color: "rgb(136, 136, 136)", fontSize: 13 }}>{b?.wechatAccountId}</div>
+        //         </div>
+        //     }
+        // },
         {
             title: '企业名称',
             dataIndex: 'corporationName',
@@ -48,40 +59,48 @@ export function columnsMp(): any {
             align: 'center',
             ellipsis: true
         },
+        // {
+        //     title: '服务商ID列表',
+        //     dataIndex: 'agencyIdList',
+        //     key: 'agencyIdList',
+        //     width: 130,
+        //     align: 'center',
+        //     render: (a: any) => {
+        //         return <Tooltip title={a}>
+        //             <div className="name-wrapper">
+        //                 <p>{ a }</p>
+        //             </div>
+        //         </Tooltip>
+        //     }
+        // },
         {
-            title: '服务商ID列表',
-            dataIndex: 'agencyIdList',
-            key: 'agencyIdList',
+            title: '行业ID',
+            dataIndex: 'systemIndustryId',
+            key: 'systemIndustryId',
             width: 130,
             align: 'center',
             render: (a: any) => {
                 return <Tooltip title={a}>
-                    <div className="name-wrapper">
-                        <p>{ a }</p>
-                    </div>
+                    <div className="name-wrapper">{ a }</div>
                 </Tooltip>
             }
         },
         {
-            title: '行业ID',
-            dataIndex: 'systemIndustryId',
-            key: 'systemIndustryId',
-            width: 130,
+            title: '是否有效',
+            dataIndex: 'enabled',
+            key: 'enabled',
             align: 'center',
-            render: (a: any) => {
-                return <Tooltip title={a}>
-                    <div className="name-wrapper">
-                        <p>{ a }</p>
-                    </div>
-                </Tooltip>
+            width:60,
+            render: (a: any, b: any) => {
+                return  <Badge status={a ? "processing" :"error" } text={a? '是' : '否'} />
             }
         },
         {
-            title: '授权状态',
-            dataIndex: 'authStatus',
-            key: 'authStatus',
-            width: 80,
+            title: '授权时间',
+            dataIndex: 'createTime',
+            key: 'createTime',
             align: 'center',
+            width: 120
         },
         {
             title: '日限额(分)',
@@ -91,11 +110,27 @@ export function columnsMp(): any {
             width: 100
         },
         {
-            title: '授权时间',
-            dataIndex: 'createTime',
-            key: 'createTime',
+            title: '资金状态',
+            dataIndex: 'fundStatus',
+            key: 'fundStatus',
             align: 'center',
-            width: 120
+            width:100,
+            render:(a: string | number)=>{
+             return FundStatusEnum[a]
+            }
+        },
+        {
+            title: '操作',
+            dataIndex: 'cz',
+            key: 'cz',
+            align: 'center',
+            width: 80,
+            fixed:'right',
+            render:(a: any,b: any)=>{
+                return <Space>
+                    <a onClick={()=>{edit(b)}}>备注</a>
+                </Space>
+            }
         },
     ]
 }

+ 92 - 0
src/pages/launchSystemNew/launchManage/createAd/ad/index.tsx

@@ -0,0 +1,92 @@
+import { CreateAdProps } from '@/services/launchAdq/createAd'
+import { Col, Empty, Space, Spin, Tooltip } from 'antd'
+import React, { useCallback, useState } from 'react'
+import style from '../index.less'
+import AdgroupsCol from "../adgroupsCol"
+import { BaseResult } from '@ahooksjs/use-request/lib/types'
+import AdModal from "../../../components/adModal"
+import WeChatAdModal from "./modal/wechat"
+import LeadAdModal from "./modal/leadAd"
+import { useAjax } from '@/Hook/useAjax'
+import { getOptimizationGoalPermissions } from '@/services/launchAdq/global'
+type Props = {
+    queryForm: Partial<CreateAdProps>,
+    setQueryForm: React.Dispatch<React.SetStateAction<Partial<CreateAdProps>>>,
+    getSysAdgroups: BaseResult<any, any>,
+    clearData: () => void
+}
+export interface ModalConfig {
+    visible: boolean;
+    title?: string;
+    type?: 'add' | 'look' | 'edit',
+    dataInfo?: null
+}
+function Ad(props: Props) {
+    let { queryForm, getSysAdgroups, setQueryForm, clearData } = props
+    const queryOptimizationGoalPermissions = useAjax((params)=>getOptimizationGoalPermissions(params))
+    const [adVisible, setAdVisible] = useState<boolean>(false) // 选择广告弹窗控制
+    const [adModalConfig, setAdModalConfig] = useState<ModalConfig>({//新建广告弹窗
+        visible: false,
+        type: 'add'
+    })
+    // 设置变量
+    const handleAdModalConfig = useCallback((arg: ModalConfig) => {
+        setAdModalConfig({ ...adModalConfig, ...arg })
+    }, [adModalConfig])
+    // 获取广告详情
+    const getInfo = useCallback((sysAdgroupId) => {
+        getSysAdgroups.run(sysAdgroupId).then(res => {
+            setQueryForm({
+                ...queryForm,
+                sysAdgroupId,
+                sysAdcreativeId: undefined,//清空创意ID
+                taskMediaMaps: [],//清空创意
+                sysAdgroup: { ...res, isTemplate: false },
+            });
+            setAdVisible(false);
+            clearData()
+        })
+    }, [queryForm])
+    return <Col className={style.conRightBorder}>
+        <div className={style.top}>
+            广告基本信息
+            {queryForm.sysAdgroup && <a onClick={() => {
+                setQueryForm({ ...queryForm, sysAdgroup: undefined, sysAdgroupId: undefined, sysAdcreativeId: undefined ,pageList:[],taskMediaMaps:[]})
+            }}>清空</a>}
+        </div>
+        <div className={style.center}>
+            <Spin spinning={getSysAdgroups.loading}>
+                <div className={style.centerContent}>
+                    {queryForm?.sysAdgroup ? <AdgroupsCol data={queryForm?.sysAdgroup} /> : <Empty image={Empty.PRESENTED_IMAGE_SIMPLE} />}
+                </div>
+            </Spin>
+        </div>
+        <div className={style.bottom}>
+            <Space size={20}>
+                {
+                    queryForm?.promotedObjectType ? <span onClick={() => { setAdVisible(true) }}>{queryForm?.sysAdgroup ? '重选广告' : '选择广告'}</span> : <Tooltip title="请先选择推广目标">
+                        <span>选择广告</span>
+                    </Tooltip>
+                }
+                {
+                    queryForm?.promotedObjectType ? <span onClick={() => { handleAdModalConfig(queryForm?.sysAdgroup ? { visible: true, type: 'edit' } : { visible: true, type: 'add' }) }}>{queryForm?.sysAdgroup ? '编辑广告' : '新建广告'}</span> : <Tooltip title="请先选择推广目标">
+                        <span>新建广告</span>
+                    </Tooltip>
+                }
+            </Space>
+        </div>
+        {/* 选择广告 */}
+        {adVisible && <AdModal visible={adVisible} onClose={() => setAdVisible(false)} promotedObjectType={queryForm.promotedObjectType as string} onChange={getInfo} sysAdgroupId={queryForm?.sysAdgroupId} />}
+        {/* 微信公众号广告弹窗 */}
+        {adModalConfig.visible && queryForm.promotedObjectType === "PROMOTED_OBJECT_TYPE_WECHAT_OFFICIAL_ACCOUNT" && <WeChatAdModal visible={adModalConfig.visible} PupFn={handleAdModalConfig} callback={(values) => {
+            setQueryForm({ ...queryForm, sysAdgroup: values, sysAdcreativeId: undefined }); setAdVisible(false); clearData()
+            handleAdModalConfig({ visible: false, dataInfo: null, type: 'add' })
+        }} type={adModalConfig.type} dataInfo={queryForm.sysAdgroup} queryForm={queryForm} ajax={queryOptimizationGoalPermissions}/>}
+        {/* 收集线索广告弹窗 */}
+        {adModalConfig.visible && queryForm.promotedObjectType === "PROMOTED_OBJECT_TYPE_LEAD_AD" && <LeadAdModal visible={adModalConfig.visible} PupFn={handleAdModalConfig} callback={(values) => {
+            setQueryForm({ ...queryForm, sysAdgroup: values, sysAdcreativeId: undefined }); setAdVisible(false); clearData()
+            handleAdModalConfig({ visible: false, dataInfo: null, type: 'add' })
+        }} type={adModalConfig.type} dataInfo={queryForm.sysAdgroup} queryForm={queryForm} ajax={queryOptimizationGoalPermissions}/>}
+    </Col>
+}
+export default Ad

+ 392 - 0
src/pages/launchSystemNew/launchManage/createAd/ad/modal/leadAd.tsx

@@ -0,0 +1,392 @@
+import React, { useCallback, useEffect, useState } from 'react'
+import { Modal, Form, Input, Divider, Select, Radio, DatePicker, Switch, Checkbox, message, Tooltip, Row, Col, Space, TimePicker, Button } from 'antd'
+import { BidModeEnum, OptimizationGoalEnum, BidStrategyEnum, AdStatus } from '@/services/launchAdq/enum'
+import { ModalConfig } from '../index'
+import moment from 'moment';
+import { useAjax } from '@/Hook/useAjax';
+import { getSceneTagsList } from '@/services/launchAdq/global';
+import { ExclamationCircleOutlined } from '@ant-design/icons';
+import { CreateAdProps } from '@/services/launchAdq/createAd';
+import { createSysAdgroups } from '@/services/launchAdq/localAd';
+const { RangePicker }: { RangePicker: any } = DatePicker;
+let DatePickers: any = DatePicker
+interface Props {
+    queryForm: Partial<CreateAdProps>,
+    visible: boolean,
+    PupFn: (arg: ModalConfig) => void,
+    callback: (params: any) => void,
+    confirmLoading?: boolean,
+    type?: 'add' | 'look' | 'edit',//新增,查看,编辑
+    dataInfo?: any,
+    ajax: any
+}
+/**收集线索广告弹窗*/
+function LeadAdModal(props: Props) {
+    let { visible, confirmLoading, PupFn, callback, type, dataInfo, queryForm, ajax } = props
+    const createSysAdgroup = useAjax((params) => createSysAdgroups(params))
+    let arg = type === 'look' ? { footer: null } : {}
+    let [state, setState] = useState<any>({
+        isShowTime: []
+    })
+    let [template_checked, settemplate_checked] = useState<boolean>(dataInfo?.isTemplate || false)
+    const sceneTagsList = useAjax((params) => getSceneTagsList(params))
+    const [form] = Form.useForm();
+    let dateType = Form.useWatch('dateType', form)
+    let bidMode = Form.useWatch('bidMode', form)
+    let smartBidType = Form.useWatch('smartBidType', form)
+    let autoAcquisitionEnabled = Form.useWatch('autoAcquisitionEnabled', form)
+    let siteSet = Form.useWatch('siteSet', form)
+    let wechatPositionType = Form.useWatch('wechatPositionType', form)
+    let wechatSceneType = Form.useWatch('wechatSceneType', form)
+    let automaticSiteEnabled = Form.useWatch('automaticSiteEnabled', form)
+    let optimizationGoal = Form.useWatch('optimizationGoal', form)
+    // 确定事件
+    const handleOk = useCallback(() => {
+        form.validateFields().then(values => {
+            let newValues = JSON.parse(JSON.stringify(values))
+            newValues.sceneSpec = {}
+            if (newValues.dateType === '2') {
+                newValues['beginDate'] = moment(newValues.date).format('YYYY-MM-DD')
+            } else {
+                newValues['beginDate'] = moment(newValues.date[0]).format('YYYY-MM-DD')
+                newValues['endDate'] = moment(newValues.date[1]).format('YYYY-MM-DD')
+            }
+            if (newValues.firstDayBeginTime) {
+                console.log(newValues.firstDayBeginTime)
+                newValues['firstDayBeginTime'] = moment(newValues.firstDayBeginTime).format('HH:mm:ss')
+            }
+            Object.keys(newValues).forEach(key => {
+                switch (key) {
+                    case 'wechatPositionType':
+                        if (newValues[key] === '1') {
+                            newValues.sceneSpec = { ...newValues.sceneSpec, wechatPosition: newValues.wechatPosition }
+                        }
+                        break;
+                    case 'wechatSceneType':
+                        if (newValues[key] === '1') {
+                            newValues.sceneSpec = {
+                                ...newValues.sceneSpec, wechatScene: {
+                                    officialAccountMediaCategory: newValues.officialAccountMediaCategory,
+                                    miniProgramAndMiniGame: newValues.miniProgramAndMiniGame,
+                                    payScene: newValues.payScene
+                                }
+                            }
+                        }
+
+                        break;
+                }
+            })
+            if (newValues.sceneSpec.wechatPosition?.length === 0) {
+                delete newValues.sceneSpec.wechatPosition
+            }
+            if (newValues.sceneSpec.wechatScene) {
+                newValues.sceneSpec.wechatScene.officialAccountMediaCategory?.length === 0 && (delete newValues.sceneSpec.wechatScene.officialAccountMediaCategory)
+                newValues.sceneSpec.wechatScene.miniProgramAndMiniGame?.length === 0 && (delete newValues.sceneSpec.wechatScene.miniProgramAndMiniGame)
+                newValues.sceneSpec.wechatScene.payScene?.length === 0 && (delete newValues.sceneSpec.wechatScene.payScene)
+            }
+            if (!newValues.sceneSpec.wechatPosition && !newValues.sceneSpec.wechatScene) {
+                delete newValues.sceneSpec
+            }
+            delete newValues.officialAccountMediaCategory
+            delete newValues.miniProgramAndMiniGame
+            delete newValues.payScene
+            delete newValues.wechatPositionType
+            delete newValues.wechatPosition
+            delete newValues.wechatScene
+            delete newValues['dateType']
+            delete newValues['date']
+            newValues['timeSeries'] = Array(336).fill(1).join('')
+            newValues['promotedObjectType'] = queryForm.promotedObjectType
+            console.log(newValues)
+            newValues['isTemplate'] = template_checked
+            // 开启存为模板开关执行
+            // if (template_checked && type==='add') {
+            //     createSysAdgroup.run(newValues).then(res => {
+            //         if (res) {
+            //             callback(newValues)
+            //         }
+            //     })
+            // } else {
+            callback(newValues)
+            // }
+        })
+    }, [form, template_checked, queryForm, type])
+    // 场景定向
+    useEffect(() => {
+        sceneTagsList.run({ typeList: ['WECHAT_POSITION', 'OFFICIAL_ACCOUNT_MEDIA_CATEGORY', 'MINI_PROGRAM_AND_MINI_GAME', 'PAY_SCENE'] })
+    }, [])
+    // 数据回填
+    useEffect(() => {
+        if (dataInfo) {
+            form.setFieldsValue({
+                adgroupName: dataInfo?.adgroupName,//广告名称
+                promotedObjectType: dataInfo?.promotedObjectType,//推广目标
+                siteSet: dataInfo?.siteSet,//广告版位
+                autoAcquisitionEnabled: dataInfo?.autoAcquisitionEnabled,//一键起量
+                bidAmount: dataInfo?.bidAmount,//出价
+                smartBidType: dataInfo?.smartBidType,//出价类型
+                bidStrategy: dataInfo?.bidStrategy,//出价策略
+                bidMode: dataInfo?.bidMode,//出价方式
+                optimizationGoal: dataInfo?.optimizationGoal,//优化目标
+                dateType: dataInfo?.endDate ? '1' : '2',//投放日期
+                dailyBudget: dataInfo?.dailyBudget,//广告日预算
+                date: dataInfo?.endDate ? [moment(dataInfo?.beginDate), moment(dataInfo?.endDate)] : moment(dataInfo?.beginDate),//日期
+                autoAcquisitionBudget: dataInfo?.autoAcquisitionBudget,//起量预算
+                wechatPositionType: dataInfo?.sceneSpec?.wechatPosition ? '1' : '0',//微信公众号与小程序定投
+                wechatPosition: dataInfo?.sceneSpec?.wechatPosition,//微信公众号与小程序定投
+                wechatSceneType: dataInfo?.sceneSpec?.wechatScene?.officialAccountMediaCategory || dataInfo?.sceneSpec?.wechatScene?.miniProgramAndMiniGame || dataInfo?.sceneSpec?.wechatScene?.payScene ? '1' : '0',//微信公众号与小程序场景
+                officialAccountMediaCategory: dataInfo?.sceneSpec?.wechatScene?.officialAccountMediaCategory,//公众号媒体类型
+                miniProgramAndMiniGame: dataInfo?.sceneSpec?.wechatScene?.miniProgramAndMiniGame,//小程序小游戏流量类型
+                payScene: dataInfo?.sceneSpec?.wechatScene?.payScene,//订单详情页消费场景
+                firstDayBeginTime: dataInfo?.firstDayBeginTime ? moment(`${dataInfo?.beginDate} ${dataInfo?.firstDayBeginTime}`) : undefined,//首日开始时间
+                configuredStatus: dataInfo?.configuredStatus || 'AD_STATUS_SUSPEND',//广告启停
+            })
+            if (dataInfo?.firstDayBeginTime) {//存在首日开始时间,选中开关
+                setState({ ...state, isShowTime: ['1'] })
+            }
+        }
+    }, [dataInfo])
+    // 出价方式改变清空某些数据
+    const bidModeChange = useCallback((props) => {
+        form.setFieldsValue({
+            ...props,
+            optimizationGoal: null,
+            smartBidType: null,
+            // bidAmount:null,
+            bidStrategy: null,
+            autoAcquisitionEnabled: false,
+            autoAcquisitionBudget: null,
+            dailyBudget: null,
+        })
+    }, [])
+    // 出价和版位改变时查询
+    useEffect(() => {
+        if (bidMode && siteSet && siteSet?.length > 0) {
+            let obj: any = { siteSet, promotedObjectType: queryForm.promotedObjectType }
+            if (bidMode === 'BID_MODE_OCPC' || bidMode === 'BID_MODE_OCPM') {
+                obj = { ...obj, bidMode }
+            }
+            ajax.run(obj).then((res: any) => {
+                console.log(res)
+            })
+        }
+    }, [bidMode, siteSet])
+    return <Modal
+        visible={visible}
+        title={type === 'add' ? '新建广告' : type === 'look' ? '广告详情' : '编辑广告'}
+        onCancel={() => { PupFn({ visible: false, dataInfo: null, type: 'add' }) }}
+        onOk={type === 'look' ? () => message.warning('详情无法改动内容') : handleOk}
+        width={900}
+        confirmLoading={createSysAdgroup?.loading}
+        footer={<Space>
+            <Button onClick={() => { PupFn({ visible: false, dataInfo: null, type: 'add' }) }}>取消</Button>
+            <Button type='primary' onClick={handleOk}>确定</Button>
+            {<Checkbox checked={template_checked} onChange={(e) => {
+                let checked = e.target.checked
+                settemplate_checked(checked)
+            }}>存为模板</Checkbox>}
+        </Space>}
+        {...arg}
+    >
+        <Form
+            form={form}
+            labelCol={{ span: 5 }}
+            className='ad_form_style'
+            initialValues={
+                {
+                    promotedObjectType: queryForm.promotedObjectType,
+                    siteSet: ['SITE_SET_MOMENTS', 'SITE_SET_WECHAT'],
+                    bidMode: 'BID_MODE_OCPM',
+                    automaticSiteEnabled: false,
+                    dateType: '2',
+                    bidStrategy: 'BID_STRATEGY_AVERAGE_COST',
+                    timeSeries: '1',
+                    smartBidType: 'SMART_BID_TYPE_CUSTOM',
+                    autoAcquisitionEnabled: false,
+                    wechatSceneType: '0',
+                    wechatPositionType: '0',
+                    // optimizationGoal: 'OPTIMIZATIONGOAL_ECOMMERCE_ORDER',
+                    configuredStatus: 'AD_STATUS_SUSPEND'
+                }
+            }
+        >
+            {/* ============================================================基本信息============================================================= */}
+            <Divider orientation='center'>基本信息</Divider>
+            <Form.Item label={<strong>广告名称</strong>} name='adgroupName' rules={[{ required: true, message: '请输入广告名称!' }]}>
+                <Input placeholder='广告名称' style={{ width: 300 }} />
+            </Form.Item>
+            <Form.Item label={<strong>广告版位</strong>}>
+                <Form.Item name='automaticSiteEnabled'>
+                    <Radio.Group buttonStyle="solid">
+                        <Radio.Button value={true} disabled={queryForm.promotedObjectType === 'PROMOTED_OBJECT_TYPE_WECHAT_OFFICIAL_ACCOUNT'}>自动版位</Radio.Button>
+                        <Radio.Button value={false}>选择特定版位</Radio.Button>
+                    </Radio.Group>
+                </Form.Item>
+                {!automaticSiteEnabled && <Form.Item name='siteSet' noStyle rules={[{ required: true, message: '请输入选择广告版位!' }]}>
+                    <Checkbox.Group style={{ width: '100%' }} onChange={() => { bidModeChange({ bidMode: 'BID_MODE_OCPM' }) }}>
+                        <Row>
+                            <Col span={4}>
+                                <Checkbox value="SITE_SET_MOMENTS">微信朋友圈</Checkbox>
+                            </Col>
+                            <Col span={4}>
+                                <Checkbox value="SITE_SET_MOBILE_UNION">优量汇</Checkbox>
+                            </Col>
+                            <Col span={4}>
+                                <Checkbox value="SITE_SET_TENCENT_NEWS">腾讯新闻</Checkbox>
+                            </Col>
+                            <Col span={4}>
+                                <Checkbox value="SITE_SET_TENCENT_VIDEO">腾讯视频</Checkbox>
+                            </Col>
+                            <Col span={4}>
+                                <Checkbox value="SITE_SET_KANDIAN">腾讯看点</Checkbox>
+                            </Col>
+                            <Col span={6}>
+                                <Checkbox value="SITE_SET_QQ_MUSIC_GAME">QQ、腾讯音乐及游戏</Checkbox>
+                            </Col>
+                            <Col span={6}>
+                                <Checkbox value="SITE_SET_WECHAT">微信公众号与小程序</Checkbox>
+                            </Col>
+                        </Row>
+                    </Checkbox.Group>
+                </Form.Item>}
+            </Form.Item>
+            {
+                siteSet?.some((s: string) => s === 'SITE_SET_WECHAT') && <>
+                    <Form.Item label={<strong>微信公众号与小程序定投</strong>} name='wechatPositionType' style={wechatPositionType === '1' ? { marginBottom: 5 } : {}}>
+                        <Radio.Group >
+                            <Radio.Button value="0">不限</Radio.Button>
+                            <Radio.Button value="1">自定义</Radio.Button>
+                        </Radio.Group>
+                    </Form.Item>
+                    {wechatPositionType === '1' && <Form.Item style={{ marginLeft: 177 }} name='wechatPosition'>
+                        <Checkbox.Group options={sceneTagsList?.data?.WECHAT_POSITION?.map((item: { description: any; id: any; }) => ({ label: item.description, value: item.id }))} />
+                    </Form.Item>}
+                    <Form.Item label={<strong>微信公众号与小程序场景</strong>} name='wechatSceneType' style={wechatSceneType === '1' ? { marginBottom: 5 } : {}} >
+                        <Radio.Group >
+                            <Radio.Button value="0">不限</Radio.Button>
+                            <Radio.Button value="1">自定义</Radio.Button>
+                        </Radio.Group>
+                    </Form.Item>
+                    {wechatSceneType === '1' && <>
+                        <p style={{ marginBottom: 5, marginLeft: 177 }}><strong style={{ marginRight: 20 }}>公众号媒体类型</strong></p>
+                        <Form.Item style={{ marginLeft: 177 }} name='officialAccountMediaCategory'>
+                            <Checkbox.Group options={sceneTagsList?.data?.OFFICIAL_ACCOUNT_MEDIA_CATEGORY?.filter((i: { description: string; }) => i.description !== '不限')?.map((item: { description: any; id: any; }) => ({ label: item.description, value: item.id }))} />
+                        </Form.Item>
+                        <p style={{ marginBottom: 5, marginLeft: 177 }}><strong style={{ marginRight: 20 }}>小程序小游戏流量类型</strong></p>
+                        <Form.Item style={{ marginLeft: 177 }} name='miniProgramAndMiniGame'>
+                            <Checkbox.Group options={sceneTagsList?.data?.MINI_PROGRAM_AND_MINI_GAME?.filter((i: { description: string; }) => i.description !== '不限')?.map((item: { description: any; id: any; }) => ({ label: item.description, value: item.id }))} />
+                        </Form.Item>
+                        <p style={{ marginBottom: 5, marginLeft: 177 }}><strong style={{ marginRight: 20 }}>订单详情页消费场景</strong></p>
+                        <Form.Item style={{ marginLeft: 177 }} name='payScene'>
+                            <Checkbox.Group options={sceneTagsList?.data?.PAY_SCENE?.filter((i: { description: string; }) => i.description !== '不限')?.map((item: { description: any; id: any; }) => ({ label: item.description, value: item.id }))} />
+                        </Form.Item>
+                    </>}
+                </>
+            }
+            {/* ============================================================排期与出价============================================================= */}
+            <Divider orientation='center'>排期与出价</Divider>
+            <Form.Item label={<strong>投放日期</strong>} name='dateType'>
+                <Radio.Group >
+                    <Radio.Button value="1">选择开始与结束日期</Radio.Button>
+                    <Radio.Button value="2">长期投放</Radio.Button>
+                </Radio.Group>
+            </Form.Item>
+            {/* 投放日期的不同展示不同的日期选择 */}
+            {
+                dateType === '1' ? <Form.Item name='date' rules={[{ required: true, message: '请选择日期' }]}>
+                    <RangePicker style={{ marginLeft: 177 }}></RangePicker>
+                </Form.Item> : <Form.Item name='date' style={{ marginLeft: 177 }} rules={[{ required: true, message: '请选择日期' }]}>
+                    <DatePickers />
+                </Form.Item>
+            }
+            <Form.Item label={<strong>投放时段</strong>}>
+                <Space>
+                    <Radio.Group name='timeSeries' defaultValue='1'>
+                        <Radio.Button value={'1'}>全天投放</Radio.Button>
+                    </Radio.Group>
+                    <Checkbox.Group options={[{ label: '指定首日开始投放时间', value: '1' }]} onChange={(checkedValue) => {
+                        setState({ ...state, isShowTime: checkedValue })
+                    }
+                    } value={state.isShowTime} />
+                </Space>
+                {state?.isShowTime?.length > 0 && <Form.Item name='firstDayBeginTime' noStyle rules={[{ required: true, message: '请选择时间' }]}>
+                    <TimePicker />
+                </Form.Item>}
+            </Form.Item>
+            <Form.Item label={<strong>出价方式<Tooltip title='出价方式不同将影响自定义人群,行为兴趣意向等某些功能无法使用'><ExclamationCircleOutlined style={{ color: '#e91e63', marginLeft: 5 }} /></Tooltip></strong>} name='bidMode' rules={[{ required: true, message: '请选择出价方式' }]}>
+                <Radio.Group onChange={bidModeChange}>
+                    {
+                        Object.keys(BidModeEnum).filter(key => { if (siteSet?.some((name: string) => name === "SITE_SET_MOMENTS")) { return key === 'BID_MODE_OCPM' || key === 'BID_MODE_CPM' } else { return true } })?.map(key => {
+                            return <Radio.Button value={key} key={key} >{BidModeEnum[key]}</Radio.Button>
+                        })
+                    }
+
+                </Radio.Group>
+            </Form.Item>
+            {/* 出价方式为OCPM才展示 */}
+            {
+                (bidMode === 'BID_MODE_OCPM' || bidMode === 'BID_MODE_OCPC') && <>
+                    <Form.Item label={<strong>优化目标</strong>} name='optimizationGoal' rules={[{ required: true, message: '请选择优化目标' }]}>
+                        <Select style={{ width: 300 }} showSearch filterOption={(input, option) =>
+                            (option!.children as unknown as string).toLowerCase().includes(input.toLowerCase())
+                        } allowClear>
+                            {
+                                // Object.keys(OptimizationGoalEnum).map(key => {
+                                //     return <Select.Option value={key} key={key}>{OptimizationGoalEnum[key]}</Select.Option>
+                                // })
+                                ajax?.data?.optimizationGoalPermissionList.map((key: string) => {
+                                    return <Select.Option value={key} key={key}>{OptimizationGoalEnum[key]}</Select.Option>
+                                })
+                            }
+                        </Select>
+                    </Form.Item>
+                    <Form.Item label={<strong>出价类型</strong>} name='smartBidType' rules={[{ required: true, message: '请选择出价类型' }]}>
+                        <Radio.Group >
+                            <Radio.Button value="SMART_BID_TYPE_CUSTOM">手动出价</Radio.Button>
+                            <Radio.Button value="SMART_BID_TYPE_SYSTEMATIC">自动出价</Radio.Button>
+                        </Radio.Group>
+                    </Form.Item>
+                    <Form.Item label={<strong>出价策略</strong>} name='bidStrategy' rules={[{ required: true, message: '请选择出价策略' }]}>
+                        <Radio.Group >
+                            {
+                                Object.keys(BidStrategyEnum).map(key => {
+                                    return <Radio.Button value={key} key={key} disabled={smartBidType === 'SMART_BID_TYPE_SYSTEMATIC' && key === 'BID_STRATEGY_PRIORITY_CAP_COST'}> {BidStrategyEnum[key]}</Radio.Button>
+                                })
+                            }
+                        </Radio.Group>
+                    </Form.Item>
+                </>
+            }
+            {/* 出价类型为手动出价才展示 */}
+            {
+                smartBidType !== 'SMART_BID_TYPE_SYSTEMATIC' && <>
+                    <Form.Item label={<strong>出价</strong>} name='bidAmount' rules={[{ required: true, message: '请输入价格' }]}>
+                        <Input placeholder={`输入价格 元/${bidMode === 'BID_MODE_CPM' ? '千次曝光' : bidMode === 'BID_MODE_CPC' ? '点击' : OptimizationGoalEnum[optimizationGoal]}`} style={{ width: 300 }} />
+                    </Form.Item>
+                    {/* 当版位选择大于1时才出现 */}
+                    {/* {siteSet?.length > 1 &&<Form.Item label={<strong>分版位出价</strong>} name='bidAdjustment'>
+                        <Switch checkedChildren="开启" unCheckedChildren="关闭" />
+                    </Form.Item>} */}
+                    <Form.Item label={<strong>一键起量</strong>} name='autoAcquisitionEnabled' valuePropName="checked">
+                        <Switch checkedChildren="开启" unCheckedChildren="关闭" />
+                    </Form.Item>
+                    {/* 一键起量开启时才出现 */}
+                    {autoAcquisitionEnabled && <Form.Item label={<strong>起量预算</strong>} name='autoAcquisitionBudget' rules={[{ required: true, message: '请输入起量预算' }]}>
+                        <Input placeholder='起量预算' style={{ width: 300 }} />
+                    </Form.Item>}
+                </>
+            }
+            <Form.Item label={<strong>广告日预算</strong>} name='dailyBudget'>
+                <Input placeholder='不填默认为不限' style={{ width: 300 }} />
+            </Form.Item>
+            <Form.Item label={<strong>广告状态</strong>} name="configuredStatus" rules={[{ required: true, message: '请选择广告状态' }]}>
+                <Select placeholder="选择广告状态" style={{ width: 300 }}>
+                    {Object.keys(AdStatus).map(key => {
+                        return <Select.Option value={key} key={key}>{AdStatus[key]}</Select.Option>
+                    })}
+                </Select>
+            </Form.Item>
+        </Form>
+    </Modal >
+}
+export default LeadAdModal

+ 372 - 0
src/pages/launchSystemNew/launchManage/createAd/ad/modal/wechat.tsx

@@ -0,0 +1,372 @@
+import React, { useCallback, useEffect, useState } from 'react'
+import { Modal, Form, Input, Divider, Select, Radio, DatePicker, Switch, Checkbox, message, Tooltip, Row, Col, Space, TimePicker, Button } from 'antd'
+import { BidModeEnum, OptimizationGoalEnum, BidStrategyEnum, AdStatus } from '@/services/launchAdq/enum'
+import { ModalConfig } from '../index'
+import moment from 'moment';
+import { useAjax } from '@/Hook/useAjax';
+import { getSceneTagsList } from '@/services/launchAdq/global';
+import { ExclamationCircleOutlined } from '@ant-design/icons';
+import { CreateAdProps } from '@/services/launchAdq/createAd';
+import { createSysAdgroups } from '@/services/launchAdq/localAd';
+const { RangePicker }: { RangePicker: any } = DatePicker;
+let DatePickers: any = DatePicker
+interface Props {
+    queryForm: Partial<CreateAdProps>,
+    visible: boolean,
+    PupFn: (arg: ModalConfig) => void,
+    callback: (params: any) => void,
+    confirmLoading?: boolean,
+    type?: 'add' | 'look' | 'edit',//新增,查看,编辑
+    dataInfo?: any,
+    ajax: any
+}
+/**微信公众号广告弹窗*/
+function WeChatAdModal(props: Props) {
+    let { visible, confirmLoading, PupFn, callback, type, dataInfo, queryForm, ajax } = props
+    const createSysAdgroup = useAjax((params) => createSysAdgroups(params))
+    let [state, setState] = useState<any>({
+        isShowTime: []
+    })
+    let [template_checked, settemplate_checked] = useState<boolean>(dataInfo?.isTemplate || false)
+    let arg = type === 'look' ? { footer: null } : {}
+    const sceneTagsList = useAjax((params) => getSceneTagsList(params))
+    const [form] = Form.useForm();
+    let dateType = Form.useWatch('dateType', form)
+    let bidMode = Form.useWatch('bidMode', form)
+    let smartBidType = Form.useWatch('smartBidType', form)
+    let autoAcquisitionEnabled = Form.useWatch('autoAcquisitionEnabled', form)
+    let siteSet = Form.useWatch('siteSet', form)
+    let wechatPositionType = Form.useWatch('wechatPositionType', form)
+    let wechatSceneType = Form.useWatch('wechatSceneType', form)
+    let automaticSiteEnabled = Form.useWatch('automaticSiteEnabled', form)
+    let optimizationGoal = Form.useWatch('optimizationGoal', form)
+
+    // 确定事件
+    const handleOk = useCallback(() => {
+        form.validateFields().then(values => {
+            let newValues = JSON.parse(JSON.stringify(values))
+            newValues.sceneSpec = {}
+            if (newValues.dateType === '2') {
+                newValues['beginDate'] = moment(newValues.date).format('YYYY-MM-DD')
+            } else {
+                newValues['beginDate'] = moment(newValues.date[0]).format('YYYY-MM-DD')
+                newValues['endDate'] = moment(newValues.date[1]).format('YYYY-MM-DD')
+            }
+            if (newValues.firstDayBeginTime) {
+                newValues['firstDayBeginTime'] = moment(newValues.firstDayBeginTime).format('HH:mm:ss')
+            }
+            Object.keys(newValues).forEach(key => {
+                switch (key) {
+                    case 'wechatPositionType':
+                        if (newValues[key] === '1') {
+                            newValues.sceneSpec = { ...newValues.sceneSpec, wechatPosition: newValues.wechatPosition }
+                        }
+                        break;
+                    case 'wechatSceneType':
+                        if (newValues[key] === '1') {
+                            newValues.sceneSpec = {
+                                ...newValues.sceneSpec, wechatScene: {
+                                    officialAccountMediaCategory: newValues.officialAccountMediaCategory,
+                                    miniProgramAndMiniGame: newValues.miniProgramAndMiniGame,
+                                    payScene: newValues.payScene
+                                }
+                            }
+                        }
+
+                        break;
+                }
+            })
+            if (newValues.sceneSpec.wechatPosition?.length === 0) {
+                delete newValues.sceneSpec.wechatPosition
+            }
+            if (newValues.sceneSpec.wechatScene) {
+                newValues.sceneSpec.wechatScene.officialAccountMediaCategory?.length === 0 && (delete newValues.sceneSpec.wechatScene.officialAccountMediaCategory)
+                newValues.sceneSpec.wechatScene.miniProgramAndMiniGame?.length === 0 && (delete newValues.sceneSpec.wechatScene.miniProgramAndMiniGame)
+                newValues.sceneSpec.wechatScene.payScene?.length === 0 && (delete newValues.sceneSpec.wechatScene.payScene)
+            }
+            if (!newValues.sceneSpec.wechatPosition && !newValues.sceneSpec.wechatScene) {
+                delete newValues.sceneSpec
+            }
+            delete newValues.officialAccountMediaCategory
+            delete newValues.miniProgramAndMiniGame
+            delete newValues.payScene
+            delete newValues.wechatPositionType
+            delete newValues.wechatPosition
+            delete newValues.wechatScene
+            delete newValues['dateType']
+            delete newValues['date']
+            newValues['timeSeries'] = Array(336).fill(1).join('')
+            newValues['promotedObjectType'] = queryForm.promotedObjectType
+            newValues['isTemplate'] = template_checked
+            console.log(newValues)
+            // 开启存为模板开关执行
+            // if (template_checked && type === 'add') {
+            //     createSysAdgroup.run(newValues).then(res => {
+            //         if (res) {
+            //             callback(newValues)
+            //         }
+            //     })
+            // } else {
+            callback(newValues)
+            // }
+        })
+    }, [form, template_checked, queryForm, type])
+    // 场景定向
+    useEffect(() => {
+        sceneTagsList.run({ typeList: ['WECHAT_POSITION', 'OFFICIAL_ACCOUNT_MEDIA_CATEGORY', 'MINI_PROGRAM_AND_MINI_GAME', 'PAY_SCENE'] })
+    }, [])
+    // 数据回填
+    useEffect(() => {
+        if (dataInfo) {
+            form.setFieldsValue({
+                adgroupName: dataInfo?.adgroupName,//广告名称
+                promotedObjectType: dataInfo?.promotedObjectType,//推广目标
+                siteSet: dataInfo?.siteSet,//广告版位
+                autoAcquisitionEnabled: dataInfo?.autoAcquisitionEnabled,//一键起量
+                bidAmount: dataInfo?.bidAmount,//出价
+                smartBidType: dataInfo?.smartBidType,//出价类型
+                bidStrategy: dataInfo?.bidStrategy,//出价策略
+                bidMode: dataInfo?.bidMode,//出价方式
+                optimizationGoal: dataInfo?.optimizationGoal,//优化目标
+                dateType: dataInfo?.endDate ? '1' : '2',//投放日期
+                dailyBudget: dataInfo?.dailyBudget,//广告日预算
+                date: dataInfo?.endDate ? [moment(dataInfo?.beginDate), moment(dataInfo?.endDate)] : moment(dataInfo?.beginDate),//日期
+                autoAcquisitionBudget: dataInfo?.autoAcquisitionBudget,//起量预算
+                wechatPositionType: dataInfo?.sceneSpec?.wechatPosition ? '1' : '0',//微信公众号与小程序定投
+                wechatPosition: dataInfo?.sceneSpec?.wechatPosition,//微信公众号与小程序定投
+                wechatSceneType: dataInfo?.sceneSpec?.wechatScene?.officialAccountMediaCategory || dataInfo?.sceneSpec?.wechatScene?.miniProgramAndMiniGame || dataInfo?.sceneSpec?.wechatScene?.payScene ? '1' : '0',//微信公众号与小程序场景
+                officialAccountMediaCategory: dataInfo?.sceneSpec?.wechatScene?.officialAccountMediaCategory,//公众号媒体类型
+                miniProgramAndMiniGame: dataInfo?.sceneSpec?.wechatScene?.miniProgramAndMiniGame,//小程序小游戏流量类型
+                payScene: dataInfo?.sceneSpec?.wechatScene?.payScene,//订单详情页消费场景
+                firstDayBeginTime: dataInfo?.firstDayBeginTime ? moment(`${dataInfo?.beginDate} ${dataInfo?.firstDayBeginTime}`) : undefined,//首日开始时间
+                configuredStatus: dataInfo?.configuredStatus || 'AD_STATUS_SUSPEND',//广告启停
+            })
+            if (dataInfo?.firstDayBeginTime) {//存在首日开始时间,选中开关
+                setState({ ...state, isShowTime: ['1'] })
+            }
+        }
+    }, [dataInfo])
+    // 出价方式改变清空某些数据
+    const bidModeChange = useCallback((props) => {
+        form.setFieldsValue({
+            ...props,
+            optimizationGoal: null,
+            smartBidType: null,
+            // bidAmount:null,
+            bidStrategy: null,
+            autoAcquisitionEnabled: false,
+            autoAcquisitionBudget: null,
+            dailyBudget: null,
+        })
+    }, [])
+    // 出价和版位改变时查询
+    useEffect(() => {
+        if (bidMode && siteSet && siteSet?.length > 0) {
+            let obj:any = {siteSet,promotedObjectType: queryForm.promotedObjectType}
+            if(bidMode === 'BID_MODE_OCPC' || bidMode === 'BID_MODE_OCPM'){
+                obj = {...obj,bidMode}
+            }
+            ajax.run(obj).then((res: any)=>{
+                console.log(res)
+            })
+        }
+    }, [bidMode, siteSet])
+    return <Modal
+        visible={visible}
+        title={type === 'add' ? '新建广告' : type === 'look' ? '广告详情' : '编辑广告'}
+        onCancel={() => { PupFn({ visible: false, dataInfo: null, type: 'add' }) }}
+        width={900}
+        confirmLoading={createSysAdgroup?.loading}
+        footer={<Space>
+            <Button onClick={() => { PupFn({ visible: false, dataInfo: null, type: 'add' }) }}>取消</Button>
+            <Button type='primary' onClick={handleOk}>确定</Button>
+            {<Checkbox checked={template_checked} onChange={(e) => {
+                let checked = e.target.checked
+                settemplate_checked(checked)
+            }}>存为模板</Checkbox>}
+        </Space>}
+        {...arg}
+    >
+        <Form
+            form={form}
+            labelCol={{ span: 5 }}
+            className='ad_form_style'
+            initialValues={
+                {
+                    promotedObjectType: queryForm.promotedObjectType,
+                    siteSet: ['SITE_SET_MOMENTS', 'SITE_SET_WECHAT'],
+                    bidMode: 'BID_MODE_OCPM',
+                    automaticSiteEnabled: false,
+                    dateType: '2',
+                    bidStrategy: 'BID_STRATEGY_AVERAGE_COST',
+                    timeSeries: '1',
+                    smartBidType: 'SMART_BID_TYPE_CUSTOM',
+                    autoAcquisitionEnabled: false,
+                    wechatSceneType: '0',
+                    wechatPositionType: '0',
+                    // optimizationGoal: 'OPTIMIZATIONGOAL_ECOMMERCE_ORDER',
+                    configuredStatus: 'AD_STATUS_SUSPEND'
+                }
+            }
+        >
+            {/* ============================================================基本信息============================================================= */}
+            <Divider orientation='center'>基本信息</Divider>
+            <Form.Item label={<strong>广告名称</strong>} name='adgroupName' rules={[{ required: true, message: '请输入广告名称!' }]}>
+                <Input placeholder='广告名称' style={{ width: 300 }} />
+            </Form.Item>
+            <Form.Item label={<strong>广告版位</strong>}>
+                <Form.Item name='automaticSiteEnabled'>
+                    <Radio.Group buttonStyle="solid">
+                        <Radio.Button value={true} disabled={queryForm.promotedObjectType === 'PROMOTED_OBJECT_TYPE_WECHAT_OFFICIAL_ACCOUNT'}>自动版位</Radio.Button>
+                        <Radio.Button value={false}>选择特定版位</Radio.Button>
+                    </Radio.Group>
+                </Form.Item>
+                {!automaticSiteEnabled && <Form.Item name='siteSet' noStyle rules={[{ required: true, message: '请输入选择广告版位!' }]}>
+                    <Checkbox.Group style={{ width: '100%' }} onChange={() => { bidModeChange({ bidMode: 'BID_MODE_OCPM' }) }}>
+                        <Row>
+                            <Col span={5}>
+                                <Checkbox value="SITE_SET_MOMENTS">微信朋友圈</Checkbox>
+                            </Col>
+                            <Col span={6}>
+                                <Checkbox value="SITE_SET_WECHAT">微信公众号与小程序</Checkbox>
+                            </Col>
+                        </Row>
+                    </Checkbox.Group>
+                </Form.Item>}
+            </Form.Item>
+            {
+                siteSet?.some((s: string) => s === 'SITE_SET_WECHAT') && <>
+                    <Form.Item label={<strong>微信公众号与小程序定投</strong>} name='wechatPositionType' style={wechatPositionType === '1' ? { marginBottom: 5 } : {}}>
+                        <Radio.Group >
+                            <Radio.Button value="0">不限</Radio.Button>
+                            <Radio.Button value="1">自定义</Radio.Button>
+                        </Radio.Group>
+                    </Form.Item>
+                    {wechatPositionType === '1' && <Form.Item style={{ marginLeft: 177 }} name='wechatPosition'>
+                        <Checkbox.Group options={sceneTagsList?.data?.WECHAT_POSITION?.map((item: { description: any; id: any; }) => ({ label: item.description, value: item.id }))} />
+                    </Form.Item>}
+                    <Form.Item label={<strong>微信公众号与小程序场景</strong>} name='wechatSceneType' style={wechatSceneType === '1' ? { marginBottom: 5 } : {}} >
+                        <Radio.Group >
+                            <Radio.Button value="0">不限</Radio.Button>
+                            <Radio.Button value="1">自定义</Radio.Button>
+                        </Radio.Group>
+                    </Form.Item>
+                    {wechatSceneType === '1' && <>
+                        <p style={{ marginBottom: 5, marginLeft: 177 }}><strong style={{ marginRight: 20 }}>公众号媒体类型</strong></p>
+                        <Form.Item style={{ marginLeft: 177 }} name='officialAccountMediaCategory'>
+                            <Checkbox.Group options={sceneTagsList?.data?.OFFICIAL_ACCOUNT_MEDIA_CATEGORY?.filter((i: { description: string; }) => i.description !== '不限')?.map((item: { description: any; id: any; }) => ({ label: item.description, value: item.id }))} />
+                        </Form.Item>
+                        <p style={{ marginBottom: 5, marginLeft: 177 }}><strong style={{ marginRight: 20 }}>小程序小游戏流量类型</strong></p>
+                        <Form.Item style={{ marginLeft: 177 }} name='miniProgramAndMiniGame'>
+                            <Checkbox.Group options={sceneTagsList?.data?.MINI_PROGRAM_AND_MINI_GAME?.filter((i: { description: string; }) => i.description !== '不限')?.map((item: { description: any; id: any; }) => ({ label: item.description, value: item.id }))} />
+                        </Form.Item>
+                        <p style={{ marginBottom: 5, marginLeft: 177 }}><strong style={{ marginRight: 20 }}>订单详情页消费场景</strong></p>
+                        <Form.Item style={{ marginLeft: 177 }} name='payScene'>
+                            <Checkbox.Group options={sceneTagsList?.data?.PAY_SCENE?.filter((i: { description: string; }) => i.description !== '不限')?.map((item: { description: any; id: any; }) => ({ label: item.description, value: item.id }))} />
+                        </Form.Item>
+                    </>}
+                </>
+            }
+            {/* ============================================================排期与出价============================================================= */}
+            <Divider orientation='center'>排期与出价</Divider>
+            <Form.Item label={<strong>投放日期</strong>} name='dateType'>
+                <Radio.Group >
+                    <Radio.Button value="1">选择开始与结束日期</Radio.Button>
+                    <Radio.Button value="2">长期投放</Radio.Button>
+                </Radio.Group>
+            </Form.Item>
+            {/* 投放日期的不同展示不同的日期选择 */}
+            {
+                dateType === '1' ? <Form.Item name='date' rules={[{ required: true, message: '请选择日期' }]}>
+                    <RangePicker style={{ marginLeft: 177 }}></RangePicker>
+                </Form.Item> : <Form.Item name='date' style={{ marginLeft: 177 }} rules={[{ required: true, message: '请选择日期' }]}>
+                    <DatePickers />
+                </Form.Item>
+            }
+            <Form.Item label={<strong>投放时段</strong>}>
+                <Space>
+                    <Radio.Group name='timeSeries' defaultValue='1'>
+                        <Radio.Button value={'1'}>全天投放</Radio.Button>
+                    </Radio.Group>
+                    <Checkbox.Group options={[{ label: '指定首日开始投放时间', value: '1' }]} onChange={(checkedValue) => {
+                        setState({ ...state, isShowTime: checkedValue })
+                    }
+                    } value={state.isShowTime} />
+                </Space>
+                {state?.isShowTime?.length > 0 && <Form.Item name='firstDayBeginTime' noStyle rules={[{ required: true, message: '请选择时间' }]}>
+                    <TimePicker />
+                </Form.Item>}
+            </Form.Item>
+            <Form.Item label={<strong>出价方式<Tooltip title='oCPC/oCPM出价,或开启自动扩量/智能扩量时不支持二方人群'><ExclamationCircleOutlined style={{ color: '#e91e63', marginLeft: 5 }} /></Tooltip></strong>} name='bidMode' rules={[{ required: true, message: '请选择出价方式' }]}>
+                <Radio.Group onChange={bidModeChange}>
+                    {
+                        Object.keys(BidModeEnum).filter(key => { if (siteSet?.some((name: string) => name === "SITE_SET_MOMENTS")) { return key === 'BID_MODE_OCPM' || key === 'BID_MODE_CPM' } else { return true } })?.map(key => {
+                            return <Radio.Button value={key} key={key} >{BidModeEnum[key]}</Radio.Button>
+                        })
+                    }
+                </Radio.Group>
+            </Form.Item>
+            {/* 出价方式为OCPM才展示 */}
+            {
+                bidMode === 'BID_MODE_OCPM' && <>
+                    <Form.Item label={<strong>优化目标</strong>} name='optimizationGoal' rules={[{ required: true, message: '请选择优化目标' }]}>
+                        <Select style={{ width: 300 }} showSearch filterOption={(input, option) =>
+                            (option!.children as unknown as string).toLowerCase().includes(input.toLowerCase())
+                        } allowClear>
+                            {
+                                Object.keys(OptimizationGoalEnum).map(key => {
+                                    return <Select.Option value={key} key={key}>{OptimizationGoalEnum[key]}</Select.Option>
+                                })
+                            }
+                        </Select>
+                    </Form.Item>
+                    <Form.Item label={<strong>出价类型</strong>} name='smartBidType' rules={[{ required: true, message: '请选择出价类型' }]}>
+                        <Radio.Group >
+                            <Radio.Button value="SMART_BID_TYPE_CUSTOM">手动出价</Radio.Button>
+                            <Radio.Button value="SMART_BID_TYPE_SYSTEMATIC">自动出价</Radio.Button>
+                        </Radio.Group>
+                    </Form.Item>
+                    <Form.Item label={<strong>出价策略</strong>} name='bidStrategy' rules={[{ required: true, message: '请选择出价策略' }]}>
+                        <Radio.Group >
+                            {
+                                Object.keys(BidStrategyEnum).map(key => {
+                                    return <Radio.Button value={key} key={key} disabled={smartBidType === 'SMART_BID_TYPE_SYSTEMATIC' && key === 'BID_STRATEGY_PRIORITY_CAP_COST'}> {BidStrategyEnum[key]}</Radio.Button>
+                                })
+                            }
+                        </Radio.Group>
+                    </Form.Item>
+                </>
+            }
+            {/* 出价类型为手动出价才展示 */}
+            {
+                smartBidType !== 'SMART_BID_TYPE_SYSTEMATIC' && <>
+                    <Form.Item label={<strong>出价</strong>} name='bidAmount' rules={[{ required: true, message: '请输入价格' }]}>
+                        <Input placeholder={`输入价格 元/${bidMode === 'BID_MODE_CPM' ? '千次曝光' : bidMode === 'BID_MODE_CPC' ? '点击' : OptimizationGoalEnum[optimizationGoal]}`} style={{ width: 300 }} />
+                    </Form.Item>
+                    {/* 当版位选择大于1时才出现 */}
+                    {/* {siteSet?.length > 1 &&<Form.Item label={<strong>分版位出价</strong>} name='bidAdjustment'>
+                        <Switch checkedChildren="开启" unCheckedChildren="关闭" />
+                    </Form.Item>} */}
+                    <Form.Item label={<strong>一键起量</strong>} name='autoAcquisitionEnabled' valuePropName="checked">
+                        <Switch checkedChildren="开启" unCheckedChildren="关闭" />
+                    </Form.Item>
+                    {/* 一键起量开启时才出现 */}
+                    {autoAcquisitionEnabled && <Form.Item label={<strong>起量预算</strong>} name='autoAcquisitionBudget' rules={[{ required: true, message: '请输入起量预算' }]}>
+                        <Input placeholder='起量预算' style={{ width: 300 }} />
+                    </Form.Item>}
+                </>
+            }
+            <Form.Item label={<strong>广告日预算</strong>} name='dailyBudget'>
+                <Input placeholder='不填默认为不限' style={{ width: 300 }} />
+            </Form.Item>
+            <Form.Item label={<strong>广告状态</strong>} name="configuredStatus" rules={[{ required: true, message: '请选择广告状态' }]}>
+                <Select placeholder="选择广告状态" style={{ width: 300 }}>
+                    {Object.keys(AdStatus).map(key => {
+                        return <Select.Option value={key} key={key}>{AdStatus[key]}</Select.Option>
+                    })}
+                </Select>
+            </Form.Item>
+        </Form>
+    </Modal >
+}
+export default WeChatAdModal

+ 44 - 32
src/pages/launchSystemNew/launchManage/createAd/adcreativeCol.tsx

@@ -1,29 +1,30 @@
-import { PromotedObjectType, SiteSetEnum } from "@/services/launchAdq/enum"
+import { AdcreativeTemplateEnum, EndPageTypeEnum, LinkPageNameTypeEnum, LinkPageTypeEnum, PromotedObjectType, SiteSetEnum } from "@/services/launchAdq/enum"
 import React from "react"
 import { Image, Space } from "antd"
+import { overrideCanvasHeadOptionEnum } from "./creative/modal/config"
 
 
 export const adcreativeTemplate = [
-    {adcreativeTemplateAppellation: "常规大图 1:1", adcreativeTemplateId: 311},
-    {adcreativeTemplateAppellation: "常规视频  4:3", adcreativeTemplateId: 618},
-    {adcreativeTemplateAppellation: "常规多图 1:1 三图", adcreativeTemplateId: 641},
-    {adcreativeTemplateAppellation: "常规多图 1:1 四图", adcreativeTemplateId: 642},
-    {adcreativeTemplateAppellation: "常规多图 1:1 六图", adcreativeTemplateId: 643},
-    {adcreativeTemplateAppellation: "横版视频 16:9", adcreativeTemplateId: 720},
-    {adcreativeTemplateAppellation: "竖版视频 9:16", adcreativeTemplateId: 721},
-    {adcreativeTemplateAppellation: "常规视频 750×1536", adcreativeTemplateId: 1064},
-    {adcreativeTemplateAppellation: "常规视频 16:9", adcreativeTemplateId: 1465},
-    {adcreativeTemplateAppellation: "常规视频 9:16", adcreativeTemplateId: 1480},
-    {adcreativeTemplateAppellation: "卡片广告 横版大图 16:9", adcreativeTemplateId: 1707},
-    {adcreativeTemplateAppellation: "卡片广告 横版视频 16:9", adcreativeTemplateId: 1708},
-    {adcreativeTemplateAppellation: "破框形态 视频合约广告", adcreativeTemplateId: 1885},
-    {adcreativeTemplateAppellation: "横版大图 16:9", adcreativeTemplateId: 711},
-    {adcreativeTemplateAppellation: "竖版大图 9:16", adcreativeTemplateId: 712},
-    {adcreativeTemplateAppellation: "横版视频 16:9", adcreativeTemplateId: 720},
-    {adcreativeTemplateAppellation: "竖版视频 9:16", adcreativeTemplateId: 721},
-    {adcreativeTemplateAppellation: "激励浏览广告", adcreativeTemplateId: 910},
-    {adcreativeTemplateAppellation: "Banner图片 20:7", adcreativeTemplateId: 925},
-    {adcreativeTemplateAppellation: "出框形态 视频合约广告", adcreativeTemplateId: 1945}
+    { adcreativeTemplateAppellation: "常规大图 1:1", adcreativeTemplateId: 311 },
+    { adcreativeTemplateAppellation: "常规视频  4:3", adcreativeTemplateId: 618 },
+    { adcreativeTemplateAppellation: "常规多图 1:1 三图", adcreativeTemplateId: 641 },
+    { adcreativeTemplateAppellation: "常规多图 1:1 四图", adcreativeTemplateId: 642 },
+    { adcreativeTemplateAppellation: "常规多图 1:1 六图", adcreativeTemplateId: 643 },
+    { adcreativeTemplateAppellation: "横版视频 16:9", adcreativeTemplateId: 720 },
+    { adcreativeTemplateAppellation: "竖版视频 9:16", adcreativeTemplateId: 721 },
+    { adcreativeTemplateAppellation: "常规视频 750×1536", adcreativeTemplateId: 1064 },
+    { adcreativeTemplateAppellation: "常规视频 16:9", adcreativeTemplateId: 1465 },
+    { adcreativeTemplateAppellation: "常规视频 9:16", adcreativeTemplateId: 1480 },
+    { adcreativeTemplateAppellation: "卡片广告 横版大图 16:9", adcreativeTemplateId: 1707 },
+    { adcreativeTemplateAppellation: "卡片广告 横版视频 16:9", adcreativeTemplateId: 1708 },
+    { adcreativeTemplateAppellation: "破框形态 视频合约广告", adcreativeTemplateId: 1885 },
+    { adcreativeTemplateAppellation: "横版大图 16:9", adcreativeTemplateId: 711 },
+    { adcreativeTemplateAppellation: "竖版大图 9:16", adcreativeTemplateId: 712 },
+    { adcreativeTemplateAppellation: "横版视频 16:9", adcreativeTemplateId: 720 },
+    { adcreativeTemplateAppellation: "竖版视频 9:16", adcreativeTemplateId: 721 },
+    { adcreativeTemplateAppellation: "激励浏览广告", adcreativeTemplateId: 910 },
+    { adcreativeTemplateAppellation: "Banner图片 20:7", adcreativeTemplateId: 925 },
+    { adcreativeTemplateAppellation: "出框形态 视频合约广告", adcreativeTemplateId: 1945 }
 ]
 
 /**
@@ -36,24 +37,35 @@ const AdcreativeCol: React.FC<Props> = (props) => {
 
     /***************************/
     const { data } = props
-    const { adcreativeName, promotedObjectType, siteSet, adcreativeTemplateId, adcreativeElements } = data
+    const { adcreativeName, promotedObjectType, siteSet, adcreativeTemplateId, adcreativeElements, profile, overrideCanvasHeadOption, linkNameType, linkPageType, linkPageSpec } = data
     /***************************/
 
     return <>
-        <div>创意名称: <span>{adcreativeName}</span></div>
-        <div>推广目标: <span>{PromotedObjectType[promotedObjectType]}</span></div>
-        <div>广告版位: <span>{siteSet?.map((item: string) => SiteSetEnum[item]).toString()}</span></div>
-        <div>创意形式: <span>{adcreativeTemplate?.find((item: any) => item?.adcreativeTemplateId === adcreativeTemplateId)?.adcreativeTemplateAppellation || ''}</span></div>
-        {adcreativeElements?.description && <div>创意文案: <span>{adcreativeElements?.description}</span></div>}
-        {adcreativeElements?.title && <div>文案: <span>{adcreativeElements?.title}</span></div>}
-        {adcreativeElements?.imageUrl && <div style={{ display: 'flex', alignItems: 'flex-start' }}>创意素材: <Image width={80} src={adcreativeElements?.imageUrl} style={{ borderRadius: 8, overflow: 'hidden', marginLeft: 5 }} /></div>}
-        {adcreativeElements?.imageUrlList && <div style={{ display: 'flex', alignItems: 'flex-start', flexWrap: 'wrap' }}><span style={{ marginRight: 4 }}>创意素材:</span> <Image.PreviewGroup>
+        <div><strong>创意名称:</strong><span style={{ color: "#5a5a5a" }}>{adcreativeName}</span></div>
+        <div><strong>推广目标:</strong> <span style={{ color: "#5a5a5a" }}>{PromotedObjectType[promotedObjectType]}</span></div>
+        <div><strong>广告版位:</strong> <span style={{ color: "#5a5a5a" }}>{siteSet?.map((item: string) => SiteSetEnum[item]).toString()}</span></div>
+        <div><strong>创意形式: </strong><span style={{ color: "#5a5a5a" }}>{AdcreativeTemplateEnum[adcreativeTemplateId]}</span></div>
+        {(profile && Object.keys(profile)?.length > 0) ?
+            <div><strong>头像及昵称跳转页:</strong> <span style={{ color: "#5a5a5a" }}><img src={adcreativeElements?.brand?.brandImgUrl} style={{ width: 20, marginRight: 5 }} />{adcreativeElements?.brand?.brandName}</span></div> :
+            adcreativeElements?.brand ? <div><strong>品牌形象:</strong> <span style={{ color: "#5a5a5a" }}><img src={adcreativeElements?.brand?.brandImgUrl} style={{ width: 20, marginRight: 5 }} />{adcreativeElements?.brand?.brandName}</span></div> : null}
+        {adcreativeElements?.description && <div><strong>创意文案:</strong> <span style={{ color: "#5a5a5a" }}>{adcreativeElements?.description}</span></div>}
+        {adcreativeElements?.title && <div><strong>文案:</strong> <span style={{ color: "#5a5a5a" }}>{adcreativeElements?.title}</span></div>}
+        {linkNameType && <div><strong>按钮文案:</strong> <span style={{ color: "#5a5a5a" }}>{LinkPageNameTypeEnum[linkNameType]}</span></div>}
+        {linkPageType && <div><strong>跳转落地页:</strong> <span style={{ color: "#5a5a5a" }}>{LinkPageTypeEnum[linkPageType]}</span></div>}
+        {linkPageSpec?.pageUrl && <div><strong>落地页地址:</strong> <span style={{ color: "#5a5a5a" }}>{linkPageSpec?.pageUrl}</span></div>}
+        {linkPageSpec?.miniProgramSpec && linkPageSpec?.miniProgramSpec?.miniProgramId && <div><strong>小程序ID:</strong> <span style={{ color: "#5a5a5a" }}>{linkPageSpec?.miniProgramSpec?.miniProgramId}</span></div>}
+        {linkPageSpec?.miniProgramSpec && linkPageSpec?.miniProgramSpec?.miniProgramPath && <div><strong>小程序地址:</strong> <span style={{ color: "#5a5a5a" }}>{linkPageSpec?.miniProgramSpec?.miniProgramPath}</span></div>}
+        {adcreativeElements?.endPage && <div><strong>视频结束页类型:</strong> <span style={{ color: "#5a5a5a" }}>{EndPageTypeEnum[adcreativeElements?.endPage?.endPageType]}</span></div>}
+        {adcreativeElements?.endPage && <div><strong>视频结束页文案:</strong> <span style={{ color: "#5a5a5a" }}>{adcreativeElements?.endPage?.endPageDesc}</span></div>}
+        {adcreativeElements?.imageUrl && <div style={{ display: 'flex', alignItems: 'flex-start', marginBottom: 4 }}><strong>创意素材:</strong> <Image width={80} src={adcreativeElements?.imageUrl} style={{ borderRadius: 8, overflow: 'hidden', marginLeft: 5 }} /></div>}
+        {adcreativeElements?.imageUrlList && <div style={{ display: 'flex', alignItems: 'flex-start', flexWrap: 'wrap' }}><span style={{ marginRight: 4 }}><strong>创意素材:</strong></span> <Image.PreviewGroup>
             <Space wrap>
                 {adcreativeElements?.imageUrlList?.map((url: string, index: number) => <Image width={50} src={url} style={{ borderRadius: 4 }} key={'TOP_SLIDER' + index} />)}
             </Space>
         </Image.PreviewGroup></div>}
-        {adcreativeElements?.shortVideoStruct?.shortVideo1Url && <div style={{ display: 'flex', alignItems: 'flex-start' }}><span style={{ marginRight: 4 }}>创意素材:</span> <video src={adcreativeElements?.shortVideoStruct?.shortVideo1Url} width={130} controls></video></div>}
-        {adcreativeElements?.videoUrl && <div style={{ display: 'flex', alignItems: 'flex-start' }}><span style={{ marginRight: 4 }}>创意素材:</span> <video src={adcreativeElements?.videoUrl} width={130} controls></video></div>}
+        {overrideCanvasHeadOption && <div><strong>素材选项:</strong> <span style={{ color: "#5a5a5a" }}>{overrideCanvasHeadOptionEnum[overrideCanvasHeadOption]}</span></div>}
+        {adcreativeElements?.shortVideoStruct?.shortVideo1Url && <div style={{ display: 'flex', alignItems: 'flex-start' }}><span style={{ marginRight: 4 }}><strong>创意素材:</strong></span> <video src={adcreativeElements?.shortVideoStruct?.shortVideo1Url} width={130} controls></video></div>}
+        {adcreativeElements?.videoUrl && <div style={{ display: 'flex', alignItems: 'flex-start' }}><span style={{ marginRight: 4 }}><strong>创意素材:</strong></span> <video src={adcreativeElements?.videoUrl} width={130} controls></video></div>}
     </>
 }
 

+ 14 - 12
src/pages/launchSystemNew/launchManage/createAd/adgroupsCol.tsx

@@ -1,4 +1,4 @@
-import { BidModeEnum, BidStrategyEnum, OptimizationGoalEnum, PromotedObjectType, SiteSetEnum } from "@/services/launchAdq/enum"
+import { AdStatus, BidModeEnum, BidStrategyEnum, OptimizationGoalEnum, PromotedObjectType, SiteSetEnum } from "@/services/launchAdq/enum"
 import React from "react"
 
 
@@ -13,20 +13,22 @@ const AdgroupsCol = React.forwardRef((props: Props, ref) => {
 
     /*************************/
     const { data } = props
-    const { adgroupName, promotedObjectType, siteSet, endDate, beginDate, bidMode, optimizationGoal, smartBidType, bidStrategy, bidAmount, dailyBudget } = data
+    const { adgroupName, promotedObjectType, siteSet, endDate, beginDate, bidMode, optimizationGoal, smartBidType, bidStrategy, bidAmount, dailyBudget ,firstDayBeginTime,configuredStatus} = data
     /*************************/
 
     return <>
-        <div>广告名称: <span>{adgroupName}</span></div>
-        <div>推广目标: <span>{PromotedObjectType[promotedObjectType]}</span></div>
-        <div>广告版位: <span>{siteSet?.map((item: string) => SiteSetEnum[item]).toString()}</span></div>
-        <div>投放日期: <span>{endDate ? beginDate + '~' + endDate : beginDate + '~' + '长期投放'}</span></div>
-        <div>出价方式: <span>{BidModeEnum[bidMode]}</span></div>
-        {optimizationGoal && <div>优化目标: <span>{OptimizationGoalEnum[optimizationGoal]}</span></div>}
-        <div>出价类型: <span>{smartBidType === 'SMART_BID_TYPE_CUSTOM' ? '手动出价' : '自动出价'}</span></div>
-        {bidStrategy && <div>出价策略: <span>{BidStrategyEnum[bidStrategy]}</span></div>}
-        <div>广告出价: <span>{bidAmount}{`元/${OptimizationGoalEnum[optimizationGoal] || '千次曝光'}`}</span></div>
-        <div>广告日预算: <span>{dailyBudget || '不限'}</span></div>
+        <div><strong>广告名称:</strong> <span style={{color:"#5a5a5a"}}>{adgroupName}</span></div>
+        <div><strong>推广目标: </strong><span style={{color:"#5a5a5a"}}>{PromotedObjectType[promotedObjectType]}</span></div>
+        <div><strong>广告版位:</strong> <span style={{color:"#5a5a5a"}}>{siteSet?.map((item: string) => SiteSetEnum[item]).toString()}</span></div>
+        <div><strong>投放日期:</strong> <span style={{color:"#5a5a5a"}}>{endDate ? beginDate + '~' + endDate : beginDate + '~' + '长期投放'}</span></div>
+        {firstDayBeginTime && <div><strong>首日时间: </strong><span style={{color:"#5a5a5a"}}>{firstDayBeginTime}</span></div>}
+        <div><strong>出价方式: </strong><span style={{color:"#5a5a5a"}}>{BidModeEnum[bidMode]}</span></div>
+        {optimizationGoal && <div><strong>优化目标:</strong> <span style={{color:"#5a5a5a"}}>{OptimizationGoalEnum[optimizationGoal]}</span></div>}
+        <div><strong>出价类型:</strong> <span style={{color:"#5a5a5a"}}>{smartBidType === 'SMART_BID_TYPE_CUSTOM' ? '手动出价' : '自动出价'}</span></div>
+        {bidStrategy && <div><strong>出价策略:</strong> <span style={{color:"#5a5a5a"}}>{BidStrategyEnum[bidStrategy]}</span></div>}
+        <div><strong>广告出价:</strong> <span style={{color:"#5a5a5a"}}>{bidAmount}{`元/${OptimizationGoalEnum[optimizationGoal] || '千次曝光'}`}</span></div>
+        <div><strong>广告日预算:</strong> <span style={{color:"#5a5a5a"}}>{dailyBudget || '不限'}</span></div>
+        <div><strong>广告状态:</strong> <span style={{color:"#5a5a5a"}}>{AdStatus[configuredStatus||'AD_STATUS_SUSPEND']}</span></div>
     </>
 })
 

+ 122 - 0
src/pages/launchSystemNew/launchManage/createAd/creative/index.tsx

@@ -0,0 +1,122 @@
+import React, { useCallback, useState } from 'react'
+import { Button, Col, Space, Spin, Tabs, Tooltip, } from 'antd'
+import style from '../index.less'
+import CreativeModal from "../../../components/creativeModal"
+import { CreateAdProps } from '@/services/launchAdq/createAd'
+import { BaseResult } from '@ahooksjs/use-request/lib/types'
+import { ModalConfig } from '../ad'
+import AdcreativeCol from "../adcreativeCol"
+import CreativePup from './modal'
+
+type Props = {
+    queryForm: Partial<CreateAdProps>,
+    setQueryForm: React.Dispatch<React.SetStateAction<Partial<CreateAdProps>>>,
+    getSysAdgroups: BaseResult<any, any>,
+    getSysAdcreative: BaseResult<any, any>,
+    clearData: () => void,
+    targetKey: string,
+    page_checked: boolean,
+    set_targetKey: (key: string) => void
+}
+function Creative(props: Props) {
+    let { queryForm, getSysAdgroups, getSysAdcreative, setQueryForm, clearData, targetKey, set_targetKey, page_checked } = props
+    const [adModalConfig, setAdModalConfig] = useState<ModalConfig>({//新建广告弹窗
+        visible: false,
+        type: 'add'
+    })
+    const [creativeVisible, setCreativeVisible] = useState<boolean>(false) // 选择创意弹窗控制
+
+    // 设置变量
+    const handleAdModalConfig = useCallback((arg: ModalConfig) => {
+        setAdModalConfig({ ...adModalConfig, ...arg })
+    }, [adModalConfig])
+
+    // 获取创意详情
+    const getInfo = useCallback((sysAdcreativeId) => {
+        getSysAdcreative.run(sysAdcreativeId).then(res => {
+            let arr = queryForm.taskMediaMaps || []
+            let { createTime, ...params } = res
+            arr[targetKey] = { sysAdcreative: { ...params, isTemplate: false } }
+            setQueryForm({ ...queryForm, sysAdcreativeId, taskMediaMaps: arr });
+            setCreativeVisible(false);
+            clearData()
+        })
+    }, [queryForm, targetKey])
+
+    // tabs新增和删除
+    const onEdit = useCallback((targetKey: string | React.MouseEvent<Element, MouseEvent> | React.KeyboardEvent<Element>, action: 'add' | 'remove') => {
+        if (queryForm.taskMediaMaps) {
+            if (action === 'add') {
+                setQueryForm({ ...queryForm, taskMediaMaps: [...queryForm.taskMediaMaps, { sysAdcreative: '' }] })
+                set_targetKey(queryForm.taskMediaMaps.length.toString())
+            } else {
+                let arr = queryForm.taskMediaMaps || []
+                let adqPageArr = queryForm.adqPageList || []
+                let pageArr = queryForm.pageList || []
+                if (arr.length > 1) {
+                    arr = arr.filter((item, index) => index.toString() !== targetKey)
+                    adqPageArr = adqPageArr?.filter((item, index) => index.toString() !== targetKey)
+                    pageArr = pageArr?.filter((item, index) => index.toString() !== targetKey)
+                } else {
+                    arr = [{ sysAdcreative: '' }]
+                    adqPageArr = []
+                    pageArr = []
+                }
+                set_targetKey((Number(targetKey) === 0 ? 0 : Number(targetKey) - 1).toString())
+                setQueryForm({ ...queryForm, taskMediaMaps: arr, pageList: pageArr, adqPageList: adqPageArr })
+            }
+        }
+    }, [queryForm])
+    return <Col span={12} className={style.conRightBorder}>
+        <div className={style.top}>创意基本信息
+            {queryForm.taskMediaMaps && queryForm.taskMediaMaps?.length > 0 && <a onClick={() => {
+                setQueryForm({ ...queryForm, taskMediaMaps: [], sysAdcreativeId: undefined, pageList: [], adqPageList: [] })
+                set_targetKey('0')
+            }}>全部清空</a>}
+        </div>
+        <div className={style.center}>
+            <Tabs size={'small'} onEdit={onEdit} type="editable-card" activeKey={targetKey} onChange={(key) => { set_targetKey(key) }} >
+                {
+                    queryForm?.taskMediaMaps?.map((item, index) => {
+                        return <Tabs.TabPane key={index} tab={'创意' + (index + 1)}>
+                            <Spin spinning={getSysAdcreative.loading}>
+                                <div className={style.centerContent}>
+                                    {item.sysAdcreative && <AdcreativeCol data={item.sysAdcreative} />}
+                                </div>
+                            </Spin>
+                        </Tabs.TabPane >
+                    })
+                }
+            </Tabs>
+
+        </div>
+        <div className={style.bottom}>
+            <Space size={20}>
+                {queryForm?.sysAdgroup ? <>
+                    <span onClick={() => { setCreativeVisible(true) }}>{queryForm?.taskMediaMaps && queryForm?.taskMediaMaps[targetKey]?.sysAdcreative ? '重选创意' : '选择创意'}</span>
+                </> : <Tooltip title="请先设置广告">
+                    <span>选择创意</span>
+                </Tooltip>}
+                {queryForm?.sysAdgroup ? <>
+                    <span onClick={() => { handleAdModalConfig(queryForm?.taskMediaMaps && queryForm?.taskMediaMaps[targetKey]?.sysAdcreative ? { visible: true, type: 'edit' } : { visible: true, type: 'add' }) }}>{queryForm?.taskMediaMaps && queryForm?.taskMediaMaps[targetKey]?.sysAdcreative ? '编辑创意' : '新建创意'}</span>
+                </> : <Tooltip title="请先设置广告">
+                    <span>新建创意</span>
+                </Tooltip>}
+            </Space>
+        </div>
+        {/* 选择创意 */}
+        {creativeVisible && <CreativeModal siteSet={getSysAdgroups?.data?.siteSet} visible={creativeVisible} onClose={() => setCreativeVisible(false)} onChange={getInfo} sysAdcreativeId={queryForm?.sysAdcreativeId} promotedObjectType={queryForm.promotedObjectType as string} />}
+        {/* 创建创意 */}
+        {adModalConfig.visible && <CreativePup visible={adModalConfig.visible} type={adModalConfig.type} PupFn={handleAdModalConfig} callback={(values: any) => {
+            let arr = queryForm.taskMediaMaps || []
+            let adqPageArr: any = queryForm.adqPageList || []
+            let pageArr: any = queryForm.pageList || []
+            adqPageArr[targetKey as string] = null//清除adq落地页
+            pageArr[targetKey as string] = null//清除本地落地页
+            arr[targetKey] = { sysAdcreative: values }
+            setQueryForm({ ...queryForm, taskMediaMaps: arr, adqPageList: adqPageArr, pageList: pageArr }); setCreativeVisible(false); clearData();
+            handleAdModalConfig({ visible: false, dataInfo: null, type: 'add' })
+        }} dataInfo={queryForm?.taskMediaMaps && queryForm?.taskMediaMaps[targetKey]?.sysAdcreative} queryForm={queryForm} />}
+    </Col>
+}
+export default Creative

+ 196 - 0
src/pages/launchSystemNew/launchManage/createAd/creative/modal/brandImage.tsx

@@ -0,0 +1,196 @@
+import Tables from "@/components/Tables"
+import { useAjax } from "@/Hook/useAjax"
+import SelectCloud from "@/pages/launchSystemNew/components/selectCloud"
+import { addSysBrandApi, delSysBrandApi, editSysBrandApi, getSysBrandApi } from "@/services/launchAdq/global"
+import { PlusOutlined } from "@ant-design/icons"
+import { Button, Divider, Form, Input, message, Modal, Select, Space } from "antd"
+import React, { useEffect, useState } from "react"
+import { useModel } from "umi"
+import { brandColumns } from "./tableConfig"
+
+interface Props {
+    onChange?: (data: any) => void,
+    value?: any
+}
+
+/**
+ * 品牌形象
+ * @returns 
+ */
+const BrandImage: React.FC<Props> = (props) => {
+
+    /****************************/
+    const { onChange, value } = props
+
+    const [visible, setVisible] = useState<boolean>(false)
+    const [addVisible, setAddVisible] = useState<boolean>(false)
+    const [form] = Form.useForm()
+    const [initialValues, setInitialValues] = useState<any>({})
+
+    const getSysBrand = useAjax(() => getSysBrandApi())
+    const addSysBrand = useAjax((params) => addSysBrandApi(params))
+    const editSysBrand = useAjax((params) => editSysBrandApi(params))
+    const delSysBrand = useAjax((params) => delSysBrandApi(params))
+    /****************************/
+
+    // 获取列表
+    useEffect(() => {
+        getSysBrand.run()
+    }, [])
+
+
+    // 新增修改
+    const handleOk = async () => {
+        form.submit()
+        let data = await form.validateFields()
+        if (Object.keys(initialValues).length > 0) { // 修改
+            editSysBrand.run({ ...data, sysBrandId: initialValues.id }).then(res => {
+                if (res) {
+                    message.success('修改成功')
+                    setAddVisible(false)
+                    getSysBrand.refresh()
+                }
+            })
+        } else { // 新增
+            addSysBrand.run(data).then(res => {
+                if (res) {
+                    message.success('新增成功')
+                    setAddVisible(false)
+                    getSysBrand.refresh()
+                }
+            })
+        }
+        setInitialValues({})
+    }
+
+    /** 删除 */
+    const del = (id: number) => {
+        delSysBrand.run({ sysBrandId: id }).then(res => {
+            if (res) {
+                message.success('删除成功')
+                getSysBrand.refresh()
+            }
+        })
+    }
+
+    /** 修改 */
+    const edit = (data: any) => {
+        setInitialValues(data)
+        setAddVisible(true)
+    }
+
+    return <div>
+        <Select
+            showSearch
+            placeholder="请选择一个品牌跳转页,与广告创意一起展示"
+            optionFilterProp="children"
+            style={{ width: 400 }}
+            onChange={(e) => { onChange && onChange(e) }}
+            allowClear
+            value={value}
+            filterOption={(input, option) => {
+                return (option!.value as unknown as string).toLowerCase().includes(input.toLowerCase())
+            }}
+            dropdownRender={menu => <>
+                {menu}
+                <Divider style={{ margin: '8px 0' }} />
+                <div>
+                    <Button type="link" onClick={() => { setAddVisible(true); setInitialValues({}) }}>新增</Button>
+                    <Button type="link" onClick={() => setVisible(true)}>前往管理</Button>
+                </div>
+            </>}
+        >
+            {
+                getSysBrand?.data?.map((item: any) => {
+                    return <Select.Option value={item.name + '_' + item.brandImgUrl} key={item.id}>
+                        <Space>
+                            <img src={item.brandImgUrl} style={{ width: 20 }} />
+                            <span>{item.name}</span>
+                        </Space>
+                    </Select.Option>
+                })
+            }
+        </Select>
+
+        {visible && <Modal title="品牌形象" width={1000} visible={visible} footer={null} onCancel={() => setVisible(false)}>
+            <Space direction='vertical' style={{ width: '100%' }}>
+                <Button type="primary" icon={<PlusOutlined />} onClick={() => { setAddVisible(true); setInitialValues({}) }}>上传品牌形象</Button>
+                <Tables
+                    columns={brandColumns(del, edit)}
+                    dataSource={getSysBrand?.data}
+                    size="small"
+                    loading={getSysBrand?.loading}
+                    scroll={{ y: 300 }}
+                    bordered
+                />
+            </Space>
+        </Modal>}
+
+        {addVisible && <Modal title="上传品牌形象" visible={addVisible} confirmLoading={addSysBrand.loading} onOk={handleOk} onCancel={() => setAddVisible(false)}>
+            <Form
+                name="basic"
+                form={form}
+                layout='vertical'
+                autoComplete="off"
+                initialValues={{ ...initialValues }}
+            >
+                <Form.Item label={<strong>头像</strong>} name="brandImgUrl" rules={[{ required: true, message: '请选择头像!' }]}>
+                    <UploadImage />
+                </Form.Item>
+                <Form.Item label={<strong>名称</strong>} name="name" rules={[{ required: true, message: '请输入名称!' }]}>
+                    <Input placeholder="请输入名称" maxLength={12}/>
+                </Form.Item>
+            </Form>
+        </Modal>}
+    </div>
+}
+
+
+interface ImageProps {
+    onChange?: (value: string) => void,
+    value?: string
+}
+/**
+ * 处理选择图片Form
+ * @returns 
+ */
+export const UploadImage: 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) {
+            setSliderImgContent([{ url: value }])
+        } else {
+            setSliderImgContent([])
+        }
+    }, [value])
+
+    const setImg = (content: any[]) => {
+        onChange && onChange(content[0]?.url)
+        setSelectImgVisible(false)
+    }
+
+    const selectImg = () => {
+        init({ mediaType: 'IMG', cloudSize: [[{ relation: '=', width: 512, height: 512 }]], maxSize: 50 * 1024 })
+        setTimeout(() => { setSelectImgVisible(true) }, 50)
+    }
+
+    return <>
+        {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>
+
+        {/* 选择素材 */}
+        {selectImgVisible && <SelectCloud visible={selectImgVisible} sliderImgContent={sliderImgContent} onClose={() => setSelectImgVisible(false)} onChange={setImg} />}
+    </>
+}
+
+export default React.memo(BrandImage)

+ 80 - 0
src/pages/launchSystemNew/launchManage/createAd/creative/modal/config.ts

@@ -0,0 +1,80 @@
+/**使用外层创意素材替换原生推广页顶部素材*/
+export const overrideCanvasHeadOptionEnum = {
+  OPTION_KEEP_DIFFERENT: '自定义广告创意素材,和原生推广页顶部素材保持两者不同',
+  OPTION_CANVAS_OVERRIDE_CREATIVE: '使用原生推广页顶部素材作为外层创意素材',
+  OPTION_CREATIVE_OVERRIDE_CANVAS: '使用外层创意素材替换原生推广页顶部素材',
+};
+/**使用外层创意素材替换原生推广页顶部素材*/
+export const creativeConfig = {
+  311: {
+    overrideCanvasHeadOption: [
+      'OPTION_CANVAS_OVERRIDE_CREATIVE',
+      'OPTION_CREATIVE_OVERRIDE_CANVAS',
+    ],
+  },
+  641: {
+    overrideCanvasHeadOption: [
+      'OPTION_CANVAS_OVERRIDE_CREATIVE',
+      'OPTION_CREATIVE_OVERRIDE_CANVAS',
+    ],
+  },
+  642: {
+    overrideCanvasHeadOption: [
+      'OPTION_CANVAS_OVERRIDE_CREATIVE',
+      'OPTION_CREATIVE_OVERRIDE_CANVAS',
+    ],
+  },
+  643: {
+    overrideCanvasHeadOption: [
+      'OPTION_CANVAS_OVERRIDE_CREATIVE',
+      'OPTION_CREATIVE_OVERRIDE_CANVAS',
+    ],
+  },
+  618: {
+    overrideCanvasHeadOption: [
+      'OPTION_CANVAS_OVERRIDE_CREATIVE',
+      'OPTION_CREATIVE_OVERRIDE_CANVAS',
+    ],
+  },
+  711: {
+    overrideCanvasHeadOption: [
+      'OPTION_CANVAS_OVERRIDE_CREATIVE',
+      'OPTION_CREATIVE_OVERRIDE_CANVAS',
+    ],
+  },
+  712: {
+    overrideCanvasHeadOption: [
+      'OPTION_CANVAS_OVERRIDE_CREATIVE',
+      'OPTION_CREATIVE_OVERRIDE_CANVAS',
+    ],
+  },
+  720: {
+    overrideCanvasHeadOption: [
+      'OPTION_CANVAS_OVERRIDE_CREATIVE',
+      'OPTION_CREATIVE_OVERRIDE_CANVAS',
+    ],
+  },
+  721: {
+    //保持一致,替换
+    overrideCanvasHeadOption: [
+      'OPTION_CANVAS_OVERRIDE_CREATIVE',
+      'OPTION_CREATIVE_OVERRIDE_CANVAS',
+    ],
+  },
+  1707: {
+    //卡片横版大图
+    overrideCanvasHeadOption: [
+      'OPTION_KEEP_DIFFERENT',
+      'OPTION_CANVAS_OVERRIDE_CREATIVE',
+      'OPTION_CREATIVE_OVERRIDE_CANVAS',
+    ],
+  },
+  1708: {
+    //卡片横版视频
+    overrideCanvasHeadOption: [
+      'OPTION_KEEP_DIFFERENT',
+      'OPTION_CANVAS_OVERRIDE_CREATIVE',
+      'OPTION_CREATIVE_OVERRIDE_CANVAS',
+    ],
+  },
+};

+ 150 - 0
src/pages/launchSystemNew/launchManage/createAd/creative/modal/headNickJump.tsx

@@ -0,0 +1,150 @@
+import Tables from "@/components/Tables"
+import { useAjax } from "@/Hook/useAjax"
+import { addSysProfileApi, delSysProfileApi, editSysProfileApi, getSysProfileApi } from "@/services/launchAdq/global"
+import { PlusOutlined } from "@ant-design/icons"
+import { Button, Divider, Form, Input, message, Modal, Select, Space } from "antd"
+import React, { useEffect, useState } from "react"
+import { UploadImage } from "./brandImage"
+import { profileColumns } from "./tableConfig"
+
+interface Props {
+    onChange?: (data: any) => void,
+    value?: any
+}
+
+/**
+ * 头像及昵称跳转页
+ * @returns 
+ */
+const HeadNickJump: React.FC<Props> = (props) => {
+
+    /****************************/
+    const { onChange, value } = props
+
+    const [visible, setVisible] = useState<boolean>(false)
+    const [addVisible, setAddVisible] = useState<boolean>(false)
+    const [form] = Form.useForm()
+    const [initialValues, setInitialValues] = useState<any>({})
+
+    const getSysProfile = useAjax(() => getSysProfileApi())
+    const addSysProfile = useAjax((params) => addSysProfileApi(params))
+    const editSysProfile = useAjax((params) => editSysProfileApi(params))
+    const delSysProfile = useAjax((params) => delSysProfileApi(params))
+    /****************************/
+
+    // 获取列表
+    useEffect(() => {
+        getSysProfile.run()
+    }, [])
+
+
+    // 新增修改
+    const handleOk = async () => {
+        form.submit()
+        let data = await form.validateFields()
+        if (Object.keys(initialValues).length > 0) { // 修改
+            editSysProfile.run({ ...data, sysProfileId: initialValues.id }).then(res => {
+                if (res) {
+                    message.success('修改成功')
+                    setAddVisible(false)
+                    getSysProfile.refresh()
+                }
+            })
+        } else { // 新增
+            addSysProfile.run(data).then(res => {
+                if (res) {
+                    message.success('新增成功')
+                    setAddVisible(false)
+                    getSysProfile.refresh()
+                }
+            })
+        }
+        setInitialValues({})
+        form.resetFields()
+    }
+
+    /** 删除 */
+    const del = (id: number) => {
+        delSysProfile.run({ sysProfileId: id }).then(res => {
+            if (res) {
+                message.success('删除成功')
+                getSysProfile.refresh()
+            }
+        })
+    }
+
+    /** 修改 */
+    const edit = (data: any) => {
+        setInitialValues(data)
+        setAddVisible(true)
+    }
+
+    return <div>
+        <Select
+            showSearch
+            placeholder="请选择一个品牌跳转页,与广告创意一起展示"
+            optionFilterProp="children"
+            style={{ width: 400 }}
+            onChange={(e) => { onChange && onChange(e) }}
+            allowClear
+            value={value}
+            filterOption={(input, option) => {
+                return (option!.value as unknown as string).toLowerCase().includes(input.toLowerCase())
+            }}
+            dropdownRender={menu => <>
+                {menu}
+                <Divider style={{ margin: '8px 0' }} />
+                <div>
+                    <Button type="link" onClick={() => { setAddVisible(true); setInitialValues({}) }}>新增</Button>
+                    <Button type="link" onClick={() => setVisible(true)}>前往管理</Button>
+                </div>
+            </>}
+        >
+            {
+                getSysProfile?.data?.map((item: any) => {
+                    return <Select.Option value={item.profileName + '_' + item.headImageUrl + '_' + item.description} key={item.id}>
+                        <Space>
+                            <img src={item.headImageUrl} style={{ width: 20 }} />
+                            <span>{item.profileName}</span>
+                        </Space>
+                    </Select.Option>
+                })
+            }
+        </Select>
+
+        {visible && <Modal title="头像及昵称跳转页" width={1000} visible={visible} footer={null} onCancel={() => setVisible(false)}>
+            <Space direction='vertical' style={{ width: '100%' }}>
+                <Button type="primary" icon={<PlusOutlined />} onClick={() => { setAddVisible(true); setInitialValues({}) }}>上传品牌形象</Button>
+                <Tables
+                    columns={profileColumns(del, edit)}
+                    dataSource={getSysProfile?.data}
+                    size="small"
+                    loading={getSysProfile?.loading}
+                    scroll={{ y: 300 }}
+                    bordered
+                />
+            </Space>
+        </Modal>}
+        {addVisible && <Modal title={`${Object.keys(initialValues).length > 0 ? '修改' : '上传'}头像及昵称跳转页`} visible={addVisible} confirmLoading={addSysProfile.loading || editSysProfile.loading} onOk={handleOk} onCancel={() => setAddVisible(false)}>
+            <Form
+                name="basic"
+                form={form}
+                layout='vertical'
+                autoComplete="off"
+                initialValues={{ ...initialValues }}
+            >
+                <Form.Item label={<strong>头像</strong>} name="headImageUrl" rules={[{ required: true, message: '请选择头像!' }]}>
+                    <UploadImage />
+                </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" rules={[{ required: true, message: '请输入详细描述!' }]}>
+                    <Input.TextArea placeholder="请输入详细描述" maxLength={120} />
+                </Form.Item>
+            </Form>
+        </Modal>}
+    </div>
+}
+
+export default React.memo(HeadNickJump)

+ 93 - 0
src/pages/launchSystemNew/launchManage/createAd/creative/modal/index.less

@@ -0,0 +1,93 @@
+.adcreative_template{
+    width: 100%;
+    overflow-y: auto;
+    display: flex;
+    height: 173px;
+    >label{
+        height: 100%;
+        margin-right: 15px;
+    }
+}
+.videoImgs{
+    width: 100%;
+    overflow-y: auto;
+    display: flex;
+    img{
+        width: 100%;
+    }
+    label{
+        height: 100%;
+        padding: 0;
+        width: 32%;
+        margin-right: 1%;
+    }
+}
+.adcreative_template_item{
+    width: 150px;
+    height: 160px;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    flex-flow: column;
+}
+
+.video{
+  
+}
+.box {
+    width: 60%;
+    height: 200px;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    background-color: #f5f7fa;
+    flex-direction: column;
+    color: rgba(0,0,0,.3);
+    border-radius: 5px;
+    >p{
+        display: flex;
+        align-items: center;
+        flex-flow: column;
+        font-size: 10px;
+        cursor: pointer;
+        max-height: 150px;
+        margin-bottom:0;
+        img{
+            height: 100%;
+        }
+        video{
+            height: 100%;
+        }
+    }
+}
+
+.image_list{
+    flex-flow: row wrap;
+    background-color: transparent;
+    height:auto;
+    justify-content: flex-start;
+    >p{
+        width: 150px;
+        background-color: #f5f7fa;
+        height: 150px;
+        display: flex;
+        align-items: center;
+        justify-content: center;
+        border: 1px solid #e6e8ed;
+        margin: 0;
+    }
+}
+.crt{
+    display: inline-flex;
+    align-items: center;
+    width: auto;
+    margin-left: 8px;
+    padding: 1px 4px;
+    height: 16px;
+    border-radius: 3px;
+    font-size: 12px;
+    color: #fff;
+    border: 1px solid #296bef;
+    background-color: #296bef;
+    line-height: normal;
+}

+ 1103 - 0
src/pages/launchSystemNew/launchManage/createAd/creative/modal/index.tsx

@@ -0,0 +1,1103 @@
+import React, { useCallback, useEffect, useMemo, useState } from 'react'
+import { Modal, Form, Input, Divider, Select, Radio, Switch, Spin, List, Checkbox, Space, Button, message, Image, Empty } from 'antd'
+import styles from './index.less'
+import { useAjax } from '@/Hook/useAjax'
+import { getText, get_adcreative_template, get_adcreative_template_list, get_tools_video_capture } from '@/services/launchAdq/global'
+import { AdcreativeTemplate, AdcreativeTemplateList } from '@/services/launchAdq'
+import { mySet } from '@/utils/arrFn'
+import SelectCloud from '@/pages/launchSystemNew/components/selectCloud'
+import { useModel } from 'umi'
+import { ModalConfig } from '../../ad';
+import { outAdcreativeTemplateIdFun } from '../../../localAd/adenum'
+import { CreateAdProps } from '@/services/launchAdq/createAd'
+import { createSysAdcreative } from '@/services/launchAdq/creative'
+import { creativeConfig, overrideCanvasHeadOptionEnum } from './config'
+import BrandImage from './brandImage'
+import HeadNickJump from './headNickJump'
+interface Props {
+    queryForm: Partial<CreateAdProps>,
+    title?: string,
+    visible: boolean,
+    PupFn: (arg: ModalConfig) => void,
+    callback: (params: any) => void,
+    confirmLoading?: boolean,
+    type?: 'add' | 'look' | 'edit',//新增,查看,编辑
+    dataInfo?: any
+}
+
+/**创意模板*/
+function CreativePup(props: Props) {
+    let { visible, confirmLoading, PupFn, callback, type, dataInfo, queryForm } = props
+    let [template_checked, settemplate_checked] = useState<boolean>(dataInfo?.isTemplate || false)
+    let { promotedObjectType, sysAdgroup } = queryForm
+    let { siteSet } = sysAdgroup
+    const { init } = useModel('useLaunchAdq.useBdMediaPup')
+    let arg = type === 'look' ? { footer: null } : {}
+    // 请求
+    const getAdcreativeTemplate = useAjax((params) => get_adcreative_template(params))
+    const getAdcreativeTemplateList = useAjax((params) => get_adcreative_template_list(params))
+    const getTextLsit = useAjax((params) => getText(params))
+    const addSysAdgroup = useAjax((params) => createSysAdcreative(params))
+    const getVideoCapture = useAjax((params) => get_tools_video_capture(params))
+    // 变量
+    const [adcreative_template, set_adcreative_template] = useState<AdcreativeTemplate>()
+    const [adcreative_template_list, set_adcreative_template_list] = useState<AdcreativeTemplateList[]>([])
+    const [selectImgVisible, set_selectImgVisible] = useState(false)
+    const [selectVideoVisible, set_selectVideoVisible] = useState(false)
+    const [videoImgsVisbile, set_videoImgsVisbile] = useState(false)
+    const [descriptionShow, setdescriptionshow] = useState(false)
+    const [endPageDescShow, setendPageDescnshow] = useState(false)
+    const [isShowSc, set_isShowSc] = useState(false)//是否展示素材选项
+    const [infoSet, set_infoSet] = useState(false)//回填设置已完成
+    const [videoImgs, set_videoImgs] = useState<{//视频封面图设置
+        activeUrl: string,//选中的视频封面图地址
+        preview: boolean,//是否开启图片点击预览
+        urlList: any[],//生成的视频封面列表
+    }>({
+        activeUrl: '',
+        preview: false,
+        urlList: [
+            'https://test-adq-media.oss-cn-hangzhou.aliyuncs.com/image/21D8D51AD98C4FF8BF41F1C2D28EA39F.jpg',
+            'https://test-adq-media.oss-cn-hangzhou.aliyuncs.com/image/80DBE1AB3EDE4E85ABAE5F1670D9FED0.jpg',
+            'https://test-adq-media.oss-cn-hangzhou.aliyuncs.com/image/BCB2DAB86BDB4549BCB8E493C4F29E82.jpg',
+            'https://test-adq-media.oss-cn-hangzhou.aliyuncs.com/image/545A4C2A5B874C82A9D1C0C063624AE5.jpg'
+        ]
+    })
+    const [titleShow, settitleshow] = useState(false)
+    const [form] = Form.useForm();
+    const [pupState, setPupState] = useState({
+        kp_show: false,
+        xd_show: false,
+        sj_show: false,
+        bq_show: false,
+        sp_show: false
+    })
+    const [imgMaterialConfig, setImgMaterialConfig] = useState<{
+        adcreativeTemplateId?: number,
+        type: string,
+        cloudSize: { relation: string, width: number, height: number }[],
+        list: any[],
+        max: number
+    }>({
+        type: '',//类型
+        cloudSize: [],//素材搜索条件
+        list: [],//素材
+        max: 1,//素材数量
+    })//图片素材配置
+    const [videoMaterialConfig, setVideoMaterialConfig] = useState<{
+        adcreativeTemplateId?: number,
+        type: string,
+        cloudSize: { relation: string, width: number, height: number }[],
+        list: any[],
+        max: number
+    }>({
+        type: '',//类型
+        cloudSize: [],//素材搜索条件
+        list: [],//素材
+        max: 1,//素材数量
+    })//图片素材配置
+    const [conversionList, setConversionList] = useState<any>(null)
+    let pageType = Form.useWatch('pageType', form)
+    let adcreativeTemplateId = Form.useWatch('adcreativeTemplateId', form)
+    let actionBtn = Form.useWatch('actionBtn', form)
+    // let siteSet = Form.useWatch('siteSet', form)
+    let overrideCanvasHeadOption = Form.useWatch('overrideCanvasHeadOption', form)
+    let adcreativeElementsType = Form.useWatch('adcreativeElementsType', form)
+    let dataShow = Form.useWatch('dataShow', form)
+    let conversionDataType = Form.useWatch('conversionDataType', form)
+    let titles = Form.useWatch('title', form)
+    let description = Form.useWatch('description', form)
+    let videoOver = Form.useWatch('videoOver', form)
+    let endPageDesc = Form.useWatch('endPageDesc', form)
+    let linkPageType = Form.useWatch('linkPageType', form)
+
+    // 确定事件
+    const handleOk = useCallback(() => {
+        form.validateFields().then(values => {
+            console.log('values=>1', values)
+            let newValues = JSON.parse(JSON.stringify(values))
+            for (let key in newValues) {
+                switch (key) {
+                    case 'image'://图素材
+                        newValues.adcreativeElements = {
+                            ...newValues.adcreativeElements,
+                            imageUrl: imgMaterialConfig?.list[0]?.url,
+                        }
+                        delete newValues[key]
+                        break;
+                    case 'video'://视频素材
+                        newValues.adcreativeElements = {
+                            ...newValues.adcreativeElements,
+                            videoUrl: videoMaterialConfig?.list[0]?.url,
+                        }
+                        delete newValues[key]
+                        break;
+                    case 'image_list'://图素材
+                        newValues.adcreativeElements = {
+                            ...newValues.adcreativeElements,
+                            imageUrlList: imgMaterialConfig.list?.map(item => item.url),
+                            description: newValues.description,
+                        }
+                        delete newValues[key]
+                        break;
+                    case 'short_video1'://视频素材
+                        newValues.adcreativeElements = {
+                            ...newValues.adcreativeElements,
+                            shortVideoStruct: {
+                                shortVideo1Url: videoMaterialConfig?.list[0]?.url
+                            },
+                            description: newValues.description,
+                        }
+                        delete newValues[key]
+                        break;
+                    case 'description'://文案
+                        newValues.adcreativeElements = { ...newValues.adcreativeElements, description: newValues.description }
+                        break;
+                    case 'title'://文案
+                        newValues.adcreativeElements = { ...newValues.adcreativeElements, title: newValues.title }
+                        break;
+                    case 'endPageType'://视频结束l类型
+                        newValues.adcreativeElements = { ...newValues.adcreativeElements, endPage: { ...newValues.adcreativeElements.endPage, endPageType: newValues.endPageType } }
+                        delete newValues[key]
+                        break;
+                    case 'endPageDesc'://视频结束文案
+                        newValues.adcreativeElements = { ...newValues.adcreativeElements, endPage: { ...newValues.adcreativeElements.endPage, endPageDesc: newValues.endPageDesc } }
+                        delete newValues[key]
+                        break;
+                    case 'buttonText'://特殊行动按钮
+                        newValues.adcreativeElements = { ...newValues.adcreativeElements, buttonText: newValues.buttonText }
+                        delete newValues[key]
+                        break;
+                    case 'brand'://品牌形象
+                        newValues.adcreativeElements = {
+                            ...newValues.adcreativeElements, brand: {
+                                brandName: newValues.brand.split('_')[0],
+                                brandImgUrl: newValues.brand.split('_')[1]
+                            }
+                        }
+                        break;
+                    case 'profile':
+                        newValues.adcreativeElements = {
+                            ...newValues.adcreativeElements, brand: {
+                                brandName: newValues.profile.split('_')[0],
+                                brandImgUrl: newValues.profile.split('_')[1]
+                            }
+                        }
+                        newValues.profile = {
+                            headImageUrl: newValues.profile.split('_')[1],
+                            profileName: newValues.profile.split('_')[0],
+                            description: newValues.profile.split('_')[2]
+                        }
+                        break
+                    case 'pageUrl'://跳转落地页
+                        newValues.linkPageSpec = {
+                            ...newValues.linkPageSpec,
+                            pageUrl: newValues.pageUrl
+                        }
+                        delete newValues.pageUrl
+                        break;
+                    case 'miniProgramId':
+                        newValues.linkPageSpec = {
+                            ...newValues.linkPageSpec,
+                            miniProgramSpec: {
+                                miniProgramId: newValues.miniProgramId,
+                                miniProgramPath: newValues.miniProgramPath
+                            }
+                        }
+                        delete newValues.miniProgramId
+                        delete newValues.miniProgramPath
+                        break;
+                }
+            }
+            if (!newValues.adcreativeElements) {
+                newValues.adcreativeElements = {}
+            }
+            //假如不存在promotedObjectType
+            if (!newValues?.promotedObjectType) {
+                newValues['promotedObjectType'] = queryForm.promotedObjectType
+            }
+            // 假如不存在siteSet
+            if (!newValues?.siteSet) {
+                newValues['siteSet'] = queryForm.sysAdgroup.siteSet
+            }
+            delete newValues.description //删除外层文案
+            delete newValues.title //删除外层文案
+            delete newValues.adcreativeElementsType //删除创意形式
+            delete newValues.dataShow //删除数据开关
+            delete newValues.actionBtn //删除行动开关
+            delete newValues.brand //品牌形象
+            // 假如使用了落地页顶部素材替换外部素材
+            if (newValues.overrideCanvasHeadOption === 'OPTION_CANVAS_OVERRIDE_CREATIVE') {
+                console.log(adcreative_template?.adcreativeElements)
+                adcreative_template?.adcreativeElements?.filter(item => item.required && item.name === 'image_list' || item.name === 'short_video1' || item.name === 'video' || item.name === 'image').forEach(item => {
+                    switch (item.name) {
+                        case 'image'://图素材
+                            newValues.adcreativeElements = {
+                                ...newValues.adcreativeElements,
+                                imageUrl: '',
+                            }
+                            break;
+                        case 'video'://视频素材
+                            newValues.adcreativeElements = {
+                                ...newValues.adcreativeElements,
+                                videoUrl: '',
+                            }
+                            break;
+                        case 'image_list'://图素材
+                            newValues.adcreativeElements = {
+                                ...newValues.adcreativeElements,
+                                imageUrlList: [],
+                            }
+                            break;
+                        case 'short_video1'://视频素材
+                            newValues.adcreativeElements = {
+                                ...newValues.adcreativeElements,
+                                shortVideoStruct: {
+                                    shortVideo1Url: ''
+                                },
+                            }
+                            break;
+                    }
+                })
+            }
+            console.log('newValues=>2', newValues)
+            newValues['isTemplate'] = template_checked
+            // // 开启存为模板开关执行
+            callback(newValues)
+        })
+    }, [form, imgMaterialConfig, videoMaterialConfig, queryForm, template_checked, adcreative_template, isShowSc])
+    // 获取创意形式列表
+    useEffect(() => {
+        if (siteSet?.length > 0 && promotedObjectType) {
+            getAdcreativeTemplateList.run({
+                siteSet,
+                promotedObjectType,
+                campaignType: 'CAMPAIGN_TYPE_NORMAL',
+            }).then(res => {
+                let newArr: any = []
+                // 过滤掉相同的和即将下线的
+                if (!res) {
+                    return
+                }
+                // 
+                Object.values(res)?.forEach((arr: any) => {
+                    Array.isArray(arr) && arr?.forEach((item: any) => {
+                        if (newArr.length > 0) {//假如已存在ID,需要过滤相同
+                            if (outAdcreativeTemplateIdFun(item.adcreativeTemplateId) && newArr.every((i: { adcreativeTemplateId: any }) => i.adcreativeTemplateId !== item.adcreativeTemplateId)) {//不重复的添加
+                                newArr.push(item)
+                            } else {
+                                // 找出通用创意
+                                newArr = newArr?.map((arr: { adcreativeTemplateId: any }) => {
+                                    if (arr.adcreativeTemplateId === item.adcreativeTemplateId) {
+                                        return { ...arr, isGeneral: true }
+                                    }
+                                    return arr
+                                })
+                            }
+                        } else {//不存在ID直接过滤掉即将下线的
+                            if (outAdcreativeTemplateIdFun(item.adcreativeTemplateId)) {
+                                newArr.push(item)
+                            }
+                        }
+                    })
+                })
+                /*****暂时排除激励和banner有问题******/
+                if (siteSet.some((i: string) => i === 'SITE_SET_MOMENTS')) {
+                    newArr = newArr.filter((item: { adcreativeTemplateId: number }) => item.adcreativeTemplateId !== 910 && item.adcreativeTemplateId !== 925)
+                }
+                set_adcreative_template_list(newArr)
+            })
+        }
+    }, [siteSet, promotedObjectType])
+    // 获取创意形式详情
+    const getTemplate = useCallback((id: any, ok?: any) => {
+        // CAMPAIGN_TYPE_NORMAL
+        if (siteSet?.length > 0 && promotedObjectType && id) {
+            if (id) {
+                getAdcreativeTemplate.run({
+                    siteSet,
+                    promotedObjectType,
+                    adcreativeTemplateId: id
+                }).then(res => {
+                    if (res?.length > 0) {
+                        set_adcreative_template(res[0])
+                        if (siteSet?.some((name: string) => name === 'SITE_SET_MOMENTS')) {
+                            let id = res[0].adcreativeTemplateId
+                            set_isShowSc(!!creativeConfig[id])//判定当前创意是否需要展示替换素材选项
+                            if (creativeConfig[id] && !ok) {//假如不等于回填元素的ID
+                                form.setFieldsValue({ overrideCanvasHeadOption: creativeConfig[id].overrideCanvasHeadOption[0] })
+                            }
+                        }
+                        templateChange(res[0], ok)
+                    }
+                })
+            }
+        }
+    }, [siteSet, promotedObjectType])
+    // 获取对应落地页按钮
+    const pageTypeList = useMemo(() => {
+        if (adcreativeTemplateId) {
+            let arr: any = adcreative_template?.landingPageConfig?.supportPageTypeList
+            return arr
+        }
+        return null
+
+    }, [adcreativeTemplateId, adcreative_template])
+    // 获取对应行动按钮数据
+    const linkNameList = useMemo(() => {
+        if (pageType) {
+            let arr = (pageTypeList?.filter((item: { pageType: any; }) => item.pageType === pageType)[0] as any)?.supportLinkNameType?.list
+            return arr
+        }
+        return null
+    }, [pageType, pageTypeList])
+    // 跳转落地页
+    const linkPageList = useMemo(() => {
+        if (pageType) {
+            let arr = (pageTypeList?.filter((item: { pageType: any; }) => item.pageType === pageType)[0] as any)?.supportLinkPageType?.list
+            return arr
+        }
+        return null
+    }, [pageType, pageTypeList])
+    const typeChange = useCallback((adcreativeElementsType) => {
+        if (adcreativeElementsType && adcreative_template_list?.length > 0) {
+            let adcreativeTemplateIdArr = adcreative_template_list?.filter(item => item.adcreativeTemplateStyle === adcreativeElementsType)
+            console.log('typeChange====>', adcreativeTemplateIdArr[0].adcreativeTemplateId)
+            getTemplate(adcreativeTemplateIdArr[0].adcreativeTemplateId)
+            form.setFieldsValue({ adcreativeTemplateId: adcreativeTemplateIdArr[0].adcreativeTemplateId })
+
+        }
+    }, [adcreative_template_list])
+
+    //每次选中创意设置该展示的界面
+    const templateChange = useCallback((adcreative_template, ok?: any) => {
+        let states = {
+            kp_show: false,
+            xd_show: true,
+            sj_show: false,
+            bq_show: false,
+            sp_show: false
+        }
+        let values: any = { pageType: 'PAGE_TYPE_CANVAS_WECHAT', }
+        if (adcreative_template) {
+            let pageList = adcreative_template?.landingPageConfig?.supportPageTypeList?.filter((i: { description: string | string[] }) => i.description.includes('微信原生推广页'))//当前版本只获取微信原生页,后期改进
+            let pageType = pageList?.length ? pageList[0]?.pageType : null
+            //数据展示组件
+            if (adcreative_template.adcreativeAttributes.some((item: { name: string }) => item.name === 'conversion_data_type' || item.name === 'conversion_target_type')) {
+                let arr = adcreative_template.adcreativeAttributes?.filter((item: { name: string; }) => item.name === 'conversion_data_type' || item.name === 'conversion_target_type')
+                let newObj: any = {}
+                arr.forEach((item: { propertyDetail: { enumDetail: { enumeration: any[] } }; name: string | number }) => {
+                    let arr: any[] = mySet(item.propertyDetail.enumDetail.enumeration)
+                    newObj[item.name] = arr
+                })
+                setConversionList(newObj)
+                states = { ...states, sj_show: true }
+                if (newObj.conversion_data_type) {
+                    values = { ...values, conversionDataType: newObj.conversion_data_type[0].value }
+                }
+                if (newObj.conversion_target_type) {
+                    values = { ...values, conversionTargetType: newObj.conversion_target_type[0].value }
+                }
+            }
+
+            //行动按钮组件存在
+            if (states.xd_show) {
+                let linkNameList = (pageList?.filter((item: { pageType: any; }) => item.pageType === pageType)[0] as any)?.supportLinkNameType?.list
+                let linkPageList = (pageList?.filter((item: { pageType: any; }) => item.pageType === pageType)[0] as any)?.supportLinkPageType?.list
+                if (linkNameList && !linkPageType) {
+                    if (!ok) {
+                        let linkNameType = linkNameList[0]?.linkNameType
+                        let linkPageType = linkPageList?.some((i: { linkPageType: string }) => i.linkPageType === "LINK_PAGE_TYPE_CANVAS_WECHAT") ? "LINK_PAGE_TYPE_CANVAS_WECHAT" : linkPageList[0]?.linkPageType
+                        values = { ...values, linkNameType, linkPageType, actionBtn: true }
+                    }
+                } else {
+                    states = { ...states, xd_show: false }
+                }
+            }
+            // 特殊行动按钮
+            if (adcreative_template.adcreativeElements?.find((item: { name: string }) => item.name === 'button_text') && !ok) {
+                values = { ...values, buttonText: adcreative_template?.adcreativeElements?.find((item: { name: string }) => item.name === 'button_text')?.enumProperty?.enumeration[0].value }
+            }
+            // 视频结束页 end_page
+            if (adcreative_template.adcreativeElements.some((item: { name: string }) => item.name === 'end_page')) {
+                // let endPageType =adcreative_template?.adcreativeElements?.filter(item=>item.name === 'end_page_type')[0]?.enumProperty?.enumeration
+                if (!ok) {
+                    values = { ...values, endPageType: 'END_PAGE_AVATAR_NICKNAME_HIGHLIGHT' }
+                }
+                states = { ...states, sp_show: true }
+            }
+            setPupState(states)
+            form.setFieldsValue(values)
+        }
+    }, [pageType, linkPageType])
+    // 版位改变清空数据
+    useEffect(() => {
+        if (imgMaterialConfig.adcreativeTemplateId && adcreativeTemplateId !== imgMaterialConfig.adcreativeTemplateId) {
+            setImgMaterialConfig({ ...imgMaterialConfig, adcreativeTemplateId: undefined, list: [] })
+        }
+        if (videoMaterialConfig.adcreativeTemplateId && adcreativeTemplateId !== videoMaterialConfig.adcreativeTemplateId) {
+            setVideoMaterialConfig({ ...videoMaterialConfig, adcreativeTemplateId: undefined, list: [] })
+        }
+    }, [adcreativeTemplateId, imgMaterialConfig, videoMaterialConfig])
+    // 文案助手
+    const textList = useCallback((arg: { maxTextLength: number, keyword?: string }) => {
+        let { maxTextLength, keyword } = arg
+        getTextLsit.run({ keyword: keyword || titles || description, maxTextLength })
+    }, [titles, description])
+    // 监听点击取消文案助手弹窗
+    useEffect(() => {
+        let modal = document.querySelector('.myModal')
+        let onBiurdescription = (e: any) => {
+            let d = document.querySelector('.my_description')
+            let t = document.querySelector('.my_title')
+            let p = document.querySelector('.my_endPageDesc')
+            if (!d?.contains(e.target)) {
+                setdescriptionshow(false)
+            }
+            if (!t?.contains(e.target)) {
+                settitleshow(false)
+            }
+            if (!p?.contains(e.target)) {
+                setendPageDescnshow(false)
+            }
+        }
+        modal?.addEventListener('click', onBiurdescription)
+        return () => {
+            modal?.removeEventListener('click', onBiurdescription)
+        }
+
+    }, [])
+    // 数据回填
+    useEffect(() => {
+        if (!infoSet && dataInfo && adcreative_template_list?.length > 0) {
+            let { adcreativeName, adcreativeTemplateId, conversionDataType, conversionTargetType, linkNameType, linkPageType, pageType, promotedObjectType, siteSet, profile, adcreativeElements, overrideCanvasHeadOption, linkPageSpec } = dataInfo
+            let { description, imageUrl, title, videoUrl, imageUrlList, endPage, shortVideoStruct, brand, buttonText } = adcreativeElements
+            let obj: any = {
+                adcreativeName,
+                siteSet,
+                promotedObjectType,
+                adcreativeTemplateId,
+            }
+            getTemplate(adcreativeTemplateId, true)
+            console.log(2222,dataInfo)
+            if ([720, 721, 618, 1708, 722, 1529].some(n => n === adcreativeTemplateId)) {
+                obj = { ...obj, adcreativeElementsType: '视频' }
+            } else {
+                obj = { ...obj, adcreativeElementsType: '图片' }
+            }
+            if (conversionDataType) {
+                obj = { ...obj, conversionDataType, dataShow: true }
+            }
+            if (conversionTargetType) {
+                obj = { ...obj, conversionTargetType, dataShow: true }
+            }
+            if (linkNameType) {
+                obj = { ...obj, linkNameType, actionBtn: true }
+            }
+            if (linkPageType) {
+                obj = { ...obj, linkPageType, actionBtn: true }
+            }
+            if (pageType) {
+                obj = { ...obj, pageType }
+            }
+            if (description) {
+                obj = { ...obj, description }
+            }
+            if (title) {
+                obj = { ...obj, title }
+            }
+            if (endPage) {
+                obj = { ...obj, videoOver: true, ...endPage }
+            }
+            if (overrideCanvasHeadOption) {
+                obj = { ...obj, overrideCanvasHeadOption }
+            }
+            if (linkPageSpec?.pageUrl) {
+                obj = { ...obj, pageUrl: linkPageSpec?.pageUrl }
+            }
+            if (linkPageSpec?.miniProgramSpec && linkPageSpec?.miniProgramSpec?.miniProgramPath) {
+                obj = { ...obj, miniProgramPath: linkPageSpec?.miniProgramSpec?.miniProgramPath, miniProgramId: linkPageSpec?.miniProgramSpec?.miniProgramId }
+            }
+            if (brand && brand.brandImgUrl && brand.brandName) {
+                obj = { ...obj, brand: brand.brandName + '_' + brand.brandImgUrl }
+            }
+            if (profile && profile.headImageUrl && profile.profileName && profile.description) {
+                obj = { ...obj, profile: profile.profileName + '_' + profile.headImageUrl + '_' + profile.description}
+            }
+            if(buttonText){
+                obj = {...obj,buttonText}
+            }
+            if (videoUrl) {
+                setVideoMaterialConfig({
+                    cloudSize: [],
+                    list: [{ url: videoUrl }],
+                    max: 1,
+                    type: 'video',
+                    adcreativeTemplateId
+                })
+                obj = { ...obj, video: videoUrl }
+            }
+            if (imageUrl) {
+                setImgMaterialConfig({
+                    cloudSize: [],
+                    list: [{ url: imageUrl }],
+                    max: 1,
+                    type: 'image',
+                    adcreativeTemplateId
+                })
+                obj = { ...obj, image: imageUrl }
+            }
+            if (imageUrlList) {
+                setImgMaterialConfig({
+                    cloudSize: [],
+                    list: imageUrlList?.map((url: any) => ({ url })),
+                    max: imageUrlList.length,
+                    type: 'image_list',
+                    adcreativeTemplateId
+                })
+                obj = { ...obj, image_list: imageUrlList }
+            }
+            if (shortVideoStruct) {
+                setVideoMaterialConfig({
+                    cloudSize: [],
+                    list: [{ url: shortVideoStruct.shortVideo1Url }],
+                    max: 1,
+                    type: 'short_video1',
+                    adcreativeTemplateId
+                })
+                obj = { ...obj, short_video1: shortVideoStruct.shortVideo1Url }
+            }
+            console.log('数据回填====>', obj)
+            form.setFieldsValue(obj)
+            set_infoSet(true)
+        }
+        // 不是数据回填首次打开界面选中视频
+        if (!infoSet && !dataInfo && adcreative_template_list?.length > 0) {
+            typeChange('视频')
+            set_infoSet(true)
+        }
+    }, [dataInfo, adcreative_template_list, adcreative_template, infoSet])
+    // 生成视频封面图
+    const videoToImgs = useCallback(() => {
+        if (videoMaterialConfig.list[0]) {
+            set_videoImgsVisbile(true)
+            // let url = videoMaterialConfig.list[0].url
+            // fetch(url).then(res => res.blob()).then(async (blob) => {
+            //     let file = new File([blob], 'sp', { type: blob.type })
+            //     // let md5 = await getMD5(file)
+            //     let formData = new FormData()
+            //     formData.append('videoFile', file)
+            //     formData.append('number', '12')
+            //     getVideoCapture.run(formData).then(res => {
+            //         console.log(res)
+            //     })
+            // })
+        } else {
+            message.warning('请先选择视频文件!!!')
+        }
+    }, [videoMaterialConfig.list])
+    return <Modal
+        visible={visible}
+        title={type === 'add' ? '新建创意' : type === 'look' ? '创意详情' : '编辑创意'}
+        onCancel={() => { PupFn({ visible: false, dataInfo: null, type: 'add' }) }}
+        // onOk={handleOk}
+        width={1200}
+        confirmLoading={confirmLoading}
+        footer={<Space>
+            <Button onClick={() => { PupFn({ visible: false, dataInfo: null, type: 'add' }) }}>取消</Button>
+            <Button type='primary' onClick={handleOk}>确定</Button>
+            {<Checkbox checked={template_checked} onChange={(e) => {
+                let checked = e.target.checked
+                settemplate_checked(checked)
+            }}>存为模板</Checkbox>}
+        </Space>}
+        className='myModal'
+        {...arg}
+    >
+        <Form
+            form={form}
+            labelCol={{ span: 5 }}
+            labelWrap={true}
+            className='ad_form_style'
+            initialValues={
+                {
+                    adcreativeElementsType: '视频',
+                }
+            }
+        >
+            {/* ============================================================基本信息============================================================= */}
+            <Divider orientation='center'>基本信息</Divider>
+            {/* ============================================================创意名称============================================================= */}
+            <Form.Item label={<strong>创意名称</strong>} name='adcreativeName' rules={[{ required: true, message: '请输入广告名称!' }]}>
+                <Input placeholder='创意名称' style={{ width: 300 }} />
+            </Form.Item>
+            {/* ============================================================创意形式============================================================= */}
+            <Divider orientation='center'>创意形式</Divider>
+            {/* ============================================================创意形式============================================================= */}
+            <Form.Item label={<strong>创意形式</strong>} name='adcreativeElementsType'>
+                <Radio.Group onChange={(e) => {
+                    let value = e.target.value
+                    typeChange(value)
+                }}>
+                    <Radio.Button value="视频">视频</Radio.Button>
+                    <Radio.Button value="图片">图片</Radio.Button>
+                </Radio.Group>
+            </Form.Item>
+
+            {
+                getAdcreativeTemplateList?.loading ? <Spin tip="Loading..." style={{ width: '100%' }}></Spin> :
+                    <>
+                        <Form.Item style={{ marginLeft: 177 }} name='adcreativeTemplateId'>
+                            <Radio.Group className={styles.adcreative_template} onChange={(e) => {
+                                let id = e.target.value
+                                getTemplate(id)
+                            }}>
+                                {
+                                    adcreative_template_list?.filter(item => item.adcreativeTemplateStyle === adcreativeElementsType)?.map((item: any) => {
+                                        return <Radio.Button value={item.adcreativeTemplateId} key={item.adcreativeTemplateId}>
+                                            <div className={styles.adcreative_template_item}>
+                                                {item.isGeneral && <span style={{ color: '#4080ff', fontSize: 10 }}>所选版位通投</span>}
+                                                <img src={item.adcreativeSampleImage} />
+                                                <span style={{ fontSize: 12, height: 20, lineHeight: '20px' }}>{item.adcreativeTemplateAppellation}</span>
+                                                <span style={{ fontSize: 12, height: 20, lineHeight: '20px' }}>{item.adcreativeTemplateId}</span>
+                                            </div>
+                                        </Radio.Button>
+                                    })
+                                }
+                            </Radio.Group>
+                        </Form.Item>
+                        {/* ============================================================创意内容============================================================= */}
+                        <Divider orientation='center'>创意内容</Divider>
+                        {/* =============================================================头像及昵称跳转页===================================================================== */}
+                        {queryForm.promotedObjectType === 'PROMOTED_OBJECT_TYPE_LEAD_AD' ? adcreative_template?.adcreativeAttributes?.find(item => item.name === 'profile_id') ? <Form.Item label={<strong>头像及昵称跳转页</strong>} name='profile' rules={[{ required: true, message: '请选择一个头像及昵称跳转页,与广告创意一起展示' }]}>
+                            <HeadNickJump />
+                        </Form.Item> : <Form.Item label={<strong>品牌形象</strong>} name='brand' rules={[{ required: true, message: '请选择一个头像及昵称跳转页,与广告创意一起展示' }]}>
+                            <BrandImage />
+                        </Form.Item> : null}
+                        {/* ============================================================素材============================================================= */}
+                        {/* 优先展示视频或图片,朋友圈常规不勾选使用外部素材替换内部,隐藏此选项,后期自动将落地页顶部素材添加进入 */}
+                        {((overrideCanvasHeadOption !== 'OPTION_CANVAS_OVERRIDE_CREATIVE') || siteSet.every((name: string) => name !== 'SITE_SET_MOMENTS')) && <div style={{ display: 'flex', flexFlow: 'column' }}>
+                            {
+                                adcreative_template?.adcreativeElements?.filter(item => item.required && item.name === 'image_list' || item.name === 'short_video1' || item.name === 'video' || item.name === 'image').map(item => {
+                                    return <Form.Item
+                                        label={<strong>{item.description === '图片' && adcreative_template?.adcreativeElements?.some(item => item.name === 'video') ? '视频封面图' : item.description}</strong>}
+                                        key={item.name}
+                                    >
+                                        {/* 视频 */}
+                                        {
+                                            (item.name === 'short_video1' || item.name === 'video') && <Form.Item
+                                                noStyle
+                                                rules={[{ required: true, message: '请选择素材!' }]}
+                                                name={item.name}
+                                                style={item.description === '图片' && adcreative_template?.adcreativeElements?.some(item => item.name === 'video') ? { order: 2 } : {}}
+                                            >
+                                                <div className={`${styles.box} ${styles.video}`} onClick={() => {
+                                                    init({ mediaType: 'VIDEO', cloudSize: adcreativeTemplateId === 1708 ? [[{ relation: '=', width: 1280, height: 720 }]] : [[{ relation: '=', width: item.restriction.videoRestriction.minWidth, height: item.restriction.videoRestriction.minHeight }]], maxSize: item.restriction.videoRestriction.fileSize * 1024 })
+                                                    setTimeout(() => {
+                                                        set_selectVideoVisible(true)
+                                                        setVideoMaterialConfig({
+                                                            ...videoMaterialConfig,
+                                                            type: item.name,
+                                                            max: 1,
+                                                            adcreativeTemplateId
+                                                        })
+                                                    }, 100)
+                                                }}>
+                                                    <p>
+                                                        {
+                                                            videoMaterialConfig?.list[0] ? <video src={videoMaterialConfig?.list[0].url} controls /> : <>
+                                                                <span>{`推荐尺寸(${adcreativeTemplateId === 1708 ? 1280 : item.restriction.videoRestriction.minWidth} x ${adcreativeTemplateId === 1708 ? 720 : item.restriction.videoRestriction.minHeight})`}</span>
+                                                                <span>{`${item.restriction.videoRestriction.fileFormat?.map(str => str?.replace('MEDIA_TYPE_', ''))};< ${item.restriction.videoRestriction.fileSize / 1024}M;时长 ≥ ${item.restriction.videoRestriction.minDuration}s,≤ ${item.restriction.videoRestriction.maxDuration}s,必须带有声音`}</span>
+                                                            </>
+                                                        }
+                                                    </p>
+                                                </div>
+                                            </Form.Item>
+                                        }
+                                        {/* 单图 */}
+                                        {
+                                            item.name === 'image' && <Form.Item
+                                                noStyle
+                                                rules={[{ required: true, message: '请选择素材!' }]}
+                                                name={item.name}
+                                                style={item.description === '图片' && adcreative_template?.adcreativeElements?.some(item => item.name === 'video') ? { order: 2 } : {}}
+                                            >
+                                                <div className={`${styles.box} ${styles.image}`} onClick={() => {
+                                                    init({ mediaType: 'IMG', cloudSize: [[{ relation: '=', width: item.restriction.imageRestriction.width, height: item.restriction.imageRestriction.height }]], maxSize: item.restriction.imageRestriction.fileSize * 1024 })
+                                                    setTimeout(() => {
+                                                        set_selectImgVisible(true)
+                                                        setImgMaterialConfig({
+                                                            ...imgMaterialConfig,
+                                                            type: item.name,
+                                                            max: 1,
+                                                            adcreativeTemplateId
+                                                        })
+                                                    }, 100)
+
+                                                }}>
+                                                    <p>
+                                                        {imgMaterialConfig?.list[0] ? <img src={imgMaterialConfig?.list[0].url} /> : <>
+                                                            <span>{`推荐尺寸(${item.restriction.imageRestriction.width} x ${item.restriction.imageRestriction.height})`}</span>
+                                                            <span>{`${item.restriction.imageRestriction.fileFormat?.map(str => str?.replace('IMAGE_TYPE_', ''))};小于 ${item.restriction.imageRestriction.fileSize}KB`}</span>
+                                                        </>}
+                                                    </p>
+                                                </div>
+                                            </Form.Item>
+                                        }
+                                        {/* {
+                                            item.description === '图片' && adcreative_template?.adcreativeElements?.some(item => item.name === 'video') && <Button onClick={videoToImgs} size='small' type='primary' disabled={!videoMaterialConfig.list[0]}>从视频生成封面图</Button>
+                                        } */}
+                                        {/* 多图 */}
+                                        {
+                                            item.name === 'image_list' && <Form.Item
+                                                noStyle
+                                                rules={[{ required: true, message: '请选择素材!' }]}
+                                                name={item.name}
+                                                style={item.description === '图片' && adcreative_template?.adcreativeElements?.some(item => item.name === 'video') ? { order: 2 } : {}}
+                                            >
+                                                <div className={`${styles.box} ${item.arrayProperty.maxNumber >= 3 ? styles.image_list : styles.image}`} onClick={() => {
+                                                    init({ mediaType: 'IMG', num: item.arrayProperty.maxNumber, cloudSize: [[{ relation: '=', width: item.restriction.imageRestriction.width, height: item.restriction.imageRestriction.height }]], maxSize: item.restriction.imageRestriction.fileSize * 1024 })
+                                                    setTimeout(() => {
+                                                        set_selectImgVisible(true)
+                                                        setImgMaterialConfig({
+                                                            ...imgMaterialConfig,
+                                                            type: item.name,
+                                                            max: item.arrayProperty.maxNumber,
+                                                            adcreativeTemplateId
+                                                        })
+                                                    }, 100)
+                                                }}>
+                                                    {
+                                                        Array(item.arrayProperty.maxNumber).fill('').map((arr, index) => {
+                                                            return <p key={index}>
+                                                                {
+                                                                    imgMaterialConfig?.list[index] ? <img src={imgMaterialConfig?.list[index].url} /> : <>
+                                                                        <span>{`推荐尺寸(${item.restriction.imageRestriction.width} x ${item.restriction.imageRestriction.height})`}</span>
+                                                                        <span>{`${item.restriction.imageRestriction.fileFormat?.map(str => str?.replace('IMAGE_TYPE_', ''))};小于 ${item.restriction.imageRestriction.fileSize}KB`}</span>
+                                                                    </>
+                                                                }
+
+                                                            </p>
+                                                        })
+                                                    }
+                                                </div>
+                                            </Form.Item>
+                                        }
+                                    </Form.Item>
+                                })
+                            }
+                        </div>}
+
+                        {/* 标题 */}
+                        {
+                            adcreative_template?.adcreativeElements?.filter(item => item.name === 'title').map(item => {
+                                return <div key={item.fieldType}>
+                                    <Form.Item label={<strong>{item.description}(选填)</strong>} className={'my_title'} >
+                                        <Form.Item name={item.name} rules={[{ pattern: RegExp(item.restriction.textRestriction.textPattern?.replace(/\+/ig, `{1,${item.restriction.textRestriction.maxLength}}`)), message: '请输入正确的' + item.description }]} noStyle>
+                                            <Input
+                                                placeholder={'请输入' + item.description}
+                                                style={{ width: 500 }}
+                                                allowClear
+                                                onFocus={() => {
+                                                    settitleshow(true)
+                                                    textList({ maxTextLength: item.restriction.textRestriction.maxLength })
+                                                }}
+                                                onChange={(e) => {
+                                                    let value = e.target.value
+                                                    textList({ maxTextLength: item.restriction.textRestriction.maxLength, keyword: value })
+                                                }}
+                                            />
+                                        </Form.Item>
+                                        <span>{`${titles?.length ?? 0}/${item.restriction.textRestriction.maxLength}`}</span>
+                                        {
+                                            titleShow && <List
+                                                loading={getTextLsit?.loading}
+                                                size="small"
+                                                style={{ maxHeight: 300, overflowX: 'auto' }}
+                                                bordered
+                                                dataSource={getTextLsit?.data?.returnTexts}
+                                                renderItem={(item: any) => <List.Item onClick={() => {
+                                                    form.setFieldsValue({ title: item.text })
+                                                    settitleshow(false)
+                                                }}><span >{item.text}{item.tag && <span className={styles.crt}>{'CTR 高'}</span>}</span></List.Item>}
+                                            />
+                                        }
+                                    </Form.Item>
+                                </div>
+                            })
+                        }
+                        {//过滤了不必传和品牌名称,品牌标识图(外部传)短视频结构(组装使用)
+                            adcreative_template?.adcreativeElements?.filter(item => item.required && item.name === 'description').map(item => {
+                                let maxNum = adcreativeTemplateId === 1708 || adcreativeTemplateId === 1707 ? pupState.xd_show ? 10 : item.restriction.textRestriction.maxLength : item.restriction.textRestriction.maxLength
+                                return <div key={item.fieldType}>
+                                    <Form.Item label={<strong>{item.description}</strong>} className={'my_description'}>
+                                        <Form.Item name={item.name} noStyle rules={[{ required: true, pattern: RegExp(item.restriction.textRestriction.textPattern?.replace(/\+/ig, `{1,${maxNum}}`)), message: '请输入正确的' + item.description }]}>
+                                            <Input
+                                                placeholder={'请输入' + item.description}
+                                                style={{ width: 500 }}
+                                                onFocus={() => {
+                                                    setdescriptionshow(true)
+                                                    textList({ maxTextLength: maxNum })
+                                                }}
+                                                onChange={(e) => {
+                                                    let value = e.target.value
+                                                    textList({ maxTextLength: maxNum, keyword: value })
+                                                }}
+                                                allowClear
+                                            />
+                                        </Form.Item>
+                                        <span>{`${description?.length ?? 0}/${maxNum}`}</span>
+                                        {
+                                            descriptionShow && <List
+                                                loading={getTextLsit?.loading}
+                                                size="small"
+                                                style={{ maxHeight: 300, overflowX: 'auto' }}
+                                                bordered
+                                                dataSource={getTextLsit?.data?.returnTexts}
+                                                renderItem={(item: any) => <List.Item onClick={(e: any) => {
+                                                    form.setFieldsValue({ description: item.text })
+                                                    setdescriptionshow(false)
+                                                }}><span >{item.text}{item.tag && <span className={styles.crt}>{'CTR 高'}</span>}</span></List.Item>}
+                                            />
+                                        }
+                                    </Form.Item>
+                                </div>
+                            })
+                        }
+                        {/* ============================================================落地页============================================================= */}
+                        {adcreativeTemplateId ? <Form.Item label={<strong>落地页</strong>} name='pageType' >
+                            <Radio.Group>
+                                {
+                                    pageTypeList?.map((item: any) => {
+                                        return <Radio.Button value={item.pageType} key={item.pageType} disabled={!item.description.includes('微信原生推广页')}>{item.description.includes('微信原生推广页') ? '微信原生推广页' : item.description}</Radio.Button>
+                                    })
+                                }
+                            </Radio.Group>
+                        </Form.Item> : <div style={{ minHeight: 400, display: 'flex', justifyContent: 'center', alignItems: 'center' }}>
+                            <Empty description="请先选择创意形式" />
+                        </div>}
+                        {
+                            pageType === 'PAGE_TYPE_CANVAS_WECHAT' && isShowSc && <Form.Item label={<strong>素材选项</strong>} name='overrideCanvasHeadOption'>
+                                <Radio.Group >
+                                    {
+                                        adcreativeTemplateId && creativeConfig[adcreativeTemplateId]?.overrideCanvasHeadOption?.map((item: string | number) => {
+                                            return <Radio value={item} key={item}>{overrideCanvasHeadOptionEnum[item]}</Radio>
+                                        })
+                                    }
+                                </Radio.Group>
+                            </Form.Item>
+                        }
+                        {/* ============================================================普通行动按钮============================================================= */}
+                        {
+                            pupState.xd_show && <Form.Item label={<strong>行动按钮</strong>} name='actionBtn' valuePropName="checked">
+                                <Switch checkedChildren="开启" unCheckedChildren="关闭" />
+                            </Form.Item>
+                        }
+                        {
+                            actionBtn && <>
+                                <Form.Item name='linkNameType' label={<strong>按钮文案</strong>}>
+                                    <Select style={{ width: 200 }} showSearch filterOption={(input, option) =>
+                                        (option!.children as unknown as string).toLowerCase().includes(input.toLowerCase())
+                                    } allowClear>
+                                        {
+                                            linkNameList?.map((item: any) => {
+                                                return <Select.Option value={item.linkNameType} key={item.linkNameType}>{item.description}</Select.Option>
+                                            })
+                                        }
+                                    </Select>
+                                </Form.Item>
+                                <Form.Item label={<strong>跳转落地页</strong>}>
+                                    <Form.Item name='linkPageType' noStyle>
+                                        <Radio.Group style={{ display: 'flex' }}>
+                                            {
+                                                linkPageList?.map((item: { linkPageType: string; description: string; }, index: number) => {
+                                                    return <Radio.Button value={item.linkPageType} key={item.linkPageType} >{item.description}</Radio.Button>
+                                                })
+                                            }
+                                        </Radio.Group>
+                                    </Form.Item>
+                                    {/* 自定义落地页地址 */}
+                                    {linkPageType === "LINK_PAGE_TYPE_DEFAULT" && <Form.Item name='pageUrl' rules={[{ required: true, message: '请输入自定义落地页地址' }]} style={{ marginTop: 10, marginBottom: 0 }}>
+                                        <Input placeholder='请输入自定义落地页地址' style={{ width: 300 }} />
+                                    </Form.Item>}
+                                    {/* 小程序 */}
+                                    {
+                                        linkPageType === "LINK_PAGE_TYPE_MINI_PROGRAM_WECHAT" && <Form.Item noStyle >
+                                            <Form.Item rules={[{ required: true, message: '请输入小程序原始ID' }]} name='miniProgramId' style={{ marginTop: 10, marginBottom: 0 }} >
+                                                <Input placeholder='请输入小程序原始ID' style={{ width: 300 }} />
+                                            </Form.Item>
+                                            <Form.Item rules={[{ required: true, message: '请输入小程序链接' }]} name='miniProgramPath' style={{ marginTop: 10, marginBottom: 0 }}>
+                                                <Input placeholder='请输入小程序链接' style={{ width: 300 }} />
+                                            </Form.Item>
+                                        </Form.Item>
+                                    }
+                                </Form.Item>
+                                {/* 落地页 */}
+
+                            </>
+                        }
+                        {/* ============================================================特殊行动按钮============================================================= */}
+                        {
+                            adcreative_template?.adcreativeElements?.find(item => item.name === 'button_text') && <Form.Item label={<strong>行动按钮</strong>} >
+                                <Form.Item valuePropName="checked" noStyle >
+                                    <Switch checkedChildren="开启" unCheckedChildren="关闭" checked={true} disabled defaultChecked={true} />
+                                </Form.Item>
+                            </Form.Item>
+                        }
+                        {
+                            adcreative_template?.adcreativeElements?.find(item => item.name === 'button_text') && <Form.Item name='buttonText' label={<strong>按钮文案</strong>} rules={[{ required: true, message: '请选择按钮文案!' }]}>
+                                <Select style={{ width: 200 }} showSearch filterOption={(input, option) =>
+                                    (option!.children as unknown as string).toLowerCase().includes(input.toLowerCase())
+                                } allowClear>
+                                    {
+                                        adcreative_template?.adcreativeElements?.find(item => item.name === 'button_text')?.enumProperty?.enumeration?.map((item: any) => {
+                                            return <Select.Option value={item.value} key={item.value}>{item.value}</Select.Option>
+                                        })
+                                    }
+                                </Select>
+                            </Form.Item>
+                        }
+                        {/* ============================================================数据展示============================================================= */}
+                        {pupState.sj_show && <Form.Item label={<strong>数据展示</strong>} name='dataShow' valuePropName="checked">
+                            <Switch checkedChildren="开启" unCheckedChildren="关闭" />
+                        </Form.Item>}
+                        {
+                            dataShow && <>
+                                <Form.Item name='conversionDataType' label={<strong>数据类型</strong>}>
+                                    <Radio.Group>
+                                        {
+                                            conversionList?.conversion_data_type?.map((item: { value: string; description: string; }, index: number) => {
+                                                return <Radio.Button value={item.value} key={item.value}>{item.description}</Radio.Button>
+                                            })
+                                        }
+                                    </Radio.Group>
+                                </Form.Item>
+                                {conversionList?.conversion_target_type && conversionDataType === 'CONVERSION_DATA_ADMETRIC' && <Form.Item name='conversionTargetType' label={<strong>转化行为</strong>}>
+                                    <Radio.Group>
+                                        {
+                                            conversionList?.conversion_target_type?.map((item: { value: string; description: string; }, index: number) => {
+                                                return <Radio.Button value={item.value} key={item.value}>{item.description}</Radio.Button>
+                                            })
+                                        }
+                                    </Radio.Group>
+                                </Form.Item>}
+                            </>
+                        }
+                        {/* ============================================================视频结束页============================================================= */}
+                        {pupState.sp_show && <Form.Item label={<strong>视频结束页</strong>} name='videoOver' valuePropName="checked">
+                            <Switch checkedChildren="开启" unCheckedChildren="关闭" />
+                        </Form.Item>}
+                        {
+                            videoOver && <>
+                                <Form.Item name='endPageType' label={<strong>视频结束页类型</strong>} >
+                                    <Radio.Group>
+                                        {
+                                            adcreative_template?.adcreativeElements?.filter(item => item.name === 'end_page_type')[0]?.enumProperty?.enumeration?.map((item) => {
+                                                return <Radio.Button value={item.value} key={item.value}>{item.description}</Radio.Button>
+                                            })
+                                        }
+                                    </Radio.Group>
+                                </Form.Item>
+                                <div className={'my_endPageDesc'} >
+                                    <Form.Item label={<strong>结束文案</strong>}>
+                                        <Form.Item name='endPageDesc' rules={[{ required: true, pattern: RegExp("^[^\\<\\>\\&'\\\"\\/\\x08\\x09\\x0A\\x0D\\\\]{1,12}$"), message: '请输入正确的结束页文案' }]} noStyle>
+                                            <Input
+                                                placeholder='请输入结束页文案'
+                                                style={{ width: 300 }}
+                                                onFocus={() => {
+                                                    setendPageDescnshow(true)
+                                                    textList({ maxTextLength: 12 })
+                                                }}
+                                                onChange={(e) => {
+                                                    let value = e.target.value
+                                                    textList({ maxTextLength: 12, keyword: value })
+                                                }}
+                                                allowClear
+                                            />
+                                        </Form.Item>
+                                        <span>{endPageDesc?.length || 0}/12</span>
+                                        {
+                                            endPageDescShow && <List
+                                                loading={getTextLsit?.loading}
+                                                size="small"
+                                                style={{ maxHeight: 300, maxWidth: 300, overflowX: 'auto' }}
+                                                bordered
+                                                dataSource={getTextLsit?.data?.returnTexts}
+                                                renderItem={(item: any) => <List.Item onClick={(e: any) => {
+                                                    form.setFieldsValue({ endPageDesc: item.text })
+                                                    setendPageDescnshow(false)
+                                                }}><span >{item.text}{item.tag && <span className={styles.crt}>{'CTR 高'}</span>}</span></List.Item>}
+                                            />
+                                        }
+                                    </Form.Item>
+                                </div>
+                            </>
+                        }
+                    </>
+            }
+        </Form>
+        {/* 选择图片素材 */}
+        {
+            selectImgVisible && <SelectCloud
+                visible={selectImgVisible}
+                onClose={() => {
+                    set_selectImgVisible(false)
+                }}
+                sliderImgContent={imgMaterialConfig.list}
+                onChange={(content) => {
+                    if (content.length > 0) {
+                        form.setFieldsValue({ [imgMaterialConfig.type]: imgMaterialConfig.type })
+                    }
+                    setImgMaterialConfig({ ...imgMaterialConfig, list: content })
+                    set_selectImgVisible(false)
+                }} />
+        }
+        {/* 选择视频素材 */}
+        {
+            selectVideoVisible && <SelectCloud
+                visible={selectVideoVisible}
+                onClose={() => set_selectVideoVisible(false)}
+                sliderImgContent={videoMaterialConfig.list}
+                onChange={(content) => {
+                    if (content.length > 0) {
+                        form.setFieldsValue({ [videoMaterialConfig.type]: videoMaterialConfig.type })
+                    }
+                    setVideoMaterialConfig({ ...videoMaterialConfig, list: content })
+                    set_selectVideoVisible(false)
+                }} />
+        }
+        {/* 视频封面图弹窗 */}
+        {
+            videoImgsVisbile && <Modal
+                visible={videoImgsVisbile}
+                title={<div>生成封面图 <Switch checkedChildren="开启预览" unCheckedChildren="关闭预览" checked={videoImgs.preview} onChange={(checked) => { set_videoImgs({ ...videoImgs, preview: checked }) }} /></div>}
+                onOk={() => {
+                    if (videoImgs.activeUrl) {
+                        setImgMaterialConfig({ ...imgMaterialConfig, list: [{ url: videoImgs.activeUrl }] })
+                        set_videoImgsVisbile(false)
+                    } else {
+                        message.error('请选择图片,获取使用取消按钮关闭弹窗!')
+                    }
+                }}
+                onCancel={() => { set_videoImgsVisbile(false) }}
+                confirmLoading={getVideoCapture.loading}
+                width={600}
+            >
+
+                <Radio.Group className={styles.videoImgs} onChange={(e) => {
+                    let url = e.target.value
+                    set_videoImgs({ ...videoImgs, activeUrl: url })
+                }}>
+                    {
+                        videoImgs?.urlList?.map((item: any, index: number) => {
+                            return <Radio.Button value={item} key={index}>
+                                <Image src={item} preview={videoImgs.preview} />
+                            </Radio.Button>
+                        })
+                    }
+                </Radio.Group>
+            </Modal>
+        }
+    </Modal >
+}
+export default CreativePup

+ 152 - 0
src/pages/launchSystemNew/launchManage/createAd/creative/modal/tableConfig.tsx

@@ -0,0 +1,152 @@
+import React from "react"
+import { Image, Popconfirm, Space } from 'antd'
+
+let brandColumns = (del: (id: number) => void, edit: (data: any) => void) => {
+
+
+    let data: any[] = [
+        {
+            title: '操作',
+            dataIndex: 'cz',
+            key: 'cz',
+            align: 'center',
+            width: 100,
+            render: (a: any, b: any) => {
+                return <Space>
+                    <a onClick={() => edit(b)}>修改</a>
+                    <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: 'brandImgUrl',
+            key: 'brandImgUrl',
+            width: 120,
+            ellipsis: true,
+            align: 'center',
+            render: (a: any, b: any) => {
+                return <Image width={40} style={{ borderRadius: 4 }} src={a} />
+            }
+        },
+        {
+            title: '头像名称',
+            dataIndex: 'name',
+            key: 'name',
+            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
+}
+
+let profileColumns = (del: (id: number) => void, edit: (data: any) => void) => {
+
+
+    let data: any[] = [
+        {
+            title: '操作',
+            dataIndex: 'cz',
+            key: 'cz',
+            align: 'center',
+            width: 100,
+            render: (a: any, b: any) => {
+                return <Space>
+                    <a onClick={() => edit(b)}>修改</a>
+                    <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, b: 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 {
+    brandColumns,
+    profileColumns
+}

+ 11 - 2
src/pages/launchSystemNew/launchManage/createAd/index.less

@@ -5,7 +5,11 @@
     font-weight: 600;
   }
 }
-
+// #page_tabs,#ad_tabs{
+//   >div>div>div>div{
+//     padding: 5px;
+//   }
+// }
 
 .selector {
   border: 1px solid #dcdee2;
@@ -80,6 +84,10 @@
             font-size: 12px;
             color: rgb(90, 90, 90);
           }
+          >a{
+            font-size: 12px;
+            font-weight: 400;
+          }
         }
 
         .center {
@@ -147,7 +155,8 @@
           height: 40px;
           text-align: center;
           line-height: 40px;
-
+          display: flex;
+          justify-content: center;
           span {
             cursor: pointer;
             color: #108ee9;

+ 360 - 260
src/pages/launchSystemNew/launchManage/createAd/index.tsx

@@ -6,28 +6,26 @@ import { PromotedObjectType } from "@/services/launchAdq/enum"
 import { getTagsList } from "@/services/launchAdq/global"
 import { getSysAdgroupsInfo } from "@/services/launchAdq/localAd"
 import { getsysTargetingInfo } from "@/services/launchAdq/targeting"
-import { CloseOutlined, EditOutlined, QuestionCircleOutlined, SearchOutlined } from "@ant-design/icons"
-import { Button, Card, Col, Empty, Row, Select, Space, Spin, Tooltip, Image, message, Popover } from "antd"
-import React, { useEffect, useRef, useState } from "react"
+import { CloseOutlined, SearchOutlined } from "@ant-design/icons"
+import { Button, Card, Col, Empty, Row, Select, Space, Spin, Tooltip, Image, message, Tabs } from "antd"
+import React, { useCallback, useEffect, useState } from "react"
 import { useModel } from "umi"
-import AdModal from "../../components/adModal"
-import CreativeModal from "../../components/creativeModal"
-import CrowdPackModal from "../../components/crowdPackModal"
+import Ad from "./ad"
 import DataSourceModal from "../../components/dataSourceModal"
 import GoodsModal from "../../components/goodsModal"
 import IdModal from "../../components/idModal"
 import LookLanding from "../../components/lookLanding"
 import PageModal from "../../components/pageModal"
 import SelectCloud from "../../components/selectCloud"
-import TargetingModal from "../../components/targetingModal"
-import TargetingTooltip from "../../components/targetingTooltip"
 import { WxAutoButton } from "../../req"
-import AdcreativeCol from "./adcreativeCol"
-import AdgroupsCol from "./adgroupsCol"
 import style from './index.less'
 import Selector from "./selector"
 import SubmitModal from "./submitModal"
 import columns from "./tableConfig"
+import TargetIng from './targeting'
+import Creative from './creative'
+import AddGroup from '../../components/addGroup'
+import CustomerServiceModal from "../../components/customerServiceModal"
 
 const CreateAd: React.FC = () => {
 
@@ -38,32 +36,36 @@ const CreateAd: React.FC = () => {
         campaignType: 'CAMPAIGN_TYPE_NORMAL', // 计划类型 CAMPAIGN_TYPE_NORMAL CAMPAIGN_TYPE_SEARCH 
         promotedObjectType: 'PROMOTED_OBJECT_TYPE_WECHAT_OFFICIAL_ACCOUNT', // 推广目标类型
         speedMode: 'SPEED_MODE_STANDARD', // 投放速度模式
-        sysAdgroupId: undefined,  // 广告组内容
+        sysAdgroupId: undefined,  // 广告组ID
+        sysAdgroup: undefined,//广告组内容
         sysTargetingId: undefined,  // 定向包 id
+        sysTargeting: undefined,  // 定向包 内容
         adgroupName: undefined,  // 广告名称
         configuredStatus: 'AD_STATUS_SUSPEND',  // 广告状态
         sysAdcreativeId: undefined, // 创意ID
-        sysPageId: undefined, // 落地页Id
+        taskMediaMaps: [], // 创意内容
+        pageList: [],//本地落地页详情入口
+        adqPageList: [],//云落地页
     })
     const [accountCreateLogs, setAccountCreateLogs] = useState<{ adAccountId: number, id: number, userActionSetsList?: number, productList?: any, conversionList?: any, customAudienceList?: any, excludedCustomAudienceList?: any, pageList?: any }[]>([])  // 账户
+    const { currentUser: { userId } }: any = useModel('@@initialState', model => ({ currentUser: model.initialState?.currentUser }))
 
-    const [adVisible, setAdVisible] = useState<boolean>(false) // 选择广告弹窗控制
-    const [dxVisible, setDxVisible] = useState<boolean>(false) // 选择定向弹窗控制
-    const [creativeVisible, setCreativeVisible] = useState<boolean>(false) // 选择创意弹窗控制
     const [goodsVisible, setGoodsVisible] = useState<boolean>(false) // 选择商品弹窗控制
     const [sourceVisible, setSourceVisible] = useState<boolean>(false) // 选择数据源弹窗控制
     const [idVisible, setIdVisible] = useState<boolean>(false) // 选择转化ID弹窗控制
     const [selectImgVisible, setSelectImgVisible] = useState<boolean>(false) // 选择转化ID弹窗控制
     const [lookVisible, setLookVisible] = useState<boolean>(false) // 选择转化ID弹窗控制
     const [subVisible, setSubVisible] = useState<boolean>(false) // 选择设置名称弹窗控制
-    const [cpVisible, setCpVisible] = useState<boolean>(false) // 选择设置名称弹窗控制
     const [pageVisible, setPageVisible] = useState<boolean>(false) // 选择云端落地页控制
-    const [wxButtonList, setWxButtonList] = useState<WxAutoButton[]>([])
     const [tableData, setTableData] = useState<any[]>([])   // 预览表格
     const [tableSelect, setTableSelect] = useState<any[]>([])
     const [geoLocationList, setGeoLocationList] = useState<any>({}) // 所有地域列表
     const [modelList, setModelList] = useState<any>({})  // 所有品牌手机
+    const [targetKey, set_targetKey] = useState('0')//创意key
+    const [page_checked, set_page_checked] = useState(false)//创意key
+    const [usesArr, setUsersArr] = useState<any>(localStorage.getItem('ADQUSERS' + userId) ? JSON.parse(localStorage.getItem('ADQUSERS' + userId) as any) : [])
     const { init, get } = useModel('useLaunchAdq.useBdMediaPup')
+    const [cloudParams, setCloudParams] = useState<{ adcreativeTemplateId?: number }>({})
 
 
     const tagsList_REGION = useAjax((params) => getTagsList(params))
@@ -83,11 +85,10 @@ const CreateAd: React.FC = () => {
             setAccountCreateLogs(accountCreateLogs)
         }
     }, [])
-
     // 设置地域
     useEffect(() => {
         tagsList_REGION.run({ type: 'REGION' }).then(res => {
-            if (res) {
+            if (res && Array.isArray(res)) {
                 setGeoLocationList(() => (res as any[])?.reduce((prev: any, cur: { id: number }) => {
                     prev[cur.id] = cur
                     return prev
@@ -95,7 +96,7 @@ const CreateAd: React.FC = () => {
             }
         })
         tagsList_MODEL.run({ type: 'DEVICE_BRAND_MODEL' }).then(res => {
-            if (res) {
+            if (res && Array.isArray(res)) {
                 setModelList(() => (res as any[])?.reduce((prev: any, cur: { id: number }) => {
                     prev[cur.id] = cur
                     return prev
@@ -107,16 +108,9 @@ const CreateAd: React.FC = () => {
     // 获取账户列表
     useEffect(() => {
         getAdAccount.run()
-        init({ mediaType: 'PAGE' })
     }, [])
 
     /** 获取广告详情 */
-    useEffect(() => {
-        if (queryForm?.sysAdgroupId) {
-            getSysAdgroups.run(queryForm?.sysAdgroupId)
-        }
-    }, [queryForm?.sysAdgroupId])
-
     useEffect(() => {
         if (getSysAdgroups?.data?.bidMode !== 'BID_MODE_CPM' && accountCreateLogs?.length > 0) {
             let newAccountCreateLogs = accountCreateLogs?.map((item: any) => {
@@ -129,34 +123,8 @@ const CreateAd: React.FC = () => {
         }
     }, [getSysAdgroups?.data?.bidMode])
 
-    /** 获取创意详情 */
-    useEffect(() => {
-        if (queryForm?.sysAdcreativeId) {
-            getSysAdcreative.run(queryForm?.sysAdcreativeId)
-        }
-    }, [queryForm?.sysAdcreativeId])
 
-    /** 获取定向详情 */
-    useEffect(() => {
-        if (queryForm?.sysTargetingId) {
-            getsysTargeting.run(queryForm?.sysTargetingId)
-        }
-    }, [queryForm?.sysTargetingId])
 
-    /** 获取落地页详情 */
-    useEffect(() => {
-        if (queryForm?.sysPageId) {
-            get.run({ mediaType: 'PAGE', sysMediaId: queryForm?.sysPageId }).then(res => {
-                if (!Object.keys(res)?.includes('fail')) {
-                    let data = res
-                    let pageElementsSpecList = data?.pageSpecsList[0]?.pageElementsSpecList
-                    setWxButtonList(() => (pageElementsSpecList as any[])?.filter((item: { elementType: string }) => item?.elementType === 'ENTERPRISE_WX'))
-                } else {
-                    setQueryForm({ ...queryForm, sysPageId: undefined })
-                }
-            })
-        }
-    }, [queryForm?.sysPageId])
 
     /** 删除商品内容 */
     const goodsDel = (index: number) => {
@@ -186,11 +154,7 @@ const CreateAd: React.FC = () => {
         setAccountCreateLogs(newArr)
     }
 
-    /** 设置落地页 */
-    const setPage = (e: any) => {
-        setQueryForm({ ...queryForm, sysPageId: e[0]?.id || undefined })
-        setSelectImgVisible(false)
-    }
+
 
     /** 预览 */
     const preview = () => {
@@ -202,37 +166,86 @@ const CreateAd: React.FC = () => {
             message.error('请选择推广目标')
             return
         }
-        if (!queryForm.sysAdgroupId) {
+        if (!queryForm.sysAdgroup) {
             message.error('请先设置广告基本信息')
             return
         }
-        if (!queryForm.sysTargetingId) {
+        if (!queryForm.sysTargeting) {
             message.error('请选择定向')
             return
         }
-        if (!queryForm.sysAdcreativeId) {
+        if (!queryForm.taskMediaMaps?.every(item => item.sysAdcreative)) {
             message.error('请设置创意的基本信息')
             return
         }
-        if (!accountCreateLogs?.every((item: any) => item.pageList?.length > 0)) { // 所有都选云端
-            if (!queryForm.sysPageId) {
-                message.error('请选择落地页')
+        if (!queryForm.taskMediaMaps?.every(item => item.sysPageId || item.accountPageIdMap)) {
+            message.error('请选择落地页')
+            return
+        }
+        if (queryForm?.taskMediaMaps && queryForm?.taskMediaMaps?.some((item: { cropUserGroupMap: any[] }) => item?.cropUserGroupMap?.length > 0)) {
+            let cropData = queryForm?.taskMediaMaps?.filter((item: { cropUserGroupMap: any[] }) => item?.cropUserGroupMap?.length > 0)
+            if (cropData?.some((item: { cropUserGroupMap: { data: { cropList: any[] }[] }[] }) => {
+                return item?.cropUserGroupMap?.some((item1: { data: { cropList: any[] }[] }) => item1?.data?.some((item2: { cropList: any[] }) => item2?.cropList?.length === 0))
+            })) {
+                message.error('请完善落地页企微客服组')
                 return
             }
         }
-        let data = accountCreateLogs.map((item: any, index) => {
-            return { ...item, ...queryForm, sysAdGroupData: getSysAdgroups?.data, targetingData: getsysTargeting?.data, sysAdcreativeData: { ...getSysAdcreative?.data }, pageData: get?.data }
+        let data: any[] = []
+        accountCreateLogs.forEach((item: any) => {
+            queryForm.taskMediaMaps?.forEach((task, index) => {
+                let obj = {
+                    ...item,
+                    ...queryForm,
+                    sysAdGroupData: queryForm.sysAdgroup,
+                    targetingData: queryForm.sysTargeting,
+                    sysAdcreativeData: task.sysAdcreative,
+                    pageData: (queryForm.pageList as any)[index] || (queryForm.adqPageList as any)[index]?.find((adq: { adAccountId: any }) => adq.adAccountId === item.adAccountId)?.pageList[0],
+                    myId: Number(item.id + '' + index)
+                }
+                data.push(obj)
+            })
         })
-        console.log('data--->', data)
+        console.log('tableData--->', data)
         setTableData(data)
     }
 
-    const submit = (data: { adgroupName: string, campaignName: string }) => {
+    const submit = (props: { campaignName: string, count?: number }) => {
         console.log(111111, tableSelect);
-        let params = { ...queryForm, ...data }
-        let accountLogs = tableSelect.map((item: any) => {
+        let newQueryForm = JSON.parse(JSON.stringify(queryForm))
+        let newtaskMediaMaps = newQueryForm.taskMediaMaps.map((item1: { cropUserGroupMap?: any[] }) => {
+            let { cropUserGroupMap, ...data } = item1
+            if (cropUserGroupMap && cropUserGroupMap?.length > 0) {
+                let cropUserGroup1Map: any = {}
+                let cropUserGroup2Map: any = {}
+                cropUserGroupMap.forEach((cropData: { id: number, data: any[] }) => {
+                    let cropData1: { cropId: string, groupId: number }[] = []
+                    let cropData2: { cropId: string, groupId: number }[] = []
+                    cropData?.data.forEach((crop: { type: 1 | 2, cropList: { cropId: string, groupId: number }[] }) => {
+                        let cropList = crop.cropList
+                        if (crop.type === 1) {
+                            cropData1.push({ cropId: cropList[0].cropId, groupId: cropList[0].groupId })
+                        } else {
+                            cropData2.push({ cropId: cropList[0].cropId, groupId: cropList[0].groupId })
+                        }
+                    })
+                    if (cropData1.length > 0) {
+                        cropUserGroup1Map[cropData.id.toString()] = cropData1
+                    }
+                    if (cropData2.length > 0) {
+                        cropUserGroup2Map[cropData.id.toString()] = cropData2
+                    }
+                })
+                return { ...data, cropUserGroup1Map: Object.keys(cropUserGroup1Map)?.length > 0 ? cropUserGroup1Map : null, cropUserGroup2Map: Object.keys(cropUserGroup2Map)?.length > 0 ? cropUserGroup2Map : null }
+            }
+            return data
+        })
+        newQueryForm.taskMediaMaps = newtaskMediaMaps
+        let params = { ...newQueryForm, ...props }
+        console.log(accountCreateLogs)
+        let accountLogs = accountCreateLogs.map((item: any, index) => {
             // userActionSetsList 数据源  productList 商品
-            let data: any = { adAccountId: item.id }
+            let data: any = { adAccountId: item.id, count: props.count || 1 }
             if (item?.userActionSetsList?.length > 0) { // 数据源
                 data.userActionSets = item?.userActionSetsList?.map((item: any) => ({ id: item?.id, type: item?.type }))
             }
@@ -247,14 +260,21 @@ const CreateAd: React.FC = () => {
                 data.excludedCustomAudience = item?.excludedCustomAudienceList?.map((item: any) => item.id)
             }
             if (item?.pageList) {
-                data.pageId = item?.pageList[0].id
+                data.pageId = item?.pageData?.id
             }
             return data
         })
         params.accountCreateLogs = accountLogs
+        delete params.sysAdgroupId
+        delete params.sysAdcreativeId
+        delete params.sysTargetingId
+        delete params.pageList
+        delete params.adqPageList
+        delete params.count
+        console.log('paramsSubmit====>', params)
         createAdBatch.run(params).then(res => {
             if (res) {
-                sessionStorage.setItem('CAMP', data?.campaignName)
+                sessionStorage.setItem('CAMP', props?.campaignName)
                 message.success('创建成功')
                 window.location.href = '/#/launchSystemNew/launchManage/taskList'
             }
@@ -291,13 +311,163 @@ const CreateAd: React.FC = () => {
             adgroupName: undefined,  // 广告名称
             configuredStatus: 'AD_STATUS_SUSPEND',  // 广告状态
             sysAdcreativeId: undefined, // 创意ID
-            sysPageId: undefined, // 落地页Id
         })
     }
+    /** 设置落地页 */
+    const setPage = (e: any) => {
+        console.log('设置落地页=>', e[0].pageSpecsList[0].pageElementsSpecList[0])
+        let arr: any = queryForm.taskMediaMaps || []
+        function setUrl(item: { sysAdcreative: { overrideCanvasHeadOption: string, adcreativeElements: any } }) {
+            console.log('item====>', item)
+            if (item?.sysAdcreative?.overrideCanvasHeadOption && item?.sysAdcreative?.overrideCanvasHeadOption === "OPTION_CANVAS_OVERRIDE_CREATIVE") {
+                let adcreativeElementsNew = { ...item.sysAdcreative.adcreativeElements }
+                let obj = e[0].pageSpecsList[0].pageElementsSpecList[0]
+                let { topImageSpec, topVideoSpec, topSliderSpec } = obj
+                Object.keys(adcreativeElementsNew).forEach(key => {
+                    switch (key) {
+                        case 'imageUrl'://图素材
+                            adcreativeElementsNew[key] = topImageSpec?.imageUrl
+                            break;
+                        case 'videoUrl'://视频素材
+                            adcreativeElementsNew[key] = topVideoSpec?.videoUrl
+                            break;
+                        case 'imageUrlList'://图素材
+                            adcreativeElementsNew[key] = topSliderSpec?.imageUrlList || [topImageSpec?.imageUrl]
+                            break;
+                        case 'shortVideoStruct'://视频素材
+                            adcreativeElementsNew[key] = { shortVideo1Url: topVideoSpec?.videoUrl }
+                            break;
+                    }
+                })
+                return { ...item, sysPageId: e[0]?.id, accountPageIdMap: null, sysAdcreative: { ...item.sysAdcreative, adcreativeElements: adcreativeElementsNew } }
+            }
+            return { ...item, sysPageId: e[0]?.id, accountPageIdMap: null, }
+        }
+        if (page_checked) {
+            console.log('queryForm.taskMediaMaps', queryForm.taskMediaMaps)
+            arr = queryForm.taskMediaMaps?.map(item => {
+                return setUrl(item)
+            })
+        } else {
+            arr[targetKey as string] = setUrl(arr[targetKey as string])
+        }
+        getPageInfo(arr)
+        setSelectImgVisible(false)
+    }
 
+    /** 获取落地页详情 */
+    const getPageInfo = useCallback((arrList) => {
+        console.log('arrList====>', arrList)
+        if (arrList && arrList[targetKey]?.sysPageId) {
+            get.run({ mediaType: 'PAGE', sysMediaId: arrList[targetKey]?.sysPageId }).then(res => {
+                if (!Object.keys(res)?.includes('fail')) {
+                    let data = res
+                    let pageElementsSpecList = data?.pageSpecsList[0]?.pageElementsSpecList // 内容区
+                    let globalSpec = data?.globalSpec  // 悬浮组件
+                    let arr: any = queryForm.pageList || []
+                    let adqPageArr: any = queryForm.adqPageList || []
+                    adqPageArr[targetKey] = null
+                    arr[targetKey] = data
+                    /** 处理客服 */
+                    let cropUserGroupMap: any[] = []
+                    if ((pageElementsSpecList as any[])?.some((item: { elementType: string }) => item?.elementType === 'ENTERPRISE_WX') || (globalSpec?.globalElementsSpecList?.length > 0 && globalSpec?.globalElementsSpecList?.some((item: { floatButtonSpec: { elementType: string } }) => item?.floatButtonSpec?.elementType === 'ENTERPRISE_WX'))) {
+                        let groupList: { type: number, name: string, cropList: any[], cropId?: number, groupId?: number }[] = [];
+                        (pageElementsSpecList as any[])?.forEach((item: { elementType: string, enterpriseWxSpec: { btnTitle: string } }) => {
+                            if (item?.elementType === 'ENTERPRISE_WX') {
+                                groupList.push({ type: 1, name: '联系商家', cropList: [] }) // item.enterpriseWxSpec.btnTitle
+                            }
+                        })
+                        if ((globalSpec?.globalElementsSpecList?.length > 0 && globalSpec?.globalElementsSpecList)) {
+                            groupList.push({ type: 2, name: '悬浮组件', cropList: [] })
+                        }
+                        cropUserGroupMap = accountCreateLogs?.map((item: any) => ({ adAccountId: item.adAccountId, id: item.id, data: groupList }))
+                    }
+                    arrList[targetKey].cropUserGroupMap = cropUserGroupMap
+                    setQueryForm({ ...queryForm, pageList: arr, taskMediaMaps: arrList, adqPageList: adqPageArr })//设置落地页详情数组
+                } else {
+                    //清空对应创意中的落地页ID
+                    let arr = queryForm.taskMediaMaps || []
+                    arr[targetKey].sysPageId = ''
+                    setQueryForm({ ...queryForm, taskMediaMaps: arr })
+                }
+            })
+        }
+    }, [queryForm, targetKey, accountCreateLogs])
+    // 设置云端落地页
+    const setAdqPage = useCallback((data) => {
+        if (Array.isArray(data) && data.length > 0) {
+            let objMap = {}
+            data?.forEach(item => {
+                objMap[item.adAccountId] = item.pageList[0].pageId
+            })
+            let arr: any = queryForm.taskMediaMaps || []
+            let adqPageArr: any = queryForm.adqPageList || []
+            let pageArr: any = queryForm.pageList || []
+            adqPageArr[targetKey as string] = data
+            pageArr[targetKey as string] = null
+            delete arr[targetKey as string]?.cropUserGroupMap
+            arr[targetKey as string] = { ...arr[targetKey as string], sysPageId: '', accountPageIdMap: objMap }
+            // 重新设置云端数据并清空本地数据
+            setQueryForm({ ...queryForm, taskMediaMaps: arr, adqPageList: adqPageArr, pageList: pageArr })
+        }
+    }, [queryForm, targetKey])
+    // tabs新增和删除
+    const onEdit = useCallback((targetKey: string | React.MouseEvent<Element, MouseEvent> | React.KeyboardEvent<Element>, action: 'add' | 'remove') => {
+        if (queryForm.taskMediaMaps) {
+            if (action === 'remove') {
+                let arr = queryForm.taskMediaMaps
+                let adqPageArr: any = queryForm.adqPageList || []
+                let pageArr: any = queryForm.pageList || []
+                adqPageArr[targetKey as string] = null
+                pageArr[targetKey as string] = null
+                arr[targetKey as string] = { ...arr[targetKey as string], sysPageId: '', accountPageIdMap: null }
+                setQueryForm({ ...queryForm, taskMediaMaps: arr, pageList: pageArr, adqPageList: adqPageArr })
+            }
+        }
+    }, [queryForm, targetKey])
+    // 媒体组更新通知
+    const usersChange = useCallback(() => {
+        let data = JSON.parse(localStorage.getItem('ADQUSERS' + userId) as any)
+        setUsersArr(data)
+    }, [])
+
+    console.log('queryForm111111', queryForm);
     return <Space direction="vertical" style={{ width: '100%' }}>
-        <Card title={<div className={style.cardTitle}>配置区</div>} className={style.createAd} hoverable>
+        <Card
+            title={<div className={style.cardTitle}>配置区</div>}
+            className={style.createAd}
+            hoverable
+            extra={<AddGroup onChange={usersChange} pitcherData={getAdAccount?.data?.data} />}
+        >
             <Space>
+                <Selector label="媒体账户组">
+                    <Select
+                        mode="multiple"
+                        style={{ minWidth: 200 }}
+                        placeholder="快捷选择媒体账户组"
+                        maxTagCount={1}
+                        allowClear
+                        bordered={false}
+                        filterOption={(input: any, option: any) => {
+                            return option!.children?.toString().toLowerCase().includes(input.toLowerCase())
+                        }}
+                        onChange={(e, option) => {
+                            console.log(e, option)
+                            let userArr: any[] = []
+                            e.forEach((key: any) => {
+                                let obj = usesArr.find((item: { id: any }) => item.id === key)
+                                if (obj) {
+                                    userArr.push(obj['pitcher'])
+                                }
+                            })
+                            userArr = [...new Set(userArr.flat())]
+                            setAccountCreateLogs(userArr?.map((item: any) => ({ adAccountId: item?.split('_')[1], id: Number(item?.split('_')[0]) })))
+                            clearData()
+                        }}
+                    >
+                        {usesArr?.map((item: any) => <Select.Option value={item.id} key={item.id}>{item.name}</Select.Option>)}
+                    </Select>
+                </Selector>
                 <Selector label="媒体账户">
                     <Select
                         mode="multiple"
@@ -311,21 +481,19 @@ const CreateAd: React.FC = () => {
                         }}
                         value={accountCreateLogs?.map((item: { id: number }) => item?.id)}
                         onChange={(e, option) => {
-                            setAccountCreateLogs(option?.map((item: any) => ({ adAccountId: item?.children, id: item?.value })))
+                            console.log(option)
+                            setQueryForm({ ...queryForm, taskMediaMaps: queryForm?.taskMediaMaps?.map((item: { sysPageId: number }) => ({ ...item, sysPageId: '' })) })
+                            setAccountCreateLogs(option?.map((item: any) => ({ adAccountId: item?.children?.toString()?.split('——')[0], id: item?.value })))
                             clearData()
                         }}
                     >
-                        {getAdAccount?.data?.data?.map((item: any) => <Select.Option value={item.id} key={item.id}>{item.accountId}</Select.Option>)}
-                        {/* <Select.OptGroup label="Engineer">
-                            <Select.Option value="20632113">20632113</Select.Option>
-                        </Select.OptGroup> */}
+                        {getAdAccount?.data?.data?.map((item: any) => <Select.Option value={item.id} key={item.id}>{item.remark ? item.accountId + '——' + item.remark : item.accountId}</Select.Option>)}
                     </Select>
                 </Selector>
-
                 <Selector label="推广目标">
                     <Select style={{ width: 200 }} value={queryForm?.promotedObjectType} placeholder="请选择推广目标" bordered={false} showSearch filterOption={(input: any, option: any) =>
                         (option!.children as unknown as string).toLowerCase().includes(input.toLowerCase())
-                    } onChange={(e) => { setQueryForm({ ...queryForm, promotedObjectType: e }); clearData() }}>
+                    } onChange={(e) => { setQueryForm({ ...queryForm, promotedObjectType: e, sysAdgroup: null, sysAdgroupId: undefined, taskMediaMaps: [], sysAdcreativeId: undefined }); clearData() }}>
                         {Object.keys(PromotedObjectType).map(key => {
                             return <Select.Option value={key} key={key}>{PromotedObjectType[key]}</Select.Option>
                         })}
@@ -335,96 +503,26 @@ const CreateAd: React.FC = () => {
 
             <div className={style.cardBody}>
                 <Row className={style.content}>
-                    <Col span={16} className={style.conLeft}>
+                    <Col span={12} className={style.conLeft}>
                         <Row className={`${style.conTitle} ${style.conRightBorder}`}><Col span={24}>广告</Col></Row>
                         <Row className={style.items}>
                             {/* =============广告基本信息=========== */}
-                            <Col className={style.conRightBorder}>
-                                <div className={style.top}>
-                                    广告基本信息
-                                </div>
-                                <div className={style.center}>
-                                    <Spin spinning={getSysAdgroups.loading}>
-                                        <div className={style.centerContent}>
-                                            {(getSysAdgroups?.data && queryForm?.sysAdgroupId) ? <AdgroupsCol data={getSysAdgroups?.data} /> : <Empty image={Empty.PRESENTED_IMAGE_SIMPLE} />}
-                                        </div>
-                                    </Spin>
-                                </div>
-                                <div className={style.bottom}>
-                                    {queryForm?.promotedObjectType ? <span onClick={() => { setAdVisible(true) }}>{getSysAdgroups?.data ? '修改' : '添加'}</span> : <Tooltip title="请先选择推广目标">
-                                        <span>添加</span>
-                                    </Tooltip>}
-                                </div>
-                            </Col>
+                            <Ad queryForm={queryForm} setQueryForm={setQueryForm} getSysAdgroups={getSysAdgroups} clearData={clearData} />
                             {/* =============定向包=========== */}
-                            <Col className={style.conRightBorder}>
-                                <div className={style.top}>
-                                    定向
-                                    {getSysAdgroups?.data?.bidMode === 'BID_MODE_CPM' && <>{accountCreateLogs?.length > 0 && queryForm?.sysTargetingId ? <Button type="link" style={{ fontSize: 12, padding: 0 }} onClick={() => setCpVisible(true)}>选择定向包</Button> : <Tooltip title={accountCreateLogs?.length > 0 ? `请先添加定向` : `请先选择媒体账户`}>
-                                        <Button type="link" style={{ fontSize: 12, padding: 0 }}>选择定向包</Button>
-                                    </Tooltip>}</>}
-                                </div>
-                                <div className={style.center}>
-                                    <Spin spinning={getsysTargeting.loading}>
-                                        <div className={style.centerContent}>
-                                            {queryForm?.sysTargetingId ? <>
-                                                {accountCreateLogs?.some((item: any) => item?.customAudienceList?.length > 0) ? <>
-                                                    {getsysTargeting?.data && <Popover
-                                                        content={<div className={style.popover}>
-                                                            <TargetingTooltip data={getsysTargeting?.data} geoLocationList={geoLocationList} modelList={modelList} />
-                                                        </div>}
-                                                        trigger="hover"
-                                                        placement="right"
-                                                    >
-                                                        <div className={style.popoverContent}>
-                                                            <div>定向名称: <span>{getsysTargeting?.data?.targetingName}</span></div>
-                                                            <div>定向描述: <span>{getsysTargeting?.data?.description || '<空>'}</span></div>
-                                                        </div>
-                                                    </Popover>}
-                                                    {accountCreateLogs?.map((item: any, index: number) => {
-                                                        if (item?.customAudienceList) {
-                                                            return <div className={style.acc} key={index}>
-                                                                <div className={style.accName} style={{ fontWeight: 800 }}>{item.adAccountId}</div>
-                                                                {item?.customAudienceList?.length > 0 && <>
-                                                                    <div className={style.accName}>定向用户群</div>
-                                                                    {
-                                                                        item?.customAudienceList?.map((pack: { name: string, id: number }, index1: number) => {
-                                                                            return <div className={style.accCon} key={pack.id}>{pack.name}<CloseOutlined className={style.close} onClick={() => {
-                                                                                cpDel(index, index1, 'customAudienceList')
-                                                                            }} /></div>
-                                                                        })
-                                                                    }
-                                                                </>}
-                                                                {item?.excludedCustomAudienceList?.length > 0 && <>
-                                                                    <div className={style.accName} style={{ marginTop: 5 }}>排除用户群</div>
-                                                                    {
-                                                                        item?.excludedCustomAudienceList?.map((pack: { name: string, id: number }, index1: number) => {
-                                                                            return <div className={style.accCon} key={pack.id}>{pack.name}<CloseOutlined className={style.close} onClick={() => {
-                                                                                cpDel(index, index1, 'excludedCustomAudienceList')
-                                                                            }} /></div>
-                                                                        })
-                                                                    }
-                                                                </>}
-                                                            </div>
-                                                        } else {
-                                                            return null
-                                                        }
-                                                    })}
-                                                </> : <>
-                                                    <div>定向名称: <span>{getsysTargeting?.data?.targetingName}</span></div>
-                                                    <div>定向描述: <span>{getsysTargeting?.data?.description || '<空>'}</span></div>
-                                                    <TargetingTooltip data={getsysTargeting?.data} geoLocationList={geoLocationList} modelList={modelList} />
-                                                </>}
-
-
-                                            </> : <Empty image={Empty.PRESENTED_IMAGE_SIMPLE} />}
-                                        </div>
-                                    </Spin>
-                                </div>
-                                <div className={style.bottom}><span onClick={() => { setDxVisible(true) }}>{getsysTargeting?.data ? '修改' : '添加'}</span></div>
-                            </Col>
+                            <TargetIng
+                                queryForm={queryForm}
+                                setQueryForm={setQueryForm}
+                                getSysAdgroups={getSysAdgroups}
+                                clearData={clearData}
+                                setAccountCreateLogs={setAccountCreateLogs}
+                                getsysTargeting={getsysTargeting}
+                                geoLocationList={geoLocationList}
+                                modelList={modelList}
+                                cpDel={cpDel}
+                                accountCreateLogs={accountCreateLogs}
+                            />
                             {/* =============商品=========== */}
-                            <Col className={style.conRightBorder}>
+                            <Col className={style.conRightBorder} span={5}>
                                 <div className={style.top}>
                                     商品{/* <span>已选:{1}</span> */}
                                 </div>
@@ -455,7 +553,7 @@ const CreateAd: React.FC = () => {
                                 </div>
                             </Col>
                             {/* 数据源 */}
-                            <Col className={style.conRightBorder}>
+                            <Col className={style.conRightBorder} span={5}>
                                 <div className={style.top}>
                                     数据源 {/* <span>已选:{1}</span> */}
                                 </div>
@@ -489,86 +587,95 @@ const CreateAd: React.FC = () => {
                         </Row>
                     </Col>
                     {/* =============广告创意=========== */}
-                    <Col span={8} className={style.conRight}>
+                    <Col span={12} className={style.conRight}>
                         <Row className={style.conTitle}><Col span={24}>广告创意</Col></Row>
                         <Row className={style.items}>
                             {/* 创意 */}
-                            <Col span={12} className={style.conRightBorder}>
-                                <div className={style.top}>创意基本信息</div>
-                                <div className={style.center}>
-                                    <Spin spinning={getSysAdcreative.loading}>
-                                        <div className={style.centerContent}>
-                                            {(getSysAdcreative?.data && queryForm?.sysAdcreativeId) && <AdcreativeCol data={getSysAdcreative?.data} />}
-                                        </div>
-                                    </Spin>
-                                </div>
-                                <div className={style.bottom}>{queryForm?.sysAdgroupId ? <>
-                                    <Button type="link" onClick={() => { setCreativeVisible(true) }}>{queryForm?.sysAdcreativeId ? '修改' : '添加'}</Button>
-                                </> : <Tooltip title="请先设置广告">
-                                    <Button type="link"><span>添加</span></Button>
-                                </Tooltip>}
-                                </div>
-                            </Col>
+                            <Creative queryForm={queryForm} setQueryForm={setQueryForm} getSysAdgroups={getSysAdgroups} clearData={clearData} getSysAdcreative={getSysAdcreative} set_targetKey={set_targetKey} targetKey={targetKey} page_checked={page_checked} />
                             {/* 落地页 */}
                             <Col span={12} >
                                 <div className={style.top}>
-                                    <span>落地页 <Tooltip title="云端落地页优先于本地落地页">
-                                        <QuestionCircleOutlined />
-                                    </Tooltip></span>
-                                    {wxButtonList?.length > 0 && <Button type="link" size="small">配置客服</Button>}
+                                    落地页
+                                    {(queryForm?.taskMediaMaps && queryForm?.taskMediaMaps[targetKey]?.cropUserGroupMap?.length > 0) && <CustomerServiceModal data={queryForm?.taskMediaMaps[targetKey]?.cropUserGroupMap} onChange={(data) => {
+                                        let newQueryForm = JSON.parse(JSON.stringify(queryForm))
+                                        newQueryForm.taskMediaMaps[targetKey].cropUserGroupMap = data
+                                        setQueryForm(newQueryForm)
+                                    }} />}
                                 </div>
                                 <div className={style.center}>
-                                    <Spin spinning={get.loading}>
-                                        <div className={style.centerContent}>
-                                            {accountCreateLogs?.some((item: any) => item.pageList?.length > 0 || (queryForm?.sysPageId && (get?.data && !Object.keys(get?.data)?.includes('fail'))))  ? <>
-                                                {(queryForm?.sysPageId && !accountCreateLogs?.every((item: any) => item.pageList?.length > 0)) && <>
-                                                    <div>落地页名称:{get?.data?.pageName || ''}</div>
-                                                    <div>分享名称:{get?.data?.shareContentSpec?.shareTitle || ''}</div>
-                                                    <div>分享描述:{get?.data?.shareContentSpec?.shareDescription || ''}</div>
-                                                    <div style={{ marginBottom: 10 }}>原生推广页顶部素材预览:
-                                                        <div>{get?.data?.pageSpecsList && get?.data?.pageSpecsList[0]?.pageElementsSpecList?.filter((item: any, index: number) => index === 0)?.map((item: { elementType: 'TOP_IMAGE' | 'TOP_VIDEO' | 'TOP_SLIDER', topImageSpec: any, topSliderSpec: any, topVideoSpec: any }, index: number) => {
-                                                            switch (item?.elementType) {
-                                                                case 'TOP_IMAGE':
-                                                                    return <Image width={80} src={item.topImageSpec.imageUrl} style={{ borderRadius: 8, overflow: 'hidden' }} key={index} />
-                                                                case 'TOP_SLIDER':
-                                                                    return <Space wrap key={index}>
-                                                                        {item?.topSliderSpec?.imageUrlList?.map((url: string, index: number) => <Image width={70} src={url} style={{ borderRadius: 8 }} key={'TOP_SLIDER' + index} />)}
-                                                                    </Space>
-                                                                case 'TOP_VIDEO':
-                                                                    return <video src={item.topVideoSpec.videoUrl} width={150} controls key={index}></video>
-                                                            }
-                                                        })}</div>
-                                                    </div>
-                                                </>}
-                                                {accountCreateLogs?.map((item: any, index: number) => {
-                                                    if (item?.pageList && item?.pageList?.length > 0) {
-                                                        return <div className={style.acc} key={index}>
-                                                            <div className={style.accName} style={{ fontWeight: 800 }}>{item.adAccountId}</div>
+                                    <Tabs size={'small'} onEdit={onEdit} type="editable-card" activeKey={targetKey} onChange={(key) => { set_targetKey(key) }} hideAdd >
+                                        {
+                                            queryForm?.taskMediaMaps?.map((item, index) => {
+                                                return <Tabs.TabPane tab={'创意' + (index + 1)} key={index} >
+                                                    <Spin spinning={get.loading}>
+                                                        <div className={style.centerContent}>
                                                             {
-                                                                item?.pageList?.map((pack: { pageName: string, type: string, id: number }, index1: number) => {
-                                                                    return <div className={style.accCon} key={pack.id}> <span className={style.title}>{pack.pageName}</span> <CloseOutlined className={style.close} onClick={() => {
-                                                                        pageDel(index)
-                                                                    }} /></div>
-                                                                })
-                                                            }
+                                                                item?.sysPageId || item?.accountPageIdMap ? <>
+                                                                    {
+                                                                        (item?.sysPageId && queryForm?.pageList) && <>
+                                                                            <div>落地页名称:{queryForm?.pageList[targetKey]?.pageName || ''}</div>
+                                                                            <div>分享名称:{queryForm?.pageList[targetKey]?.shareContentSpec?.shareTitle || ''}</div>
+                                                                            <div>分享描述:{queryForm?.pageList[targetKey]?.shareContentSpec?.shareDescription || ''}</div>
+                                                                            <div style={{ marginBottom: 10 }}>原生推广页顶部素材预览:
+                                                                                <div>{queryForm?.pageList[targetKey]?.pageSpecsList && queryForm?.pageList[targetKey]?.pageSpecsList[0]?.pageElementsSpecList?.filter((item: any, index: number) => index === 0)?.map((item: { elementType: 'TOP_IMAGE' | 'TOP_VIDEO' | 'TOP_SLIDER', topImageSpec: any, topSliderSpec: any, topVideoSpec: any }, index: number) => {
+                                                                                    switch (item?.elementType) {
+                                                                                        case 'TOP_IMAGE':
+                                                                                            return <Image width={80} src={item?.topImageSpec?.imageUrl} style={{ borderRadius: 8, overflow: 'hidden' }} key={index} />
+                                                                                        case 'TOP_SLIDER':
+                                                                                            return <Space wrap key={index}>
+                                                                                                {item?.topSliderSpec?.imageUrlList?.map((url: string, index: number) => <Image width={70} src={url} style={{ borderRadius: 8 }} key={'TOP_SLIDER' + index} />)}
+                                                                                            </Space>
+                                                                                        case 'TOP_VIDEO':
+                                                                                            return <video src={item?.topVideoSpec?.videoUrl} width={150} controls key={index}></video>
+                                                                                    }
+                                                                                })}</div>
+                                                                            </div>
+                                                                        </>
+                                                                    }
+                                                                    {
+                                                                        queryForm?.adqPageList && queryForm?.adqPageList[targetKey]?.map((adq: any) => {
+                                                                            return <div className={style.acc} key={adq.adAccountId}>
+                                                                                <div className={style.accName} style={{ fontWeight: 800 }}>{adq.adAccountId}</div>
+                                                                                <div className={style.accCon}>
+                                                                                    <span className={style.title}>{adq.pageList[0].pageName}</span>
+                                                                                </div>
+                                                                            </div>
+                                                                        })
+                                                                    }
+                                                                </> : <Empty image={Empty.PRESENTED_IMAGE_SIMPLE} />}
                                                         </div>
-                                                    } else {
-                                                        return null
-                                                    }
-                                                })}
-                                            </> : <Empty image={Empty.PRESENTED_IMAGE_SIMPLE} />}
-                                        </div>
-                                    </Spin>
+                                                    </Spin>
+                                                </Tabs.TabPane>
+                                            })
+                                        }
+                                    </Tabs>
                                 </div>
-                                <div className={style.bottom}>{queryForm?.sysAdcreativeId ? <>
-                                    {queryForm?.sysPageId && <Button type="link" onClick={() => { setLookVisible(true) }}>查看</Button>}
-                                    <Button type="link" onClick={() => { setSelectImgVisible(true) }}>{queryForm?.sysPageId ? '修改' : '选择落地页'}</Button>
-                                    {accountCreateLogs?.length > 0 ? <Button type="link" onClick={() => { setPageVisible(true) }}>云端落地页</Button> : <Tooltip title="请先选择媒体账户">
-                                        <Button type="link">云端落地页</Button>
+                                <div className={style.bottom}>{
+                                    (queryForm?.taskMediaMaps && queryForm?.taskMediaMaps[targetKey]?.sysAdcreative) ? <>
+                                        {queryForm?.taskMediaMaps && queryForm?.taskMediaMaps[targetKey]?.sysPageId && <Button type="link" onClick={() => { setLookVisible(true) }}>查看</Button>}
+                                        {queryForm?.promotedObjectType !== 'PROMOTED_OBJECT_TYPE_LEAD_AD' && <Button type="link" onClick={() => {
+                                            setSelectImgVisible(true)
+                                            // 判定是否用原生页顶部替换外部素材
+                                            if (queryForm?.taskMediaMaps && queryForm?.taskMediaMaps[targetKey]?.sysAdcreative?.overrideCanvasHeadOption === 'OPTION_CANVAS_OVERRIDE_CREATIVE') {
+                                                init({ mediaType: 'PAGE', cloudSize: undefined, adcreativeTemplateId: queryForm?.taskMediaMaps[targetKey]?.sysAdcreative?.adcreativeTemplateId })
+                                            } else {
+                                                init({ mediaType: 'PAGE', cloudSize: undefined })
+                                            }
+                                        }}>{queryForm?.taskMediaMaps && queryForm?.taskMediaMaps[targetKey]?.sysPageId ? '修改' : '选择落地页'}</Button>}
+                                        
+                                        {accountCreateLogs?.length > 0 ? <Button type="link" onClick={() => {
+                                            setPageVisible(true)
+                                            if (queryForm?.taskMediaMaps && queryForm?.taskMediaMaps[targetKey]?.sysAdcreative?.overrideCanvasHeadOption === 'OPTION_CANVAS_OVERRIDE_CREATIVE') {
+                                                setCloudParams({ adcreativeTemplateId: queryForm?.taskMediaMaps[targetKey]?.sysAdcreative?.adcreativeTemplateId })
+                                            } else {
+                                                setCloudParams({})
+                                            }
+                                        }}>云端落地页</Button> : <Tooltip title="请先选择媒体账户">
+                                            <Button type="link">云端落地页</Button>
+                                        </Tooltip>}
+                                    </> : <Tooltip title="请先设置创意">
+                                        <Button type="link"><span>选择落地页</span></Button>
                                     </Tooltip>}
-                                </> : <Tooltip title="请先设置创意">
-                                    <Button type="link"><span>选择落地页</span></Button>
-                                </Tooltip>}
                                 </div>
                             </Col>
                         </Row>
@@ -587,15 +694,15 @@ const CreateAd: React.FC = () => {
             className={style.createAd}
             hoverable
             extra={tableData?.length > 0 ? <Space>
-                <span>推广计划总数:{accountCreateLogs?.length}</span>
-                <span>广告总数:{accountCreateLogs?.length}</span>
-                {tableSelect?.length > 0 && <span> 已选:<span style={{ color: '#1890FF' }}>{tableSelect?.length}</span> 条</span>}
+                <span>推广计划总数:{tableData?.length}</span>
+                <span>广告总数:{tableData?.length}</span>
+                {/* {tableSelect?.length > 0 && <span> 已选:<span style={{ color: '#1890FF' }}>{tableSelect?.length}</span> 条</span>} */}
                 {
                     <Button type='primary' onClick={() => {
-                        if (tableSelect.length === 0) {
-                            message.error('请选择要提交的计划!')
-                            return
-                        };
+                        // if (tableSelect.length === 0) {
+                        //     message.error('请选择要提交的计划!')
+                        //     return
+                        // };
                         setSubVisible(true)
                     }}>批量提交审核</Button>
                 }
@@ -610,13 +717,14 @@ const CreateAd: React.FC = () => {
                         total={0}
                         size="small"
                         bordered
-                        scroll={{ x: 1800 }}
-                        rowSelection={{
-                            selectedRowKeys: tableSelect?.map((item: any) => item?.id.toString()),
-                            onChange: (selectedRowKeys: React.Key[], selectedRows: any) => {
-                                setTableSelect(selectedRows)
-                            }
-                        }}
+                        scroll={{ x: 2000 }}
+                        myKey={'myId'}
+                    // rowSelection={{
+                    //     selectedRowKeys: tableSelect?.map((item: any) => item?.myId.toString()),
+                    //     onChange: (selectedRowKeys: React.Key[], selectedRows: any) => {
+                    //         setTableSelect(selectedRows)
+                    //     }
+                    // }}
                     />
                 </div>
             </div> : <div style={{ minHeight: 400, display: 'flex', justifyContent: 'center', alignItems: 'center' }}>
@@ -625,26 +733,18 @@ const CreateAd: React.FC = () => {
         </Card>
 
 
-        {/* 选择广告 */}
-        {adVisible && <AdModal visible={adVisible} onClose={() => setAdVisible(false)} promotedObjectType={queryForm.promotedObjectType as string} onChange={(e) => { setQueryForm({ ...queryForm, sysAdgroupId: e, sysAdcreativeId: undefined }); setAdVisible(false); clearData() }} sysAdgroupId={queryForm?.sysAdgroupId} />}
-        {/* 选择定向 */}
-        {dxVisible && <TargetingModal visible={dxVisible} onClose={() => setDxVisible(false)} onChange={(e) => { setQueryForm({ ...queryForm, sysTargetingId: e }); setDxVisible(false); clearData() }} sysTargetingId={queryForm?.sysTargetingId} />}
-        {/* 选择创意 */}
-        {creativeVisible && <CreativeModal siteSet={getSysAdgroups?.data?.siteSet} visible={creativeVisible} onClose={() => setCreativeVisible(false)} onChange={(e) => { setQueryForm({ ...queryForm, sysAdcreativeId: e }); setCreativeVisible(false); clearData() }} sysAdcreativeId={queryForm?.sysAdcreativeId} promotedObjectType={queryForm.promotedObjectType as string} />}
         {/* 选择商品 */}
         {goodsVisible && <GoodsModal visible={goodsVisible} data={accountCreateLogs} onClose={() => setGoodsVisible(false)} onChange={(e) => { setAccountCreateLogs(e); setGoodsVisible(false); clearData() }} />}
         {/* 选择数据源 */}
         {sourceVisible && <DataSourceModal visible={sourceVisible} data={accountCreateLogs} onClose={() => setSourceVisible(false)} onChange={(e) => { setAccountCreateLogs(e); setSourceVisible(false); clearData() }} />}
         {/* 选择转化ID */}
         {idVisible && <IdModal visible={idVisible} data={accountCreateLogs} onClose={() => setIdVisible(false)} onChange={(e) => { setAccountCreateLogs(e); setSourceVisible(false); clearData() }} />}
-        {/* 选择定向包 */}
-        {cpVisible && <CrowdPackModal visible={cpVisible} data={accountCreateLogs} onClose={() => setCpVisible(false)} onChange={(e) => { setAccountCreateLogs(e); setCpVisible(false); clearData() }} />}
         {/* 选择ADQ落地页 */}
-        {pageVisible && <PageModal visible={pageVisible} data={accountCreateLogs} onClose={() => setPageVisible(false)} onChange={(e) => { setAccountCreateLogs(e); setPageVisible(false); clearData() }} />}
+        {pageVisible && <PageModal cloudParams={cloudParams} visible={pageVisible} data={accountCreateLogs} onClose={() => setPageVisible(false)} onChange={(e) => { setAdqPage(e); setPageVisible(false); clearData() }} />}
         {/* 选择素材 */}
         {selectImgVisible && <SelectCloud visible={selectImgVisible} onClose={() => setSelectImgVisible(false)} onChange={setPage} isBack={false} />}
         {/* 查看落地页 */}
-        {lookVisible && <LookLanding visible={lookVisible} onClose={() => setLookVisible(false)} id={queryForm?.sysPageId as any} />}
+        {lookVisible && <LookLanding visible={lookVisible} onClose={() => setLookVisible(false)} id={queryForm?.taskMediaMaps && queryForm?.taskMediaMaps[targetKey].sysPageId} />}
         {/* 设置名称 */}
         {subVisible && <SubmitModal data={getSysAdgroups?.data} visible={subVisible} onClose={() => setSubVisible(false)} onChange={submit} ajax={createAdBatch} />}
     </Space>

+ 19 - 66
src/pages/launchSystemNew/launchManage/createAd/submitModal.tsx

@@ -1,7 +1,7 @@
-import { AdStatus } from "@/services/launchAdq/enum"
-import { DatePicker, Form, Input, Modal, Radio, Select } from "antd"
-import React, { useEffect, useState } from "react"
-import moment from 'moment';
+import { SpeedMode } from "@/services/launchAdq/enum"
+import { QuestionCircleOutlined } from "@ant-design/icons"
+import { Form, Input, Modal, InputNumber, Tooltip, Select } from "antd"
+import React, { useState } from "react"
 
 
 /**
@@ -19,49 +19,13 @@ const SubmitModal: React.FC<Props> = (props) => {
 
     /********************/
     const { visible, onClose, onChange, ajax, data } = props
-    const { endDate, beginDate, bidAmount } = data
     const [form] = Form.useForm()
-    let dateType = Form.useWatch('dateType', form)
-    const [initialValues, setInitialValues] = useState<{ configuredStatus?: string, dateType?: string, date?: [any, any], beginDate?: any, bidAmount?: number, firstDayBeginTime?: any }>({ dateType: '1', configuredStatus: 'AD_STATUS_SUSPEND' })
-    /********************/
-
-    useEffect(() => {
-        let params: { configuredStatus?: string, dateType?: string, date?: [any, any], beginDate?: any, bidAmount?: number, firstDayBeginTime?: any } = { bidAmount, configuredStatus: 'AD_STATUS_SUSPEND' }
-        if (endDate) {
-            params.dateType = '1'
-            params.date = [moment(beginDate), moment(endDate)]
-        } else {
-            params.dateType = '2'
-            params.beginDate = moment(beginDate)
-        }
-        setInitialValues(params)
-        setTimeout(() => {
-            form.resetFields();
-        }, 50)
-    }, [])
+    const [initialValues, setInitialValues] = useState<{ speedMode: string, count?: number }>({ count: 1, speedMode: 'SPEED_MODE_STANDARD' })
 
     const handleOk = async () => {
         form.submit()
         let data = await form.validateFields()
-        const { dateType, date, beginDate, firstDayBeginTime, bidAmount, ...value } = data
-        let params: any = {}
-        if (dateType === '1') { // 选择开始与结束日期
-            if (date) {
-                params.beginDate = moment(date[0]).format('YYYY-MM-DD')
-                params.endDate = moment(date[1]).format('YYYY-MM-DD')
-            }
-        } else { // 长期投放
-            if (beginDate) {
-                params.beginDate = moment(beginDate).format('YYYY-MM-DD')
-            }
-        }
-        if (firstDayBeginTime) {
-            params.firstDayBeginTime = moment(firstDayBeginTime).format('hh:mm:ss')
-        }
-        if (bidAmount) {
-            params.bidAmount = bidAmount
-        }
-        onChange && onChange({ ...value, ...params })
+        onChange && onChange(data)
     }
 
     return <Modal title="设置名称" visible={visible} confirmLoading={ajax?.loading} onOk={handleOk} onCancel={() => { onClose && onClose() }}>
@@ -73,36 +37,25 @@ const SubmitModal: React.FC<Props> = (props) => {
             autoComplete="off"
             initialValues={{ ...initialValues }}
         >
-            <Form.Item label={<strong>广告名称</strong>} name="adgroupName">
-                <Input placeholder="请输入广告名称" />
-            </Form.Item>
             <Form.Item label={<strong>计划名称</strong>} name="campaignName">
                 <Input placeholder="请输入计划名称" />
             </Form.Item>
-            <Form.Item label={<strong>广告状态</strong>} name="configuredStatus" rules={[{ required: true, message: '请选择广告状态' }]}>
-                <Select placeholder="选择广告状态">
-                    {Object.keys(AdStatus).map(key => {
-                        return <Select.Option value={key} key={key}>{AdStatus[key]}</Select.Option>
+            <Form.Item label={<strong>投放方式</strong>} name="speedMode" rules={[{ required: true, message: '请选择投放方式!' }]}>
+                <Select
+                    style={{ width: 200 }}
+                    placeholder="请选择投放方式"
+                    showSearch
+                    filterOption={(input: any, option: any) =>
+                        (option!.children as unknown as string).toLowerCase().includes(input.toLowerCase())
+                    }
+                >
+                    {Object.keys(SpeedMode).map(key => {
+                        return <Select.Option value={key} key={key}>{SpeedMode[key]}</Select.Option>
                     })}
                 </Select>
             </Form.Item>
-            <Form.Item label={<strong>投放日期</strong>} name='dateType'>
-                <Radio.Group >
-                    <Radio.Button value="1">选择开始与结束日期</Radio.Button>
-                    <Radio.Button value="2">长期投放</Radio.Button>
-                </Radio.Group>
-            </Form.Item>
-            {dateType === '1' && <Form.Item name='date' style={{ marginLeft: 78 }} rules={[{ required: true, message: '请选择日期' }]}>
-                <DatePicker.RangePicker />
-            </Form.Item>}
-            {dateType === '2' && <Form.Item name='beginDate' style={{ marginLeft: 78 }} rules={[{ required: true, message: '请选择日期' }]}>
-                <DatePicker />
-            </Form.Item>}
-            <Form.Item label={<strong>开始时间</strong>} name='firstDayBeginTime'>
-                <DatePicker.TimePicker />
-            </Form.Item>
-            <Form.Item label={<strong>出价</strong>} name='bidAmount' rules={[{ required: true, message: '请输入价格' }]}>
-                <Input placeholder='输入价格 元/千次曝光' />
+            <Form.Item label={<strong>创建数量<Tooltip title='每条计划创建的数量!'><QuestionCircleOutlined /></Tooltip></strong>} name="count">
+                <InputNumber placeholder="创建数量" min={1} max={30} />
             </Form.Item>
         </Form>
     </Modal>

+ 145 - 0
src/pages/launchSystemNew/launchManage/createAd/targeting/index.tsx

@@ -0,0 +1,145 @@
+import { CreateAdProps } from "@/services/launchAdq/createAd"
+import { BaseResult } from "@ahooksjs/use-request/lib/types"
+import { CloseOutlined } from "@ant-design/icons"
+import { Button, Col, Empty, Popover, Space, Spin, Tooltip } from "antd"
+import React, { useCallback, useState } from "react"
+import TargetingModal from "../../../components/targetingModal"
+import TargetingPup from "./modal"
+import TargetingTooltip from "../../../components/targetingTooltip"
+import CrowdPackModal from "../../../components/crowdPackModal"
+import style from '../index.less'
+import { ModalConfig } from "./modal"
+type Props = {
+    queryForm: Partial<CreateAdProps>,
+    setQueryForm: React.Dispatch<React.SetStateAction<Partial<CreateAdProps>>>,
+    setAccountCreateLogs: React.Dispatch<React.SetStateAction<{
+        adAccountId: number;
+        id: number;
+        userActionSetsList?: number | undefined;
+        productList?: any;
+        conversionList?: any;
+        customAudienceList?: any;
+        excludedCustomAudienceList?: any;
+        pageList?: any;
+    }[]>>,
+    getSysAdgroups: BaseResult<any, any>,
+    getsysTargeting: BaseResult<any, any>,
+    accountCreateLogs: any[],
+    geoLocationList: any[],
+    modelList: any[],
+    clearData: () => void,
+    cpDel: (index: number, num: number, key: string) => void,
+}
+function TargetIng(props: Props) {
+    let { queryForm, getSysAdgroups, getsysTargeting, accountCreateLogs, geoLocationList, modelList, setQueryForm, clearData, cpDel, setAccountCreateLogs } = props
+    const [adModalConfig, setAdModalConfig] = useState<ModalConfig>({//新建广告弹窗
+        visible: false,
+        type: 'add'
+    })
+    const [dxVisible, setDxVisible] = useState<boolean>(false) // 选择定向弹窗控制
+    const [cpVisible, setCpVisible] = useState<boolean>(false) // 选择设置名称弹窗控制
+
+    // 设置变量
+    const handleAdModalConfig = useCallback((arg: ModalConfig) => {
+        setAdModalConfig({ ...adModalConfig, ...arg })
+    }, [adModalConfig])
+    // 获取定向详情
+    const getInfo = useCallback((sysTargetingId) => {
+        getsysTargeting.run(sysTargetingId).then(res => {
+            setQueryForm({ ...queryForm, sysTargetingId: sysTargetingId, sysTargeting: { ...res, isTemplate: false } });
+            setDxVisible(false);
+            clearData()
+        })
+    }, [queryForm])
+    return <Col className={style.conRightBorder}>
+        <div className={style.top}>
+            定向
+            {(queryForm.sysAdgroup?.bidMode === 'BID_MODE_CPM' || queryForm.sysAdgroup?.bidMode === 'BID_MODE_CPC') && <>{
+                accountCreateLogs?.length > 0 && queryForm?.sysTargetingId ? <Button type="link" style={{ fontSize: 12, padding: 0 }} onClick={() => setCpVisible(true)}>选择定向包</Button> : <Tooltip title={accountCreateLogs?.length > 0 ? `请先添加定向` : `请先选择媒体账户`}>
+                    <Button type="link" style={{ fontSize: 12, padding: 0 }}>选择定向包</Button>
+                </Tooltip>
+            }</>}
+            {queryForm.sysTargeting && <a onClick={() => {
+                setQueryForm({ ...queryForm, sysTargeting: undefined, sysTargetingId: undefined })
+                setAccountCreateLogs([])
+            }}>清空</a>}
+        </div>
+        <div className={style.center}>
+            <Spin spinning={getsysTargeting.loading}>
+                <div className={style.centerContent}>
+                    {queryForm?.sysTargeting ? <>
+                        {accountCreateLogs?.some((item: any) => item?.customAudienceList?.length > 0) ?
+                         <>
+                            {queryForm.sysTargeting && <Popover
+                                content={<div className={style.popover}>
+                                    <TargetingTooltip data={queryForm.sysTargeting} geoLocationList={geoLocationList} modelList={modelList} />
+                                </div>}
+                                trigger="hover"
+                                placement="right"
+                            >
+                                <div className={style.popoverContent}>
+                                    <div><strong>定向名称:</strong> <span style={{color:"#5a5a5a"}}>{queryForm?.sysTargeting?.targetingName}</span></div>
+                                    <div><strong>定向描述:</strong> <span style={{color:"#5a5a5a"}}>{queryForm?.sysTargeting?.description || '<空>'}</span></div>
+                                </div>
+                            </Popover>}
+                            {accountCreateLogs?.map((item: any, index: number) => {
+                                if (item?.customAudienceList) {
+                                    return <div className={style.acc} key={index}>
+                                        <div className={style.accName} style={{ fontWeight: 800 }}>{item.adAccountId}</div>
+                                        {item?.customAudienceList?.length > 0 && <>
+                                            <div className={style.accName}>定向用户群</div>
+                                            {
+                                                item?.customAudienceList?.map((pack: { name: string, id: number }, index1: number) => {
+                                                    return <div className={style.accCon} key={pack.id}>{pack.name}<CloseOutlined className={style.close} onClick={() => {
+                                                        cpDel(index, index1, 'customAudienceList')
+                                                    }} /></div>
+                                                })
+                                            }
+                                        </>}
+                                        {item?.excludedCustomAudienceList?.length > 0 && <>
+                                            <div className={style.accName} style={{ marginTop: 5 }}>排除用户群</div>
+                                            {
+                                                item?.excludedCustomAudienceList?.map((pack: { name: string, id: number }, index1: number) => {
+                                                    return <div className={style.accCon} key={pack.id}>{pack.name}<CloseOutlined className={style.close} onClick={() => {
+                                                        cpDel(index, index1, 'excludedCustomAudienceList')
+                                                    }} /></div>
+                                                })
+                                            }
+                                        </>}
+                                    </div>
+                                } else {
+                                    return null
+                                }
+                            })}
+                        </> 
+                        : 
+                        <>
+                            <div><strong>定向名称:</strong> <span style={{color:"#5a5a5a"}}>{queryForm?.sysTargeting?.targetingName}</span></div>
+                            <div><strong>定向描述:</strong> <span style={{color:"#5a5a5a"}}>{queryForm?.sysTargeting?.description || '<空>'}</span></div>
+                            <TargetingTooltip data={queryForm?.sysTargeting} geoLocationList={geoLocationList} modelList={modelList} />
+                        </>}
+
+
+                    </> : <Empty image={Empty.PRESENTED_IMAGE_SIMPLE} />}
+                </div>
+            </Spin>
+        </div>
+        <div className={style.bottom}>
+            <Space size={20}>
+                <span onClick={() => { setDxVisible(true) }}>{queryForm?.sysTargeting ? '重选定向' : '选择定向'}</span>
+                <span onClick={() => { handleAdModalConfig(queryForm?.sysTargeting ? { visible: true, type: 'edit' } : { visible: true, type: 'add' }) }}>{queryForm?.sysTargeting ? '编辑定向' : '新建定向'}</span>
+            </Space>
+        </div>
+        {/* 选择定向 */}
+        {dxVisible && <TargetingModal visible={dxVisible} onClose={() => setDxVisible(false)} onChange={getInfo} sysTargetingId={queryForm?.sysTargetingId} />}
+        {/* 选择定向包 */}
+        {cpVisible && <CrowdPackModal visible={cpVisible} data={accountCreateLogs} onClose={() => setCpVisible(false)} onChange={(e) => { setAccountCreateLogs(e); setCpVisible(false); clearData() }} />}
+        {/* 新建定向包 */}
+        {adModalConfig.visible && <TargetingPup visible={adModalConfig.visible} PupFn={handleAdModalConfig} callback={(values: any) => {
+            setQueryForm({ ...queryForm, sysTargeting: values, }); setDxVisible(false); clearData();
+            handleAdModalConfig({ visible: false, dataInfo: null, type: 'add' })
+        }} type={adModalConfig.type} dataInfo={queryForm.sysTargeting} />}
+    </Col>
+}
+
+export default TargetIng

+ 647 - 0
src/pages/launchSystemNew/launchManage/createAd/targeting/modal/index.tsx

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

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

@@ -78,9 +78,9 @@ function Ad() {
             pageSize={sysAdgroupsList?.data?.data?.size}
             leftChild={<>
                 <Row gutter={[10, 10]}>
-                    <Col span={24}><Button type='primary' onClick={() => {
+                    {/* <Col span={24}><Button type='primary' onClick={() => {
                         handleModalConfig({ visible: true })
-                    }}>新建广告模板</Button></Col>
+                    }}>新建广告模板</Button></Col> */}
                     <Col>
                         <Input
                             placeholder='广告名称'

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

@@ -12,7 +12,7 @@ interface Props {
     visible: boolean,
     PupFn: (arg: ModalConfig) => void,
     callback: (params: any) => void,
-    confirmLoading: boolean,
+    confirmLoading?: boolean,
     type?: 'add' | 'look' | 'edit',//新增,查看,编辑
     dataInfo?: any
 }

+ 1 - 6587
src/pages/launchSystemNew/launchManage/localAd/adenum.ts

@@ -1,6591 +1,5 @@
-import { AdcreativeTemplate } from '@/services/launchAdq';
 
-export const adcreativeTemplateList = [
-  // 720
-  {
-    //创意规格示意图链接
-    adcreative_sample_image:
-      'http://qzonestyle.gtimg.cn/gdt_ui_proj/dist/gdt/imgbox/creative_template_720.svg',
-    adcreative_template_appellation: '横版视频 16:9', //创意形式名称
-    adcreative_template_id: 720, //创意形式 id
-    adcreative_template_style: '视频', //创意形式类型
-    xd_show: true,
-    sp_show: true,
-    adcreativeElements: {
-      description: '文案(1-30字)',
-      video:
-        '视频比例(宽:高):9:16,最小尺寸(宽×高):720*1280,大小:不超过102400 KB,时长:5~30 s,格式:*.mp4|*.avi|*.mov;',
-      end_page: {
-        end_page_type: '视频结束页类型',
-        end_page_desc: '结束页文案,字数:1~12;',
-      },
-    },
-    adcreative_attributes: [
-      {
-        description: '头像及昵称跳转页',
-        field_type: 'FIELD_TYPE_INTEGER',
-        name: 'profile_id',
-        property_detail: {
-          integer_detail: {
-            max: 20,
-            min: 0,
-          },
-        },
-        required: true,
-      },
-      {
-        description: '分享信息',
-        field_type: 'FIELD_TYPE_STRUCT',
-        name: 'share_content_spec',
-        property_detail: {
-          struct_detail: {
-            element_list: [
-              {
-                description: '分享描述',
-                field_type: 'FIELD_TYPE_STRING',
-                name: 'share_desc',
-                property_detail: {
-                  string_detail: {
-                    max_length: 20,
-                    min_length: 1,
-                    text_pattern: '^[^\\<\\>\\&\'\\"\\/\\x08\\x09\\x0A\\x0D\\\\]+$',
-                  },
-                },
-                required: true,
-              },
-              {
-                description: '分享标题',
-                field_type: 'FIELD_TYPE_STRING',
-                name: 'share_title',
-                property_detail: {
-                  string_detail: {
-                    max_length: 14,
-                    min_length: 1,
-                    text_pattern: '^[^\\<\\>\\&\'\\"\\/\\x08\\x09\\x0A\\x0D\\\\]+$',
-                  },
-                },
-                required: true,
-              },
-            ],
-          },
-        },
-        required: false,
-      },
-      {
-        description: '动态创意分组',
-        field_type: 'FIELD_TYPE_ENUM',
-        name: 'dynamic_creative_group_used',
-        property_detail: {
-          enum_detail: {
-            default: 'NOT_USE_GROUP',
-            enumeration: [
-              {
-                description: '不使用组合',
-                value: 'NOT_USE_GROUP',
-              },
-              {
-                description: '视频封面图组合',
-                value: 'VIDEO_IMAGE_GROUP',
-              },
-            ],
-          },
-        },
-        required: false,
-      },
-    ],
-    adcreative_elements: [
-      {
-        array_property: [],
-        description: '品牌名称',
-        element_type: 'ELEMENT_TYPE_TEXT',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_STRING',
-        name: 'brand_name',
-        parent_name: 'brand',
-        required: true,
-        restriction: {
-          text_restriction: {
-            max_length: 12,
-            min_length: 2,
-            text_pattern: '^[^\\<\\>\\&\'\\"\\/\\x08\\x09\\x0A\\x0D\\\\]+$',
-          },
-        },
-        struct_property: [],
-      },
-      {
-        array_property: [],
-        description: '品牌标识图',
-        element_type: 'ELEMENT_TYPE_IMAGE',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_STRING',
-        name: 'brand_img',
-        parent_name: 'brand',
-        required: true,
-        restriction: {
-          image_restriction: {
-            file_format: ['IMAGE_TYPE_JPG', 'IMAGE_TYPE_PNG'],
-            file_size: 400,
-            height: 512,
-            width: 512,
-          },
-        },
-        struct_property: [],
-      },
-      {
-        array_property: [],
-        description: '品牌形象',
-        element_type: 'ELEMENT_TYPE_STRUCT',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_STRUCT',
-        name: 'brand',
-        parent_name: '',
-        required: true,
-        restriction: [],
-        struct_property: {
-          element_mutual_exclusive: false,
-        },
-      },
-      {
-        array_property: [],
-        description: 'Canvas',
-        element_type: 'ELEMENT_TYPE_CANVAS',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_INTEGER',
-        name: 'canvas',
-        parent_name: '',
-        required: false,
-        restriction: [],
-        struct_property: [],
-      },
-      {
-        array_property: [],
-        description: '文案(1-30字)',
-        element_type: 'ELEMENT_TYPE_TEXT',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_STRING',
-        name: 'description',
-        parent_name: '',
-        required: true,
-        restriction: {
-          text_restriction: {
-            max_length: 30,
-            min_length: 1,
-            text_pattern: '^[^\\<\\>\\&\'\\"\\/\\x08\\x09\\x0A\\x0D\\\\]+$',
-          },
-        },
-        struct_property: [],
-      },
-      {
-        array_property: [],
-        description: '视频结束页类型',
-        element_type: 'ELEMENT_TYPE_ENUM',
-        enum_property: {
-          default: 'END_PAGE_AVATAR_NICKNAME_HIGHLIGHT',
-          enumeration: [
-            {
-              description: '突出头像及昵称',
-              value: 'END_PAGE_AVATAR_NICKNAME_HIGHLIGHT',
-            },
-            {
-              description: '突出文案',
-              value: 'END_PAGE_DESCRIPTION_HIGHLIGHT',
-            },
-          ],
-        },
-        field_type: 'FIELD_TYPE_STRING',
-        name: 'end_page_type',
-        parent_name: 'end_page',
-        required: true,
-        restriction: [],
-        struct_property: [],
-      },
-      {
-        array_property: [],
-        description: '结束页文案',
-        element_type: 'ELEMENT_TYPE_TEXT',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_STRING',
-        name: 'end_page_desc',
-        parent_name: 'end_page',
-        required: true,
-        restriction: {
-          text_restriction: {
-            max_length: 12,
-            min_length: 1,
-            text_pattern: '^[^\\<\\>\\&\'\\"\\/\\x08\\x09\\x0A\\x0D\\\\]+$',
-          },
-        },
-        struct_property: [],
-      },
-      {
-        array_property: [],
-        description: '视频结束页',
-        element_type: 'ELEMENT_TYPE_STRUCT',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_STRUCT',
-        name: 'end_page',
-        parent_name: '',
-        required: false,
-        restriction: [],
-        struct_property: {
-          element_mutual_exclusive: false,
-        },
-      },
-      {
-        array_property: [],
-        description: '视频',
-        element_type: 'ELEMENT_TYPE_VIDEO',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_INTEGER',
-        name: 'video',
-        parent_name: '',
-        required: true,
-        restriction: {
-          video_restriction: {
-            file_format: ['MEDIA_TYPE_MP4', 'MEDIA_TYPE_MOV', 'MEDIA_TYPE_AVI'],
-            file_size: 102400,
-            height: 0,
-            max_duration: 30,
-            min_duration: 5,
-            min_height: 720,
-            min_width: 1280,
-            ratio_height: 9,
-            ratio_width: 16,
-            width: 0,
-          },
-        },
-        struct_property: [],
-      },
-    ],
-    landing_page_config: {
-      //支持的落地页类型
-      required: false,
-      support_page_type_list: [
-        {
-          description: '微信原生推广页',
-          example: '',
-          page_type: 'PAGE_TYPE_CANVAS_WECHAT',
-          support_link_name_type: {
-            list: [
-              {
-                description: '查看详情',
-                link_name_type: 'VIEW_DETAILS',
-              },
-              {
-                description: '了解更多',
-                link_name_type: 'MORE_INFO',
-              },
-              {
-                description: '立即购买',
-                link_name_type: 'BUY_NOW',
-              },
-              {
-                description: '立即申请',
-                link_name_type: 'APPLY_NOW',
-              },
-              {
-                description: '立即预定',
-                link_name_type: 'BOOK_NOW',
-              },
-              {
-                description: '立即咨询',
-                link_name_type: 'CONSULT_NOW',
-              },
-              {
-                description: '立即预约',
-                link_name_type: 'RESERVE_NOW',
-              },
-              {
-                description: '立即领取',
-                link_name_type: 'GET_IT_NOW',
-              },
-              {
-                description: '领取优惠',
-                link_name_type: 'GET_COUPONS',
-              },
-              {
-                description: '去逛逛',
-                link_name_type: 'GO_SHOPPING',
-              },
-              {
-                description: '关注公众号',
-                link_name_type: 'FOLLOW_OFFICIAL_ACCOUNT',
-              },
-              {
-                description: '阅读小说',
-                link_name_type: 'READ_NOVELS',
-              },
-            ],
-            required: false,
-          },
-          support_link_page_type: {
-            list: [
-              {
-                description: ' 微信公众号详情页',
-                link_page_type: 'LINK_PAGE_TYPE_WECHAT_OFFICIAL_ACCOUNT_DETAIL',
-              },
-              {
-                description: '微信原生页',
-                link_page_type: 'LINK_PAGE_TYPE_CANVAS_WECHAT',
-              },
-            ],
-            required: true,
-          },
-        },
-      ],
-    },
-    promoted_object_type: 'PROMOTED_OBJECT_TYPE_WECHAT_OFFICIAL_ACCOUNT', //推广目标类型
-    site_set: ['SITE_SET_MOMENTS', 'SITE_SET_WECHAT'], //投放版位集合
-    support_bid_mode_list: ['BID_MODE_CPM', 'BID_MODE_OCPM'], //支持的出价方式
-    support_billing_spec_list: [
-      //支持的计费信息
-      {
-        billing_event: 'BILLINGEVENT_IMPRESSION', //计费方式
-        max_price: 99900, //最高出价,单位分
-        min_price: 150, //最低出价,单位分
-      },
-    ],
-    support_dynamic_ability_spec_list: {
-      //
-      dynamic_ability_type: ['DYNAMIC_TYPE_DYNAMIC_CREATIVE'],
-      product_item_display_quantity: [],
-    },
-    unsupport_bid_mode_list: [
-      {
-        bid_mode_list: ['BID_MODE_CPA'],
-        site_set: ['SITE_SET_MOMENTS'],
-      },
-      {
-        bid_mode_list: ['BID_MODE_CPC', 'BID_MODE_OCPC'],
-        site_set: ['SITE_SET_MOMENTS'],
-      },
-      {
-        bid_mode_list: ['BID_MODE_CPC', 'BID_MODE_OCPC'],
-        site_set: ['SITE_SET_WECHAT'],
-      },
-      {
-        bid_mode_list: ['BID_MODE_CPA'],
-        site_set: ['SITE_SET_WECHAT'],
-      },
-    ],
-    unsupport_billing_spec_list: [
-      {
-        billing_event: 'BILLINGEVENT_APP_DOWNLOAD',
-        site_set: ['SITE_SET_MOMENTS'],
-        unsupport_type: 'UNSUPPORT_TYPE_EXPOSURE',
-      },
-      {
-        billing_event: 'BILLINGEVENT_CLICK',
-        site_set: ['SITE_SET_MOMENTS'],
-        unsupport_type: 'UNSUPPORT_TYPE_EXPOSURE',
-      },
-      {
-        billing_event: 'BILLINGEVENT_CLICK',
-        site_set: ['SITE_SET_WECHAT'],
-        unsupport_type: 'UNSUPPORT_TYPE_EXPOSURE',
-      },
-      {
-        billing_event: 'BILLINGEVENT_APP_DOWNLOAD',
-        site_set: ['SITE_SET_WECHAT'],
-        unsupport_type: 'UNSUPPORT_TYPE_EXPOSURE',
-      },
-    ],
-    unsupport_siteset_detail_spec: [
-      {
-        site_set: [],
-      },
-    ],
-  },
-  //721
-  {
-    adcreative_sample_image:
-      'http://qzonestyle.gtimg.cn/gdt_ui_proj/dist/gdt/imgbox/creative_template_721.svg',
-    adcreative_template_appellation: '竖版视频 9:16',
-    adcreative_template_id: 721,
-    adcreative_template_style: '视频',
-    xd_show: true,
-    adcreativeElements: {
-      description: '文案(1-30字)',
-      video:
-        '视频比例(宽:高):9:16,最小尺寸(宽×高):720*1280,大小:不超过102400 KB,时长:5~30 s,格式:*.mp4|*.avi|*.mov;',
-    },
-    adcreative_attributes: [
-      {
-        description: '头像及昵称跳转页',
-        field_type: 'FIELD_TYPE_INTEGER',
-        name: 'profile_id',
-        property_detail: {
-          integer_detail: {
-            max: 20,
-            min: 0,
-          },
-        },
-        required: true,
-      },
-      {
-        description: '分享信息',
-        field_type: 'FIELD_TYPE_STRUCT',
-        name: 'share_content_spec',
-        property_detail: {
-          struct_detail: {
-            element_list: [
-              {
-                description: '分享描述',
-                field_type: 'FIELD_TYPE_STRING',
-                name: 'share_desc',
-                property_detail: {
-                  string_detail: {
-                    max_length: 20,
-                    min_length: 1,
-                    text_pattern: '^[^\\<\\>\\&\'\\"\\/\\x08\\x09\\x0A\\x0D\\\\]+$',
-                  },
-                },
-                required: true,
-              },
-              {
-                description: '分享标题',
-                field_type: 'FIELD_TYPE_STRING',
-                name: 'share_title',
-                property_detail: {
-                  string_detail: {
-                    max_length: 14,
-                    min_length: 1,
-                    text_pattern: '^[^\\<\\>\\&\'\\"\\/\\x08\\x09\\x0A\\x0D\\\\]+$',
-                  },
-                },
-                required: true,
-              },
-            ],
-          },
-        },
-        required: false,
-      },
-      {
-        description: '动态创意分组',
-        field_type: 'FIELD_TYPE_ENUM',
-        name: 'dynamic_creative_group_used',
-        property_detail: {
-          enum_detail: {
-            default: 'NOT_USE_GROUP',
-            enumeration: [
-              {
-                description: '不使用组合',
-                value: 'NOT_USE_GROUP',
-              },
-              {
-                description: '视频封面图组合',
-                value: 'VIDEO_IMAGE_GROUP',
-              },
-            ],
-          },
-        },
-        required: false,
-      },
-    ],
-    adcreative_elements: [
-      {
-        array_property: [],
-        description: '品牌名称',
-        element_type: 'ELEMENT_TYPE_TEXT',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_STRING',
-        name: 'brand_name',
-        parent_name: 'brand',
-        required: true,
-        restriction: {
-          text_restriction: {
-            max_length: 12,
-            min_length: 2,
-            text_pattern: '^[^\\<\\>\\&\'\\"\\/\\x08\\x09\\x0A\\x0D\\\\]+$',
-          },
-        },
-        struct_property: [],
-      },
-      {
-        array_property: [],
-        description: '品牌标识图',
-        element_type: 'ELEMENT_TYPE_IMAGE',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_STRING',
-        name: 'brand_img',
-        parent_name: 'brand',
-        required: true,
-        restriction: {
-          image_restriction: {
-            file_format: ['IMAGE_TYPE_JPG', 'IMAGE_TYPE_PNG'],
-            file_size: 400,
-            height: 512,
-            width: 512,
-          },
-        },
-        struct_property: [],
-      },
-      {
-        array_property: [],
-        description: '品牌形象',
-        element_type: 'ELEMENT_TYPE_STRUCT',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_STRUCT',
-        name: 'brand',
-        parent_name: '',
-        required: true,
-        restriction: [],
-        struct_property: {
-          element_mutual_exclusive: false,
-        },
-      },
-      {
-        array_property: [],
-        description: 'Canvas',
-        element_type: 'ELEMENT_TYPE_CANVAS',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_INTEGER',
-        name: 'canvas',
-        parent_name: '',
-        required: false,
-        restriction: [],
-        struct_property: [],
-      },
-      {
-        array_property: [],
-        description: '文案(1-30字)',
-        element_type: 'ELEMENT_TYPE_TEXT',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_STRING',
-        name: 'description',
-        parent_name: '',
-        required: true,
-        restriction: {
-          text_restriction: {
-            max_length: 30,
-            min_length: 1,
-            text_pattern: '^[^\\<\\>\\&\'\\"\\/\\x08\\x09\\x0A\\x0D\\\\]+$',
-          },
-        },
-        struct_property: [],
-      },
-      {
-        array_property: [],
-        description: '视频',
-        element_type: 'ELEMENT_TYPE_VIDEO',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_INTEGER',
-        name: 'video',
-        parent_name: '',
-        required: true,
-        restriction: {
-          video_restriction: {
-            file_format: ['MEDIA_TYPE_MP4', 'MEDIA_TYPE_MOV', 'MEDIA_TYPE_AVI'],
-            file_size: 102400,
-            height: 0,
-            max_duration: 30,
-            min_duration: 5,
-            min_height: 1280,
-            min_width: 720,
-            ratio_height: 16,
-            ratio_width: 9,
-            width: 0,
-          },
-        },
-        struct_property: [],
-      },
-    ],
-    landing_page_config: {
-      required: false,
-      support_page_type_list: [
-        {
-          description: '微信原生推广页',
-          example: '',
-          page_type: 'PAGE_TYPE_CANVAS_WECHAT',
-          support_link_name_type: {
-            list: [
-              {
-                description: '查看详情',
-                link_name_type: 'VIEW_DETAILS',
-              },
-              {
-                description: '了解更多',
-                link_name_type: 'MORE_INFO',
-              },
-              {
-                description: '立即购买',
-                link_name_type: 'BUY_NOW',
-              },
-              {
-                description: '立即申请',
-                link_name_type: 'APPLY_NOW',
-              },
-              {
-                description: '立即预定',
-                link_name_type: 'BOOK_NOW',
-              },
-              {
-                description: '立即咨询',
-                link_name_type: 'CONSULT_NOW',
-              },
-              {
-                description: '立即预约',
-                link_name_type: 'RESERVE_NOW',
-              },
-              {
-                description: '立即领取',
-                link_name_type: 'GET_IT_NOW',
-              },
-              {
-                description: '领取优惠',
-                link_name_type: 'GET_COUPONS',
-              },
-              {
-                description: '去逛逛',
-                link_name_type: 'GO_SHOPPING',
-              },
-              {
-                description: '关注公众号',
-                link_name_type: 'FOLLOW_OFFICIAL_ACCOUNT',
-              },
-              {
-                description: '阅读小说',
-                link_name_type: 'READ_NOVELS',
-              },
-            ],
-            required: false,
-          },
-          support_link_page_type: {
-            list: [
-              {
-                description: ' 微信公众号详情页',
-                link_page_type: 'LINK_PAGE_TYPE_WECHAT_OFFICIAL_ACCOUNT_DETAIL',
-              },
-              {
-                description: '微信原生页',
-                link_page_type: 'LINK_PAGE_TYPE_CANVAS_WECHAT',
-              },
-            ],
-            required: false,
-          },
-        },
-      ],
-    },
-    promoted_object_type: 'PROMOTED_OBJECT_TYPE_WECHAT_OFFICIAL_ACCOUNT',
-    site_set: ['SITE_SET_MOMENTS', 'SITE_SET_WECHAT'],
-    support_bid_mode_list: ['BID_MODE_CPM', 'BID_MODE_OCPM'],
-    support_billing_spec_list: [
-      {
-        billing_event: 'BILLINGEVENT_IMPRESSION',
-        max_price: 99900,
-        min_price: 150,
-      },
-    ],
-    support_dynamic_ability_spec_list: {
-      dynamic_ability_type: ['DYNAMIC_TYPE_DYNAMIC_CREATIVE'],
-      product_item_display_quantity: [],
-    },
-    unsupport_bid_mode_list: [
-      {
-        bid_mode_list: ['BID_MODE_CPC', 'BID_MODE_OCPC'],
-        site_set: ['SITE_SET_MOMENTS'],
-      },
-      {
-        bid_mode_list: ['BID_MODE_CPA'],
-        site_set: ['SITE_SET_MOMENTS'],
-      },
-      {
-        bid_mode_list: ['BID_MODE_CPC', 'BID_MODE_OCPC'],
-        site_set: ['SITE_SET_WECHAT'],
-      },
-      {
-        bid_mode_list: ['BID_MODE_CPA'],
-        site_set: ['SITE_SET_WECHAT'],
-      },
-    ],
-    unsupport_billing_spec_list: [
-      {
-        billing_event: 'BILLINGEVENT_CLICK',
-        site_set: ['SITE_SET_MOMENTS'],
-        unsupport_type: 'UNSUPPORT_TYPE_EXPOSURE',
-      },
-      {
-        billing_event: 'BILLINGEVENT_APP_DOWNLOAD',
-        site_set: ['SITE_SET_MOMENTS'],
-        unsupport_type: 'UNSUPPORT_TYPE_EXPOSURE',
-      },
-      {
-        billing_event: 'BILLINGEVENT_CLICK',
-        site_set: ['SITE_SET_WECHAT'],
-        unsupport_type: 'UNSUPPORT_TYPE_EXPOSURE',
-      },
-      {
-        billing_event: 'BILLINGEVENT_APP_DOWNLOAD',
-        site_set: ['SITE_SET_WECHAT'],
-        unsupport_type: 'UNSUPPORT_TYPE_EXPOSURE',
-      },
-    ],
-    unsupport_siteset_detail_spec: [
-      {
-        site_set: [],
-      },
-    ],
-  },
-  //618
-  {
-    adcreative_attributes: [
-      {
-        description: '头像及昵称跳转页',
-        field_type: 'FIELD_TYPE_INTEGER',
-        name: 'profile_id',
-        property_detail: {
-          integer_detail: {
-            max: 20,
-            min: 0,
-          },
-        },
-        required: true,
-      },
-      {
-        description: '分享信息',
-        field_type: 'FIELD_TYPE_STRUCT',
-        name: 'share_content_spec',
-        property_detail: {
-          struct_detail: {
-            element_list: [
-              {
-                description: '分享描述',
-                field_type: 'FIELD_TYPE_STRING',
-                name: 'share_desc',
-                property_detail: {
-                  string_detail: {
-                    max_length: 20,
-                    min_length: 1,
-                    text_pattern: '^[^\\<\\>\\&\'\\"\\/\\x08\\x09\\x0A\\x0D\\\\]+$',
-                  },
-                },
-                required: true,
-              },
-              {
-                description: '分享标题',
-                field_type: 'FIELD_TYPE_STRING',
-                name: 'share_title',
-                property_detail: {
-                  string_detail: {
-                    max_length: 14,
-                    min_length: 1,
-                    text_pattern: '^[^\\<\\>\\&\'\\"\\/\\x08\\x09\\x0A\\x0D\\\\]+$',
-                  },
-                },
-                required: true,
-              },
-            ],
-          },
-        },
-        required: false,
-      },
-      {
-        description: '动态创意分组',
-        field_type: 'FIELD_TYPE_ENUM',
-        name: 'dynamic_creative_group_used',
-        property_detail: {
-          enum_detail: {
-            default: 'NOT_USE_GROUP',
-            enumeration: [
-              {
-                description: '不使用组合',
-                value: 'NOT_USE_GROUP',
-              },
-              {
-                description: '视频封面图组合',
-                value: 'VIDEO_IMAGE_GROUP',
-              },
-            ],
-          },
-        },
-        required: false,
-      },
-      {
-        description: '转化数据类型',
-        field_type: 'FIELD_TYPE_ENUM',
-        name: 'conversion_data_type',
-        property_detail: {
-          enum_detail: {
-            enumeration: [
-              {
-                category: 'VIEW_DETAILS',
-                description: '转化数据量',
-                value: 'CONVERSION_DATA_ADMETRIC',
-              },
-              {
-                category: 'VIEW_DETAILS',
-                description: '好友关注量',
-                value: 'CONVERSION_DATA_FRIEND_FOLLOW',
-              },
-              {
-                category: 'MORE_INFO',
-                description: '转化数据量',
-                value: 'CONVERSION_DATA_ADMETRIC',
-              },
-              {
-                category: 'MORE_INFO',
-                description: '好友关注量',
-                value: 'CONVERSION_DATA_FRIEND_FOLLOW',
-              },
-              {
-                category: 'BUY_NOW',
-                description: '转化数据量',
-                value: 'CONVERSION_DATA_ADMETRIC',
-              },
-              {
-                category: 'BUY_NOW',
-                description: '好友关注量',
-                value: 'CONVERSION_DATA_FRIEND_FOLLOW',
-              },
-              {
-                category: 'RESERVE_NOW',
-                description: '转化数据量',
-                value: 'CONVERSION_DATA_ADMETRIC',
-              },
-              {
-                category: 'RESERVE_NOW',
-                description: '好友关注量',
-                value: 'CONVERSION_DATA_FRIEND_FOLLOW',
-              },
-              {
-                category: 'CONSULT_NOW',
-                description: '转化数据量',
-                value: 'CONVERSION_DATA_ADMETRIC',
-              },
-              {
-                category: 'CONSULT_NOW',
-                description: '好友关注量',
-                value: 'CONVERSION_DATA_FRIEND_FOLLOW',
-              },
-              {
-                category: 'APPLY_NOW',
-                description: '转化数据量',
-                value: 'CONVERSION_DATA_ADMETRIC',
-              },
-              {
-                category: 'APPLY_NOW',
-                description: '好友关注量',
-                value: 'CONVERSION_DATA_FRIEND_FOLLOW',
-              },
-              {
-                category: 'BOOK_NOW',
-                description: '转化数据量',
-                value: 'CONVERSION_DATA_ADMETRIC',
-              },
-              {
-                category: 'BOOK_NOW',
-                description: '好友关注量',
-                value: 'CONVERSION_DATA_FRIEND_FOLLOW',
-              },
-              {
-                category: 'GET_COUPONS',
-                description: '转化数据量',
-                value: 'CONVERSION_DATA_ADMETRIC',
-              },
-              {
-                category: 'GET_COUPONS',
-                description: '好友关注量',
-                value: 'CONVERSION_DATA_FRIEND_FOLLOW',
-              },
-              {
-                category: 'GET_IT_NOW',
-                description: '转化数据量',
-                value: 'CONVERSION_DATA_ADMETRIC',
-              },
-              {
-                category: 'GET_IT_NOW',
-                description: '好友关注量',
-                value: 'CONVERSION_DATA_FRIEND_FOLLOW',
-              },
-              {
-                category: 'FOLLOW_OFFICIAL_ACCOUNT',
-                description: '转化数据量',
-                value: 'CONVERSION_DATA_ADMETRIC',
-              },
-              {
-                category: 'FOLLOW_OFFICIAL_ACCOUNT',
-                description: '好友关注量',
-                value: 'CONVERSION_DATA_FRIEND_FOLLOW',
-              },
-              {
-                category: 'READ_NOVELS',
-                description: '转化数据量',
-                value: 'CONVERSION_DATA_ADMETRIC',
-              },
-              {
-                category: 'READ_NOVELS',
-                description: '好友关注量',
-                value: 'CONVERSION_DATA_FRIEND_FOLLOW',
-              },
-              {
-                category: '',
-                description: '转化数据量',
-                value: 'CONVERSION_DATA_ADMETRIC',
-              },
-              {
-                category: '',
-                description: '好友关注量',
-                value: 'CONVERSION_DATA_FRIEND_FOLLOW',
-              },
-            ],
-          },
-        },
-        required: false,
-      },
-      {
-        description: '转化数据量类型',
-        field_type: 'FIELD_TYPE_ENUM',
-        name: 'conversion_target_type',
-        property_detail: {
-          enum_detail: {
-            enumeration: [
-              {
-                category: 'VIEW_DETAILS',
-                description: '领取',
-                value: 'CONVERSION_TARGET_GET',
-              },
-              {
-                category: 'VIEW_DETAILS',
-                description: '预约',
-                value: 'CONVERSION_TARGET_RESERVE',
-              },
-              {
-                category: 'VIEW_DETAILS',
-                description: '购买',
-                value: 'CONVERSION_TARGET_BUY',
-              },
-              {
-                category: 'VIEW_DETAILS',
-                description: '申请',
-                value: 'CONVERSION_TARGET_APPLY',
-              },
-              {
-                category: 'VIEW_DETAILS',
-                description: '咨询',
-                value: 'CONVERSION_TARGET_CONSULT',
-              },
-              {
-                category: 'MORE_INFO',
-                description: '领取',
-                value: 'CONVERSION_TARGET_GET',
-              },
-              {
-                category: 'MORE_INFO',
-                description: '预约',
-                value: 'CONVERSION_TARGET_RESERVE',
-              },
-              {
-                category: 'MORE_INFO',
-                description: '购买',
-                value: 'CONVERSION_TARGET_BUY',
-              },
-              {
-                category: 'MORE_INFO',
-                description: '申请',
-                value: 'CONVERSION_TARGET_APPLY',
-              },
-              {
-                category: 'MORE_INFO',
-                description: '咨询',
-                value: 'CONVERSION_TARGET_CONSULT',
-              },
-              {
-                category: 'BUY_NOW',
-                description: '购买',
-                value: 'CONVERSION_TARGET_BUY',
-              },
-              {
-                category: 'RESERVE_NOW',
-                description: '预约',
-                value: 'CONVERSION_TARGET_RESERVE',
-              },
-              {
-                category: 'CONSULT_NOW',
-                description: '咨询',
-                value: 'CONVERSION_TARGET_CONSULT',
-              },
-              {
-                category: 'APPLY_NOW',
-                description: '申请',
-                value: 'CONVERSION_TARGET_APPLY',
-              },
-              {
-                category: 'BOOK_NOW',
-                description: '预定',
-                value: 'CONVERSION_TARGET_BOOK',
-              },
-              {
-                category: 'GET_COUPONS',
-                description: '领取',
-                value: 'CONVERSION_TARGET_GET',
-              },
-              {
-                category: 'GET_IT_NOW',
-                description: '领取',
-                value: 'CONVERSION_TARGET_GET',
-              },
-              {
-                category: 'FOLLOW_OFFICIAL_ACCOUNT',
-                description: '关注',
-                value: 'CONVERSION_TARGET_FOLLOW',
-              },
-              {
-                category: 'READ_NOVELS',
-                description: '阅读',
-                value: 'CONVERSION_TARGET_READ',
-              },
-              {
-                category: '',
-                description: '领取',
-                value: 'CONVERSION_TARGET_GET',
-              },
-              {
-                category: '',
-                description: '预约',
-                value: 'CONVERSION_TARGET_RESERVE',
-              },
-              {
-                category: '',
-                description: '购买',
-                value: 'CONVERSION_TARGET_BUY',
-              },
-              {
-                category: '',
-                description: '申请',
-                value: 'CONVERSION_TARGET_APPLY',
-              },
-              {
-                category: '',
-                description: '咨询',
-                value: 'CONVERSION_TARGET_CONSULT',
-              },
-            ],
-          },
-        },
-        required: false,
-      },
-    ],
-    adcreative_elements: [
-      {
-        array_property: [],
-        description: '品牌标识图',
-        element_type: 'ELEMENT_TYPE_IMAGE',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_STRING',
-        name: 'brand_img',
-        parent_name: 'brand',
-        required: true,
-        restriction: {
-          image_restriction: {
-            file_format: ['IMAGE_TYPE_JPG', 'IMAGE_TYPE_PNG'],
-            file_size: 400,
-            height: 512,
-            width: 512,
-          },
-        },
-        struct_property: [],
-      },
-      {
-        array_property: [],
-        description: '品牌名称',
-        element_type: 'ELEMENT_TYPE_TEXT',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_STRING',
-        name: 'brand_name',
-        parent_name: 'brand',
-        required: true,
-        restriction: {
-          text_restriction: {
-            max_length: 12,
-            min_length: 2,
-            text_pattern: '^[^\\<\\>\\&\'\\"\\/\\x08\\x09\\x0A\\x0D\\\\]+$',
-          },
-        },
-        struct_property: [],
-      },
-      {
-        array_property: [],
-        description: '品牌形象',
-        element_type: 'ELEMENT_TYPE_STRUCT',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_STRUCT',
-        name: 'brand',
-        parent_name: '',
-        required: false,
-        restriction: [],
-        struct_property: {
-          element_mutual_exclusive: false,
-        },
-      },
-      {
-        array_property: [],
-        description: 'Canvas',
-        element_type: 'ELEMENT_TYPE_CANVAS',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_INTEGER',
-        name: 'canvas',
-        parent_name: '',
-        required: false,
-        restriction: [],
-        struct_property: [],
-      },
-      {
-        array_property: [],
-        description: '文案',
-        element_type: 'ELEMENT_TYPE_TEXT',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_STRING',
-        name: 'description',
-        parent_name: '',
-        required: true,
-        restriction: {
-          text_restriction: {
-            max_length: 30,
-            min_length: 1,
-            text_pattern: '^[^\\<\\>\\&\'\\"\\/\\x08\\x09\\x0A\\x0D\\\\]+$',
-          },
-        },
-        struct_property: [],
-      },
-      {
-        array_property: [],
-        description: '链接名称类型',
-        element_type: 'ELEMENT_TYPE_ENUM',
-        enum_property: {
-          default: '',
-          enumeration: [
-            {
-              description: '去唯品会',
-              value: 'GO_TO_VIP',
-            },
-            {
-              description: '去小红书',
-              value: 'GO_TO_RED',
-            },
-            {
-              description: '去快手',
-              value: 'GO_TO_KUAISHOU',
-            },
-            {
-              description: '进入小程序',
-              value: 'ENTER_MINI_PROGRAM',
-            },
-            {
-              description: '立即购买',
-              value: 'BUY_NOW',
-            },
-            {
-              description: '去京东',
-              value: 'GO_TO_JD',
-            },
-            {
-              description: '去苏宁',
-              value: 'GO_TO_SUNING',
-            },
-            {
-              description: '领取优惠',
-              value: 'GET_COUPONS',
-            },
-            {
-              description: '预约活动',
-              value: 'MAKE_AN_APPOINTMENT',
-            },
-            {
-              description: '去逛逛',
-              value: 'GO_SHOPPING',
-            },
-            {
-              description: '进入小游戏',
-              value: 'ENTER_MINI_GAME',
-            },
-            {
-              description: '去拼多多',
-              value: 'GO_TO_PDD',
-            },
-            {
-              description: '查看详情',
-              value: 'VIEW_DETAILS',
-            },
-          ],
-        },
-        field_type: 'FIELD_TYPE_STRING',
-        name: 'link_name_type',
-        parent_name: '',
-        required: false,
-        restriction: [],
-        struct_property: [],
-      },
-      {
-        array_property: [],
-        description: '小程序id',
-        element_type: 'ELEMENT_TYPE_REFERENCE',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_INTEGER',
-        name: 'mini_program_id',
-        parent_name: '',
-        required: false,
-        restriction: [],
-        struct_property: [],
-      },
-      {
-        array_property: [],
-        description: '小程序路径',
-        element_type: 'ELEMENT_TYPE_URL',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_STRING',
-        name: 'mini_program_path',
-        parent_name: '',
-        required: false,
-        restriction: {
-          url_restriction: {
-            url_pattern: '.*',
-          },
-        },
-        struct_property: [],
-      },
-      {
-        array_property: [],
-        description: '视频',
-        element_type: 'ELEMENT_TYPE_VIDEO',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_INTEGER',
-        name: 'short_video1',
-        parent_name: 'short_video_struct',
-        required: true,
-        restriction: {
-          video_restriction: {
-            file_format: ['MEDIA_TYPE_MP4', 'MEDIA_TYPE_MOV', 'MEDIA_TYPE_AVI'],
-            file_size: 102400,
-            height: 0,
-            max_duration: 30,
-            min_duration: 5,
-            min_height: 480,
-            min_width: 640,
-            ratio_height: 3,
-            ratio_width: 4,
-            width: 0,
-          },
-        },
-        struct_property: [],
-      },
-      {
-        array_property: [],
-        description: '短视频结构',
-        element_type: 'ELEMENT_TYPE_STRUCT',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_STRUCT',
-        name: 'short_video_struct',
-        parent_name: '',
-        required: true,
-        restriction: [],
-        struct_property: {
-          element_mutual_exclusive: false,
-        },
-      },
-    ],
-    adcreative_sample_image:
-      'http://qzonestyle.gtimg.cn/gdt_ui_proj/dist/gdt/imgbox/mp-video-nor.svg',
-    adcreative_template_appellation: '常规视频  4:3',
-    adcreative_template_id: 618,
-    xd_show: true,
-    sj_show: true,
-    adcreative_template_style: '视频',
-    landing_page_config: {
-      required: false,
-      support_page_type_list: [
-        {
-          description: '微信原生推广页',
-          example: '',
-          page_type: 'PAGE_TYPE_CANVAS_WECHAT',
-          support_link_name_type: {
-            list: [
-              {
-                description: '查看详情',
-                link_name_type: 'VIEW_DETAILS',
-              },
-              {
-                description: '了解更多',
-                link_name_type: 'MORE_INFO',
-              },
-              {
-                description: '立即购买',
-                link_name_type: 'BUY_NOW',
-              },
-              {
-                description: '立即申请',
-                link_name_type: 'APPLY_NOW',
-              },
-              {
-                description: '立即预定',
-                link_name_type: 'BOOK_NOW',
-              },
-              {
-                description: '立即咨询',
-                link_name_type: 'CONSULT_NOW',
-              },
-              {
-                description: '立即领取',
-                link_name_type: 'GET_IT_NOW',
-              },
-              {
-                description: '立即预约',
-                link_name_type: 'RESERVE_NOW',
-              },
-              {
-                description: '领取优惠',
-                link_name_type: 'GET_COUPONS',
-              },
-              {
-                description: '去逛逛',
-                link_name_type: 'GO_SHOPPING',
-              },
-              {
-                description: '关注公众号',
-                link_name_type: 'FOLLOW_OFFICIAL_ACCOUNT',
-              },
-              {
-                description: '阅读小说',
-                link_name_type: 'READ_NOVELS',
-              },
-            ],
-            required: false,
-          },
-          support_link_page_type: {
-            list: [
-              {
-                description: ' 微信公众号详情页',
-                link_page_type: 'LINK_PAGE_TYPE_WECHAT_OFFICIAL_ACCOUNT_DETAIL',
-              },
-              {
-                description: '微信原生页',
-                link_page_type: 'LINK_PAGE_TYPE_CANVAS_WECHAT',
-              },
-            ],
-            required: false,
-          },
-        },
-        {
-          description: '微信简版原生页',
-          example: '',
-          page_type: 'PAGE_TYPE_MOMENTS_SIMPLE_NATIVE_WECHAT',
-          support_link_name_type: {
-            list: [
-              {
-                description: '查看详情',
-                link_name_type: 'VIEW_DETAILS',
-              },
-              {
-                description: '了解更多',
-                link_name_type: 'MORE_INFO',
-              },
-              {
-                description: '立即购买',
-                link_name_type: 'BUY_NOW',
-              },
-              {
-                description: '立即申请',
-                link_name_type: 'APPLY_NOW',
-              },
-              {
-                description: '立即预定',
-                link_name_type: 'BOOK_NOW',
-              },
-              {
-                description: '立即咨询',
-                link_name_type: 'CONSULT_NOW',
-              },
-              {
-                description: '立即预约',
-                link_name_type: 'RESERVE_NOW',
-              },
-              {
-                description: '立即领取',
-                link_name_type: 'GET_IT_NOW',
-              },
-              {
-                description: '领取优惠',
-                link_name_type: 'GET_COUPONS',
-              },
-              {
-                description: '去逛逛',
-                link_name_type: 'GO_SHOPPING',
-              },
-              {
-                description: '关注公众号',
-                link_name_type: 'FOLLOW_OFFICIAL_ACCOUNT',
-              },
-              {
-                description: '阅读小说',
-                link_name_type: 'READ_NOVELS',
-              },
-            ],
-            required: false,
-          },
-          support_link_page_type: {
-            list: [
-              {
-                description: ' 微信公众号详情页',
-                link_page_type: 'LINK_PAGE_TYPE_WECHAT_OFFICIAL_ACCOUNT_DETAIL',
-              },
-            ],
-            required: false,
-          },
-        },
-      ],
-    },
-    promoted_object_type: 'PROMOTED_OBJECT_TYPE_WECHAT_OFFICIAL_ACCOUNT',
-    site_set: ['SITE_SET_MOMENTS', 'SITE_SET_WECHAT'],
-    support_bid_mode_list: ['BID_MODE_CPM', 'BID_MODE_OCPM'],
-    support_billing_spec_list: [
-      {
-        billing_event: 'BILLINGEVENT_IMPRESSION',
-        max_price: 99900,
-        min_price: 150,
-      },
-    ],
-    support_dynamic_ability_spec_list: {
-      dynamic_ability_type: ['DYNAMIC_TYPE_DYNAMIC_CREATIVE'],
-      product_item_display_quantity: [],
-    },
-    unsupport_bid_mode_list: [
-      {
-        bid_mode_list: ['BID_MODE_CPC', 'BID_MODE_OCPC'],
-        site_set: ['SITE_SET_MOMENTS'],
-      },
-      {
-        bid_mode_list: ['BID_MODE_CPA'],
-        site_set: ['SITE_SET_MOMENTS'],
-      },
-    ],
-    unsupport_billing_spec_list: [
-      {
-        billing_event: 'BILLINGEVENT_CLICK',
-        site_set: ['SITE_SET_MOMENTS'],
-        unsupport_type: 'UNSUPPORT_TYPE_EXPOSURE',
-      },
-      {
-        billing_event: 'BILLINGEVENT_APP_DOWNLOAD',
-        site_set: ['SITE_SET_MOMENTS'],
-        unsupport_type: 'UNSUPPORT_TYPE_EXPOSURE',
-      },
-    ],
-    unsupport_siteset_detail_spec: [
-      {
-        site_set: ['SITE_SET_WECHAT'],
-      },
-    ],
-  },
-  //1708
-  {
-    adcreative_attributes: [
-      {
-        description: '头像及昵称跳转页',
-        field_type: 'FIELD_TYPE_INTEGER',
-        name: 'profile_id',
-        property_detail: {
-          integer_detail: {
-            max: 20,
-            min: 0,
-          },
-        },
-        required: true,
-      },
-      {
-        description: '分享信息',
-        field_type: 'FIELD_TYPE_STRUCT',
-        name: 'share_content_spec',
-        property_detail: {
-          struct_detail: {
-            element_list: [
-              {
-                description: '分享描述',
-                field_type: 'FIELD_TYPE_STRING',
-                name: 'share_desc',
-                property_detail: {
-                  string_detail: {
-                    max_length: 20,
-                    min_length: 1,
-                    text_pattern: '^[^\\<\\>\\&\'\\"\\/\\x08\\x09\\x0A\\x0D\\\\]+$',
-                  },
-                },
-                required: true,
-              },
-              {
-                description: '分享标题',
-                field_type: 'FIELD_TYPE_STRING',
-                name: 'share_title',
-                property_detail: {
-                  string_detail: {
-                    max_length: 14,
-                    min_length: 1,
-                    text_pattern: '^[^\\<\\>\\&\'\\"\\/\\x08\\x09\\x0A\\x0D\\\\]+$',
-                  },
-                },
-                required: true,
-              },
-            ],
-          },
-        },
-        required: false,
-      },
-      {
-        description: '动态创意分组',
-        field_type: 'FIELD_TYPE_ENUM',
-        name: 'dynamic_creative_group_used',
-        property_detail: {
-          enum_detail: {
-            default: 'NOT_USE_GROUP',
-            enumeration: [
-              {
-                description: '不使用组合',
-                value: 'NOT_USE_GROUP',
-              },
-              {
-                description: '视频封面图组合',
-                value: 'VIDEO_IMAGE_GROUP',
-              },
-            ],
-          },
-        },
-        required: false,
-      },
-    ],
-    adcreative_elements: [
-      {
-        array_property: [],
-        description: '品牌名称',
-        element_type: 'ELEMENT_TYPE_TEXT',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_STRING',
-        name: 'brand_name',
-        parent_name: 'brand',
-        required: true,
-        restriction: {
-          text_restriction: {
-            max_length: 12,
-            min_length: 2,
-            text_pattern: '^[^\\<\\>\\&\'\\"\\/\\x08\\x09\\x0A\\x0D\\\\]+$',
-          },
-        },
-        struct_property: [],
-      },
-      {
-        array_property: [],
-        description: '品牌标识图',
-        element_type: 'ELEMENT_TYPE_IMAGE',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_STRING',
-        name: 'brand_img',
-        parent_name: 'brand',
-        required: true,
-        restriction: {
-          image_restriction: {
-            file_format: ['IMAGE_TYPE_JPG', 'IMAGE_TYPE_PNG'],
-            file_size: 400,
-            height: 512,
-            width: 512,
-          },
-        },
-        struct_property: [],
-      },
-      {
-        array_property: [],
-        description: '品牌形象',
-        element_type: 'ELEMENT_TYPE_STRUCT',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_STRUCT',
-        name: 'brand',
-        parent_name: '',
-        required: false,
-        restriction: [],
-        struct_property: {
-          element_mutual_exclusive: false,
-        },
-      },
-      {
-        array_property: [],
-        description: 'Canvas',
-        element_type: 'ELEMENT_TYPE_CANVAS',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_INTEGER',
-        name: 'canvas',
-        parent_name: '',
-        required: false,
-        restriction: [],
-        struct_property: [],
-      },
-      {
-        array_property: [],
-        description: '倒计时结束时间(选填)',
-        element_type: 'ELEMENT_TYPE_TEXT',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_STRING',
-        name: 'countdown_expiring_timestamp',
-        parent_name: '',
-        required: false,
-        restriction: {
-          text_restriction: {
-            max_length: 13,
-            min_length: 1,
-            text_pattern: '^[^\\<\\>\\&\'\\"\\/\\x08\\x09\\x0A\\x0D\\\\]+$',
-          },
-        },
-        struct_property: [],
-      },
-      {
-        array_property: [],
-        description: '广告详情',
-        element_type: 'ELEMENT_TYPE_TEXT',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_STRING',
-        name: 'description',
-        parent_name: '',
-        required: true,
-        restriction: {
-          text_restriction: {
-            max_length: 30,
-            min_length: 1,
-            text_pattern: '^[^\\<\\>\\&\'\\"\\/\\x08\\x09\\x0A\\x0D\\\\]+$',
-          },
-        },
-        struct_property: [],
-      },
-      {
-        description: '标签内容',
-        element_type: 'ELEMENT_TYPE_TEXT',
-        field_type: 'FIELD_TYPE_STRING',
-        name: 'content',
-        parent_name: 'label',
-        required: true,
-        restriction: {
-          text_restriction: {
-            max_length: 16,
-            min_length: 1,
-            text_pattern: '',
-          },
-        },
-      },
-      {
-        array_property: {
-          max_number: 3,
-          min_number: 0,
-        },
-        description: '标签',
-        element_type: 'ELEMENT_TYPE_STRUCT',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_STRUCT_ARRAY',
-        name: 'label',
-        parent_name: '',
-        required: false,
-        restriction: [],
-        struct_property: [],
-      },
-      {
-        array_property: [],
-        description: '标题',
-        element_type: 'ELEMENT_TYPE_TEXT',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_STRING',
-        name: 'title',
-        parent_name: '',
-        required: false,
-        restriction: {
-          text_restriction: {
-            max_length: 14,
-            min_length: 1,
-            text_pattern: '^[^\\<\\>\\&\'\\"\\/\\x08\\x09\\x0A\\x0D\\\\]+$',
-          },
-        },
-        struct_property: [],
-      },
-      {
-        array_property: [],
-        description: '视频',
-        element_type: 'ELEMENT_TYPE_VIDEO',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_INTEGER',
-        name: 'video',
-        parent_name: '',
-        required: true,
-        restriction: {
-          video_restriction: {
-            file_format: ['MEDIA_TYPE_MP4', 'MEDIA_TYPE_MOV', 'MEDIA_TYPE_AVI'],
-            file_size: 102400,
-            height: 0,
-            max_duration: 30,
-            min_duration: 5,
-            min_height: 360,
-            min_width: 640,
-            ratio_height: 9,
-            ratio_width: 16,
-            width: 0,
-          },
-        },
-        struct_property: [],
-      },
-      {
-        array_property: [],
-        description: '卖点图',
-        element_type: 'ELEMENT_TYPE_IMAGE',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_STRING',
-        name: 'shop_image',
-        parent_name: '',
-        required: false,
-        restriction: {
-          image_restriction: {
-            file_format: ['IMAGE_TYPE_JPG', 'IMAGE_TYPE_PNG'],
-            file_size: 20,
-            height: 80,
-            width: 80,
-          },
-        },
-        struct_property: [],
-      },
-      {
-        array_property: [],
-        description: '倒计时开始时间(选填)',
-        element_type: 'ELEMENT_TYPE_TEXT',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_STRING',
-        name: 'countdown_begin',
-        parent_name: '',
-        required: false,
-        restriction: {
-          text_restriction: {
-            max_length: 11,
-            min_length: 1,
-            text_pattern: '^[^\\<\\>\\&\'\\"\\/\\x08\\x09\\x0A\\x0D\\\\]+$',
-          },
-        },
-        struct_property: [],
-      },
-      {
-        array_property: [],
-        description: '倒计时时间描述',
-        element_type: 'ELEMENT_TYPE_TEXT',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_STRING',
-        name: 'countdown_time_type',
-        parent_name: '',
-        required: false,
-        restriction: {
-          text_restriction: {
-            max_length: 64,
-            min_length: 1,
-            text_pattern: '^[^\\<\\>\\&\'\\"\\/\\x08\\x09\\x0A\\x0D\\\\]+$',
-          },
-        },
-        struct_property: [],
-      },
-      {
-        array_property: [],
-        description: '倒计时价格展示(选填)',
-        element_type: 'ELEMENT_TYPE_TEXT',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_STRING',
-        name: 'countdown_price',
-        parent_name: '',
-        required: false,
-        restriction: {
-          text_restriction: {
-            max_length: 9,
-            min_length: 1,
-            text_pattern: '^[^\\<\\>\\&\'\\"\\/\\x08\\x09\\x0A\\x0D\\\\]+$',
-          },
-        },
-        struct_property: [],
-      },
-      {
-        array_property: [],
-        description: '是否支开启卖点图',
-        element_type: 'ELEMENT_TYPE_BOOLEAN',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_BOOLEAN',
-        name: 'shop_image_switch',
-        parent_name: 'shop_image_struct',
-        required: true,
-        restriction: [],
-        struct_property: [],
-      },
-      {
-        array_property: [],
-        description: '启用动态卖点图',
-        element_type: 'ELEMENT_TYPE_BOOLEAN',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_BOOLEAN',
-        name: 'dynamic_shop_image_switch',
-        parent_name: 'shop_image_struct',
-        required: false,
-        restriction: [],
-        struct_property: [],
-      },
-      {
-        array_property: [],
-        description: '卖点图',
-        element_type: 'ELEMENT_TYPE_IMAGE',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_STRING',
-        name: 'shop_image_id',
-        parent_name: 'shop_image_struct',
-        required: false,
-        restriction: {
-          image_restriction: {
-            file_format: ['IMAGE_TYPE_JPG', 'IMAGE_TYPE_PNG'],
-            file_size: 20,
-            height: 80,
-            width: 80,
-          },
-        },
-        struct_property: [],
-      },
-      {
-        array_property: [],
-        description: '卖点标题(选填)',
-        element_type: 'ELEMENT_TYPE_TEXT',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_STRING',
-        name: 'shop_image_title',
-        parent_name: 'shop_image_struct',
-        required: false,
-        restriction: {
-          text_restriction: {
-            max_length: 10,
-            min_length: 1,
-            text_pattern: '^[^\\<\\>\\&\'\\"\\/\\x08\\x09\\x0A\\x0D\\\\]+$',
-          },
-        },
-        struct_property: [],
-      },
-      {
-        array_property: [],
-        description: '卖点描述',
-        element_type: 'ELEMENT_TYPE_TEXT',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_STRING',
-        name: 'shop_image_description',
-        parent_name: 'shop_image_struct',
-        required: false,
-        restriction: {
-          text_restriction: {
-            max_length: 10,
-            min_length: 1,
-            text_pattern: '^[^\\<\\>\\&\'\\"\\/\\x08\\x09\\x0A\\x0D\\\\]+$',
-          },
-        },
-        struct_property: [],
-      },
-      {
-        array_property: [],
-        description: '卖点图',
-        element_type: 'ELEMENT_TYPE_STRUCT',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_STRUCT',
-        name: 'shop_image_struct',
-        parent_name: '',
-        required: false,
-        restriction: [],
-        struct_property: {
-          element_mutual_exclusive: false,
-        },
-      },
-      {
-        array_property: [],
-        description: '右按钮跳转',
-        element_type: 'ELEMENT_TYPE_TEXT',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_STRING',
-        name: 'chosen_button_landing_page2',
-        parent_name: 'chosen_button',
-        required: true,
-        restriction: [],
-        struct_property: [],
-      },
-      {
-        array_property: [],
-        description: '左按钮文案',
-        element_type: 'ELEMENT_TYPE_TEXT',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_STRING',
-        name: 'chosen_button_text1',
-        parent_name: 'chosen_button',
-        required: true,
-        restriction: {
-          text_restriction: {
-            max_length: 4,
-            min_length: 1,
-            text_pattern: '^[^\\<\\>\\&\'\\"\\/\\x08\\x09\\x0A\\x0D\\\\]+$',
-          },
-        },
-        struct_property: [],
-      },
-      {
-        array_property: [],
-        description: '左按钮跳转',
-        element_type: 'ELEMENT_TYPE_TEXT',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_STRING',
-        name: 'chosen_button_landing_page1',
-        parent_name: 'chosen_button',
-        required: true,
-        restriction: [],
-        struct_property: [],
-      },
-      {
-        array_property: [],
-        description: '右按钮文案',
-        element_type: 'ELEMENT_TYPE_TEXT',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_STRING',
-        name: 'chosen_button_text2',
-        parent_name: 'chosen_button',
-        required: true,
-        restriction: {
-          text_restriction: {
-            max_length: 4,
-            min_length: 1,
-            text_pattern: '^[^\\<\\>\\&\'\\"\\/\\x08\\x09\\x0A\\x0D\\\\]+$',
-          },
-        },
-        struct_property: [],
-      },
-      {
-        array_property: [],
-        description: '选择按钮',
-        element_type: 'ELEMENT_TYPE_STRUCT',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_STRUCT',
-        name: 'chosen_button',
-        parent_name: '',
-        required: false,
-        restriction: [],
-        struct_property: {
-          element_mutual_exclusive: false,
-        },
-      },
-      {
-        array_property: [],
-        description: '是否开启轮播文案',
-        element_type: 'ELEMENT_TYPE_TEXT',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_STRING',
-        name: 'living_desc_struct_switch',
-        parent_name: 'living_desc_struct',
-        required: true,
-        restriction: {
-          text_restriction: {
-            max_length: 8,
-            min_length: 1,
-            text_pattern: '^[^\\<\\>\\&\'\\"\\/\\x08\\x09\\x0A\\x0D\\\\]+$',
-          },
-        },
-        struct_property: [],
-      },
-      {
-        array_property: {
-          max_number: 5,
-          min_number: 2,
-        },
-        description: '轮播文案',
-        element_type: 'ELEMENT_TYPE_TEXT',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_STRING_ARRAY',
-        name: 'living_desc_list',
-        parent_name: 'living_desc_struct',
-        required: true,
-        restriction: {
-          text_restriction: {
-            max_length: 16,
-            min_length: 1,
-            text_pattern: '^[^\\<\\>\\&\'\\"\\/\\x08\\x09\\x0A\\x0D\\\\]+$',
-          },
-        },
-        struct_property: [],
-      },
-      {
-        array_property: [],
-        description: '轮播文案',
-        element_type: 'ELEMENT_TYPE_STRUCT',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_STRUCT',
-        name: 'living_desc_struct',
-        parent_name: '',
-        required: false,
-        restriction: [],
-        struct_property: {
-          element_mutual_exclusive: false,
-        },
-      },
-    ],
-    adcreative_sample_image:
-      'http://qzonestyle.gtimg.cn/gdt_ui_proj/dist/gdt/imgbox/mp-video-act.svg',
-    adcreative_template_appellation: '卡片广告 横版视频 16:9',
-    adcreative_template_id: 1708,
-    kp_show: true,
-    adcreative_template_style: '视频',
-    landing_page_config: {
-      required: false,
-      support_page_type_list: [
-        {
-          description: '微信原生推广页',
-          example: '',
-          page_type: 'PAGE_TYPE_CANVAS_WECHAT',
-          support_link_name_type: {
-            list: [
-              {
-                description: '查看详情',
-                link_name_type: 'VIEW_DETAILS',
-              },
-              {
-                description: '了解更多',
-                link_name_type: 'MORE_INFO',
-              },
-              {
-                description: '立即购买',
-                link_name_type: 'BUY_NOW',
-              },
-              {
-                description: '立即申请',
-                link_name_type: 'APPLY_NOW',
-              },
-              {
-                description: '立即预定',
-                link_name_type: 'BOOK_NOW',
-              },
-              {
-                description: '立即咨询',
-                link_name_type: 'CONSULT_NOW',
-              },
-              {
-                description: '立即预约',
-                link_name_type: 'RESERVE_NOW',
-              },
-              {
-                description: '立即领取',
-                link_name_type: 'GET_IT_NOW',
-              },
-              {
-                description: '领取优惠',
-                link_name_type: 'GET_COUPONS',
-              },
-              {
-                description: '去逛逛',
-                link_name_type: 'GO_SHOPPING',
-              },
-              {
-                description: '关注公众号',
-                link_name_type: 'FOLLOW_OFFICIAL_ACCOUNT',
-              },
-              {
-                description: '阅读小说',
-                link_name_type: 'READ_NOVELS',
-              },
-            ],
-            required: false,
-          },
-          support_link_page_type: {
-            list: [
-              {
-                description: '微信原生页',
-                link_page_type: 'LINK_PAGE_TYPE_CANVAS_WECHAT',
-              },
-              {
-                description: ' 微信公众号详情页',
-                link_page_type: 'LINK_PAGE_TYPE_WECHAT_OFFICIAL_ACCOUNT_DETAIL',
-              },
-            ],
-            required: false,
-          },
-        },
-        {
-          description: ' 微信公众号详情页',
-          example: '',
-          page_type: 'PAGE_TYPE_WECHAT_OFFICIAL_ACCOUNT_DETAIL',
-          support_link_name_type: {
-            list: [
-              {
-                description: '查看详情',
-                link_name_type: 'VIEW_DETAILS',
-              },
-              {
-                description: '了解更多',
-                link_name_type: 'MORE_INFO',
-              },
-              {
-                description: '立即购买',
-                link_name_type: 'BUY_NOW',
-              },
-              {
-                description: '立即申请',
-                link_name_type: 'APPLY_NOW',
-              },
-              {
-                description: '立即预定',
-                link_name_type: 'BOOK_NOW',
-              },
-              {
-                description: '立即咨询',
-                link_name_type: 'CONSULT_NOW',
-              },
-              {
-                description: '立即预约',
-                link_name_type: 'RESERVE_NOW',
-              },
-              {
-                description: '立即领取',
-                link_name_type: 'GET_IT_NOW',
-              },
-              {
-                description: '领取优惠',
-                link_name_type: 'GET_COUPONS',
-              },
-              {
-                description: '去逛逛',
-                link_name_type: 'GO_SHOPPING',
-              },
-              {
-                description: '关注公众号',
-                link_name_type: 'FOLLOW_OFFICIAL_ACCOUNT',
-              },
-              {
-                description: '阅读小说',
-                link_name_type: 'READ_NOVELS',
-              },
-            ],
-            required: false,
-          },
-          support_link_page_type: {
-            list: [
-              {
-                description: ' 微信公众号详情页',
-                link_page_type: 'LINK_PAGE_TYPE_WECHAT_OFFICIAL_ACCOUNT_DETAIL',
-              },
-            ],
-            required: false,
-          },
-        },
-      ],
-    },
-    promoted_object_type: 'PROMOTED_OBJECT_TYPE_WECHAT_OFFICIAL_ACCOUNT',
-    site_set: ['SITE_SET_MOMENTS', 'SITE_SET_WECHAT'],
-    support_bid_mode_list: ['BID_MODE_CPM', 'BID_MODE_OCPM'],
-    support_billing_spec_list: [
-      {
-        billing_event: 'BILLINGEVENT_IMPRESSION',
-        max_price: 99900,
-        min_price: 150,
-      },
-    ],
-    support_dynamic_ability_spec_list: {
-      dynamic_ability_type: ['DYNAMIC_TYPE_DYNAMIC_CREATIVE'],
-      product_item_display_quantity: [],
-    },
-    unsupport_bid_mode_list: [
-      {
-        bid_mode_list: ['BID_MODE_CPC', 'BID_MODE_OCPC'],
-        site_set: ['SITE_SET_MOMENTS'],
-      },
-      {
-        bid_mode_list: ['BID_MODE_CPA'],
-        site_set: ['SITE_SET_MOMENTS'],
-      },
-      {
-        bid_mode_list: ['BID_MODE_CPC', 'BID_MODE_OCPC'],
-        site_set: ['SITE_SET_WECHAT'],
-      },
-      {
-        bid_mode_list: ['BID_MODE_CPA'],
-        site_set: ['SITE_SET_WECHAT'],
-      },
-    ],
-    unsupport_billing_spec_list: [
-      {
-        billing_event: 'BILLINGEVENT_CLICK',
-        site_set: ['SITE_SET_MOMENTS'],
-        unsupport_type: 'UNSUPPORT_TYPE_EXPOSURE',
-      },
-      {
-        billing_event: 'BILLINGEVENT_APP_DOWNLOAD',
-        site_set: ['SITE_SET_MOMENTS'],
-        unsupport_type: 'UNSUPPORT_TYPE_EXPOSURE',
-      },
-      {
-        billing_event: 'BILLINGEVENT_CLICK',
-        site_set: ['SITE_SET_WECHAT'],
-        unsupport_type: 'UNSUPPORT_TYPE_EXPOSURE',
-      },
-      {
-        billing_event: 'BILLINGEVENT_APP_DOWNLOAD',
-        site_set: ['SITE_SET_WECHAT'],
-        unsupport_type: 'UNSUPPORT_TYPE_EXPOSURE',
-      },
-    ],
-    unsupport_siteset_detail_spec: [
-      {
-        site_set: [],
-      },
-    ],
-  },
-  //311
-  {
-    adcreative_attributes: [
-      {
-        description: '头像及昵称跳转页',
-        field_type: 'FIELD_TYPE_INTEGER',
-        name: 'profile_id',
-        property_detail: {
-          integer_detail: {
-            max: 20,
-            min: 0,
-          },
-        },
-        required: true,
-      },
-      {
-        description: '分享信息',
-        field_type: 'FIELD_TYPE_STRUCT',
-        name: 'share_content_spec',
-        property_detail: {
-          struct_detail: {
-            element_list: [
-              {
-                description: '分享描述',
-                field_type: 'FIELD_TYPE_STRING',
-                name: 'share_desc',
-                property_detail: {
-                  string_detail: {
-                    max_length: 20,
-                    min_length: 1,
-                    text_pattern: '^[^\\<\\>\\&\'\\"\\/\\x08\\x09\\x0A\\x0D\\\\]+$',
-                  },
-                },
-                required: true,
-              },
-              {
-                description: '分享标题',
-                field_type: 'FIELD_TYPE_STRING',
-                name: 'share_title',
-                property_detail: {
-                  string_detail: {
-                    max_length: 14,
-                    min_length: 1,
-                    text_pattern: '^[^\\<\\>\\&\'\\"\\/\\x08\\x09\\x0A\\x0D\\\\]+$',
-                  },
-                },
-                required: true,
-              },
-            ],
-          },
-        },
-        required: false,
-      },
-      {
-        description: '动态创意分组',
-        field_type: 'FIELD_TYPE_ENUM',
-        name: 'dynamic_creative_group_used',
-        property_detail: {
-          enum_detail: {
-            default: 'NOT_USE_GROUP',
-            enumeration: [
-              {
-                description: '不使用组合',
-                value: 'NOT_USE_GROUP',
-              },
-              {
-                description: '视频封面图组合',
-                value: 'VIDEO_IMAGE_GROUP',
-              },
-            ],
-          },
-        },
-        required: false,
-      },
-      {
-        description: '转化数据类型',
-        field_type: 'FIELD_TYPE_ENUM',
-        name: 'conversion_data_type',
-        property_detail: {
-          enum_detail: {
-            enumeration: [
-              {
-                category: 'VIEW_DETAILS',
-                description: '转化数据量',
-                value: 'CONVERSION_DATA_ADMETRIC',
-              },
-              {
-                category: 'VIEW_DETAILS',
-                description: '好友关注量',
-                value: 'CONVERSION_DATA_FRIEND_FOLLOW',
-              },
-              {
-                category: 'MORE_INFO',
-                description: '转化数据量',
-                value: 'CONVERSION_DATA_ADMETRIC',
-              },
-              {
-                category: 'MORE_INFO',
-                description: '好友关注量',
-                value: 'CONVERSION_DATA_FRIEND_FOLLOW',
-              },
-              {
-                category: 'BUY_NOW',
-                description: '转化数据量',
-                value: 'CONVERSION_DATA_ADMETRIC',
-              },
-              {
-                category: 'BUY_NOW',
-                description: '好友关注量',
-                value: 'CONVERSION_DATA_FRIEND_FOLLOW',
-              },
-              {
-                category: 'RESERVE_NOW',
-                description: '转化数据量',
-                value: 'CONVERSION_DATA_ADMETRIC',
-              },
-              {
-                category: 'RESERVE_NOW',
-                description: '好友关注量',
-                value: 'CONVERSION_DATA_FRIEND_FOLLOW',
-              },
-              {
-                category: 'CONSULT_NOW',
-                description: '转化数据量',
-                value: 'CONVERSION_DATA_ADMETRIC',
-              },
-              {
-                category: 'CONSULT_NOW',
-                description: '好友关注量',
-                value: 'CONVERSION_DATA_FRIEND_FOLLOW',
-              },
-              {
-                category: 'APPLY_NOW',
-                description: '转化数据量',
-                value: 'CONVERSION_DATA_ADMETRIC',
-              },
-              {
-                category: 'APPLY_NOW',
-                description: '好友关注量',
-                value: 'CONVERSION_DATA_FRIEND_FOLLOW',
-              },
-              {
-                category: 'BOOK_NOW',
-                description: '转化数据量',
-                value: 'CONVERSION_DATA_ADMETRIC',
-              },
-              {
-                category: 'BOOK_NOW',
-                description: '好友关注量',
-                value: 'CONVERSION_DATA_FRIEND_FOLLOW',
-              },
-              {
-                category: 'GET_COUPONS',
-                description: '转化数据量',
-                value: 'CONVERSION_DATA_ADMETRIC',
-              },
-              {
-                category: 'GET_COUPONS',
-                description: '好友关注量',
-                value: 'CONVERSION_DATA_FRIEND_FOLLOW',
-              },
-              {
-                category: 'GET_IT_NOW',
-                description: '转化数据量',
-                value: 'CONVERSION_DATA_ADMETRIC',
-              },
-              {
-                category: 'GET_IT_NOW',
-                description: '好友关注量',
-                value: 'CONVERSION_DATA_FRIEND_FOLLOW',
-              },
-              {
-                category: 'FOLLOW_OFFICIAL_ACCOUNT',
-                description: '转化数据量',
-                value: 'CONVERSION_DATA_ADMETRIC',
-              },
-              {
-                category: 'FOLLOW_OFFICIAL_ACCOUNT',
-                description: '好友关注量',
-                value: 'CONVERSION_DATA_FRIEND_FOLLOW',
-              },
-              {
-                category: 'READ_NOVELS',
-                description: '转化数据量',
-                value: 'CONVERSION_DATA_ADMETRIC',
-              },
-              {
-                category: 'READ_NOVELS',
-                description: '好友关注量',
-                value: 'CONVERSION_DATA_FRIEND_FOLLOW',
-              },
-              {
-                category: '',
-                description: '转化数据量',
-                value: 'CONVERSION_DATA_ADMETRIC',
-              },
-              {
-                category: '',
-                description: '好友关注量',
-                value: 'CONVERSION_DATA_FRIEND_FOLLOW',
-              },
-            ],
-          },
-        },
-        required: false,
-      },
-      {
-        description: '转化数据量类型',
-        field_type: 'FIELD_TYPE_ENUM',
-        name: 'conversion_target_type',
-        property_detail: {
-          enum_detail: {
-            enumeration: [
-              {
-                category: 'VIEW_DETAILS',
-                description: '领取',
-                value: 'CONVERSION_TARGET_GET',
-              },
-              {
-                category: 'VIEW_DETAILS',
-                description: '预约',
-                value: 'CONVERSION_TARGET_RESERVE',
-              },
-              {
-                category: 'VIEW_DETAILS',
-                description: '购买',
-                value: 'CONVERSION_TARGET_BUY',
-              },
-              {
-                category: 'VIEW_DETAILS',
-                description: '申请',
-                value: 'CONVERSION_TARGET_APPLY',
-              },
-              {
-                category: 'VIEW_DETAILS',
-                description: '咨询',
-                value: 'CONVERSION_TARGET_CONSULT',
-              },
-              {
-                category: 'MORE_INFO',
-                description: '领取',
-                value: 'CONVERSION_TARGET_GET',
-              },
-              {
-                category: 'MORE_INFO',
-                description: '预约',
-                value: 'CONVERSION_TARGET_RESERVE',
-              },
-              {
-                category: 'MORE_INFO',
-                description: '购买',
-                value: 'CONVERSION_TARGET_BUY',
-              },
-              {
-                category: 'MORE_INFO',
-                description: '申请',
-                value: 'CONVERSION_TARGET_APPLY',
-              },
-              {
-                category: 'MORE_INFO',
-                description: '咨询',
-                value: 'CONVERSION_TARGET_CONSULT',
-              },
-              {
-                category: 'BUY_NOW',
-                description: '购买',
-                value: 'CONVERSION_TARGET_BUY',
-              },
-              {
-                category: 'RESERVE_NOW',
-                description: '预约',
-                value: 'CONVERSION_TARGET_RESERVE',
-              },
-              {
-                category: 'CONSULT_NOW',
-                description: '咨询',
-                value: 'CONVERSION_TARGET_CONSULT',
-              },
-              {
-                category: 'APPLY_NOW',
-                description: '申请',
-                value: 'CONVERSION_TARGET_APPLY',
-              },
-              {
-                category: 'BOOK_NOW',
-                description: '预定',
-                value: 'CONVERSION_TARGET_BOOK',
-              },
-              {
-                category: 'GET_COUPONS',
-                description: '领取',
-                value: 'CONVERSION_TARGET_GET',
-              },
-              {
-                category: 'GET_IT_NOW',
-                description: '领取',
-                value: 'CONVERSION_TARGET_GET',
-              },
-              {
-                category: 'FOLLOW_OFFICIAL_ACCOUNT',
-                description: '关注',
-                value: 'CONVERSION_TARGET_FOLLOW',
-              },
-              {
-                category: 'READ_NOVELS',
-                description: '阅读',
-                value: 'CONVERSION_TARGET_READ',
-              },
-              {
-                category: '',
-                description: '领取',
-                value: 'CONVERSION_TARGET_GET',
-              },
-              {
-                category: '',
-                description: '预约',
-                value: 'CONVERSION_TARGET_RESERVE',
-              },
-              {
-                category: '',
-                description: '购买',
-                value: 'CONVERSION_TARGET_BUY',
-              },
-              {
-                category: '',
-                description: '申请',
-                value: 'CONVERSION_TARGET_APPLY',
-              },
-              {
-                category: '',
-                description: '咨询',
-                value: 'CONVERSION_TARGET_CONSULT',
-              },
-            ],
-          },
-        },
-        required: false,
-      },
-    ],
-    adcreative_elements: [
-      {
-        array_property: [],
-        description: '品牌名称',
-        element_type: 'ELEMENT_TYPE_TEXT',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_STRING',
-        name: 'brand_name',
-        parent_name: 'brand',
-        required: true,
-        restriction: {
-          text_restriction: {
-            max_length: 12,
-            min_length: 2,
-            text_pattern: '^[^\\<\\>\\&\'\\"\\/\\x08\\x09\\x0A\\x0D\\\\]+$',
-          },
-        },
-        struct_property: [],
-      },
-      {
-        array_property: [],
-        description: '品牌标识图',
-        element_type: 'ELEMENT_TYPE_IMAGE',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_STRING',
-        name: 'brand_img',
-        parent_name: 'brand',
-        required: true,
-        restriction: {
-          image_restriction: {
-            file_format: ['IMAGE_TYPE_JPG', 'IMAGE_TYPE_PNG'],
-            file_size: 400,
-            height: 512,
-            width: 512,
-          },
-        },
-        struct_property: [],
-      },
-      {
-        array_property: [],
-        description: '品牌形象',
-        element_type: 'ELEMENT_TYPE_STRUCT',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_STRUCT',
-        name: 'brand',
-        parent_name: '',
-        required: false,
-        restriction: [],
-        struct_property: {
-          element_mutual_exclusive: false,
-        },
-      },
-      {
-        array_property: [],
-        description: 'Canvas',
-        element_type: 'ELEMENT_TYPE_CANVAS',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_INTEGER',
-        name: 'canvas',
-        parent_name: '',
-        required: false,
-        restriction: [],
-        struct_property: [],
-      },
-      {
-        array_property: [],
-        description: '文案',
-        element_type: 'ELEMENT_TYPE_TEXT',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_STRING',
-        name: 'description',
-        parent_name: '',
-        required: true,
-        restriction: {
-          text_restriction: {
-            max_length: 30,
-            min_length: 1,
-            text_pattern: '^[^\\<\\>\\&\'\\"\\/\\x08\\x09\\x0A\\x0D\\\\]+$',
-          },
-        },
-        struct_property: [],
-      },
-      {
-        array_property: {
-          max_number: 1,
-          min_number: 1,
-        },
-        description: '图片',
-        element_type: 'ELEMENT_TYPE_IMAGE',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_STRING_ARRAY',
-        name: 'image_list',
-        parent_name: '',
-        required: true,
-        restriction: {
-          image_restriction: {
-            file_format: ['IMAGE_TYPE_JPG', 'IMAGE_TYPE_PNG'],
-            file_size: 300,
-            height: 800,
-            width: 800,
-          },
-        },
-        struct_property: [],
-      },
-      {
-        array_property: [],
-        description: '链接名称类型',
-        element_type: 'ELEMENT_TYPE_ENUM',
-        enum_property: {
-          default: '',
-          enumeration: [
-            {
-              description: '去唯品会',
-              value: 'GO_TO_VIP',
-            },
-            {
-              description: '领取优惠',
-              value: 'GET_COUPONS',
-            },
-            {
-              description: '进入小程序',
-              value: 'ENTER_MINI_PROGRAM',
-            },
-            {
-              description: '进入小游戏',
-              value: 'ENTER_MINI_GAME',
-            },
-            {
-              description: '去拼多多',
-              value: 'GO_TO_PDD',
-            },
-            {
-              description: '去逛逛',
-              value: 'GO_SHOPPING',
-            },
-            {
-              description: '去苏宁',
-              value: 'GO_TO_SUNING',
-            },
-            {
-              description: '去快手',
-              value: 'GO_TO_KUAISHOU',
-            },
-            {
-              description: '查看详情',
-              value: 'VIEW_DETAILS',
-            },
-            {
-              description: '去京东',
-              value: 'GO_TO_JD',
-            },
-            {
-              description: '预约活动',
-              value: 'MAKE_AN_APPOINTMENT',
-            },
-            {
-              description: '立即购买',
-              value: 'BUY_NOW',
-            },
-            {
-              description: '去小红书',
-              value: 'GO_TO_RED',
-            },
-          ],
-        },
-        field_type: 'FIELD_TYPE_STRING',
-        name: 'link_name_type',
-        parent_name: '',
-        required: false,
-        restriction: [],
-        struct_property: [],
-      },
-      {
-        array_property: [],
-        description: '小程序id',
-        element_type: 'ELEMENT_TYPE_REFERENCE',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_INTEGER',
-        name: 'mini_program_id',
-        parent_name: '',
-        required: false,
-        restriction: [],
-        struct_property: [],
-      },
-      {
-        array_property: [],
-        description: '小程序路径',
-        element_type: 'ELEMENT_TYPE_URL',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_STRING',
-        name: 'mini_program_path',
-        parent_name: '',
-        required: false,
-        restriction: {
-          url_restriction: {
-            url_pattern: '.*',
-          },
-        },
-        struct_property: [],
-      },
-    ],
-    adcreative_sample_image:
-      'http://qzonestyle.gtimg.cn/gdt_ui_proj/dist/gdt/imgbox/mp-img-big.svg',
-    adcreative_template_appellation: '常规大图 1:1',
-    adcreative_template_id: 311,
-    xd_show: true,
-    sj_show: true,
-    adcreative_template_style: '图片',
-    landing_page_config: {
-      required: false,
-      support_page_type_list: [
-        {
-          description: '微信原生推广页',
-          example: '',
-          page_type: 'PAGE_TYPE_CANVAS_WECHAT',
-          support_link_name_type: {
-            list: [
-              {
-                description: '查看详情',
-                link_name_type: 'VIEW_DETAILS',
-              },
-              {
-                description: '了解更多',
-                link_name_type: 'MORE_INFO',
-              },
-              {
-                description: '立即购买',
-                link_name_type: 'BUY_NOW',
-              },
-              {
-                description: '立即申请',
-                link_name_type: 'APPLY_NOW',
-              },
-              {
-                description: '立即预定',
-                link_name_type: 'BOOK_NOW',
-              },
-              {
-                description: '立即咨询',
-                link_name_type: 'CONSULT_NOW',
-              },
-              {
-                description: '立即预约',
-                link_name_type: 'RESERVE_NOW',
-              },
-              {
-                description: '立即领取',
-                link_name_type: 'GET_IT_NOW',
-              },
-              {
-                description: '领取优惠',
-                link_name_type: 'GET_COUPONS',
-              },
-              {
-                description: '去逛逛',
-                link_name_type: 'GO_SHOPPING',
-              },
-              {
-                description: '关注公众号',
-                link_name_type: 'FOLLOW_OFFICIAL_ACCOUNT',
-              },
-              {
-                description: '阅读小说',
-                link_name_type: 'READ_NOVELS',
-              },
-            ],
-            required: false,
-          },
-          support_link_page_type: {
-            list: [
-              {
-                description: ' 微信公众号详情页',
-                link_page_type: 'LINK_PAGE_TYPE_WECHAT_OFFICIAL_ACCOUNT_DETAIL',
-              },
-              {
-                description: '微信原生页',
-                link_page_type: 'LINK_PAGE_TYPE_CANVAS_WECHAT',
-              },
-            ],
-            required: false,
-          },
-        },
-      ],
-    },
-    promoted_object_type: 'PROMOTED_OBJECT_TYPE_WECHAT_OFFICIAL_ACCOUNT',
-    site_set: ['SITE_SET_MOMENTS', 'SITE_SET_WECHAT'],
-    support_bid_mode_list: ['BID_MODE_CPM', 'BID_MODE_OCPM'],
-    support_billing_spec_list: [
-      {
-        billing_event: 'BILLINGEVENT_IMPRESSION',
-        max_price: 99900,
-        min_price: 150,
-      },
-    ],
-    support_dynamic_ability_spec_list: {
-      dynamic_ability_type: ['DYNAMIC_TYPE_DYNAMIC_CREATIVE'],
-      product_item_display_quantity: [],
-    },
-    unsupport_bid_mode_list: [
-      {
-        bid_mode_list: ['BID_MODE_CPC', 'BID_MODE_OCPC'],
-        site_set: ['SITE_SET_MOMENTS'],
-      },
-      {
-        bid_mode_list: ['BID_MODE_CPA'],
-        site_set: ['SITE_SET_MOMENTS'],
-      },
-    ],
-    unsupport_billing_spec_list: [
-      {
-        billing_event: 'BILLINGEVENT_CLICK',
-        site_set: ['SITE_SET_MOMENTS'],
-        unsupport_type: 'UNSUPPORT_TYPE_EXPOSURE',
-      },
-      {
-        billing_event: 'BILLINGEVENT_APP_DOWNLOAD',
-        site_set: ['SITE_SET_MOMENTS'],
-        unsupport_type: 'UNSUPPORT_TYPE_EXPOSURE',
-      },
-    ],
-    unsupport_siteset_detail_spec: [
-      {
-        site_set: ['SITE_SET_WECHAT'],
-      },
-    ],
-  },
-  // 641
-  {
-    adcreative_attributes: [
-      {
-        description: '头像及昵称跳转页',
-        field_type: 'FIELD_TYPE_INTEGER',
-        name: 'profile_id',
-        property_detail: {
-          integer_detail: {
-            max: 20,
-            min: 0,
-          },
-        },
-        required: true,
-      },
-      {
-        description: '分享信息',
-        field_type: 'FIELD_TYPE_STRUCT',
-        name: 'share_content_spec',
-        property_detail: {
-          struct_detail: {
-            element_list: [
-              {
-                description: '分享描述',
-                field_type: 'FIELD_TYPE_STRING',
-                name: 'share_desc',
-                property_detail: {
-                  string_detail: {
-                    max_length: 20,
-                    min_length: 1,
-                    text_pattern: '^[^\\<\\>\\&\'\\"\\/\\x08\\x09\\x0A\\x0D\\\\]+$',
-                  },
-                },
-                required: true,
-              },
-              {
-                description: '分享标题',
-                field_type: 'FIELD_TYPE_STRING',
-                name: 'share_title',
-                property_detail: {
-                  string_detail: {
-                    max_length: 14,
-                    min_length: 1,
-                    text_pattern: '^[^\\<\\>\\&\'\\"\\/\\x08\\x09\\x0A\\x0D\\\\]+$',
-                  },
-                },
-                required: true,
-              },
-            ],
-          },
-        },
-        required: false,
-      },
-      {
-        description: '动态创意分组',
-        field_type: 'FIELD_TYPE_ENUM',
-        name: 'dynamic_creative_group_used',
-        property_detail: {
-          enum_detail: {
-            default: 'NOT_USE_GROUP',
-            enumeration: [
-              {
-                description: '不使用组合',
-                value: 'NOT_USE_GROUP',
-              },
-              {
-                description: '视频封面图组合',
-                value: 'VIDEO_IMAGE_GROUP',
-              },
-            ],
-          },
-        },
-        required: false,
-      },
-      {
-        description: '转化数据类型',
-        field_type: 'FIELD_TYPE_ENUM',
-        name: 'conversion_data_type',
-        property_detail: {
-          enum_detail: {
-            enumeration: [
-              {
-                category: 'VIEW_DETAILS',
-                description: '转化数据量',
-                value: 'CONVERSION_DATA_ADMETRIC',
-              },
-              {
-                category: 'VIEW_DETAILS',
-                description: '好友关注量',
-                value: 'CONVERSION_DATA_FRIEND_FOLLOW',
-              },
-              {
-                category: 'MORE_INFO',
-                description: '转化数据量',
-                value: 'CONVERSION_DATA_ADMETRIC',
-              },
-              {
-                category: 'MORE_INFO',
-                description: '好友关注量',
-                value: 'CONVERSION_DATA_FRIEND_FOLLOW',
-              },
-              {
-                category: 'BUY_NOW',
-                description: '转化数据量',
-                value: 'CONVERSION_DATA_ADMETRIC',
-              },
-              {
-                category: 'BUY_NOW',
-                description: '好友关注量',
-                value: 'CONVERSION_DATA_FRIEND_FOLLOW',
-              },
-              {
-                category: 'RESERVE_NOW',
-                description: '转化数据量',
-                value: 'CONVERSION_DATA_ADMETRIC',
-              },
-              {
-                category: 'RESERVE_NOW',
-                description: '好友关注量',
-                value: 'CONVERSION_DATA_FRIEND_FOLLOW',
-              },
-              {
-                category: 'CONSULT_NOW',
-                description: '转化数据量',
-                value: 'CONVERSION_DATA_ADMETRIC',
-              },
-              {
-                category: 'CONSULT_NOW',
-                description: '好友关注量',
-                value: 'CONVERSION_DATA_FRIEND_FOLLOW',
-              },
-              {
-                category: 'APPLY_NOW',
-                description: '转化数据量',
-                value: 'CONVERSION_DATA_ADMETRIC',
-              },
-              {
-                category: 'APPLY_NOW',
-                description: '好友关注量',
-                value: 'CONVERSION_DATA_FRIEND_FOLLOW',
-              },
-              {
-                category: 'BOOK_NOW',
-                description: '转化数据量',
-                value: 'CONVERSION_DATA_ADMETRIC',
-              },
-              {
-                category: 'BOOK_NOW',
-                description: '好友关注量',
-                value: 'CONVERSION_DATA_FRIEND_FOLLOW',
-              },
-              {
-                category: 'GET_COUPONS',
-                description: '转化数据量',
-                value: 'CONVERSION_DATA_ADMETRIC',
-              },
-              {
-                category: 'GET_COUPONS',
-                description: '好友关注量',
-                value: 'CONVERSION_DATA_FRIEND_FOLLOW',
-              },
-              {
-                category: 'GET_IT_NOW',
-                description: '转化数据量',
-                value: 'CONVERSION_DATA_ADMETRIC',
-              },
-              {
-                category: 'GET_IT_NOW',
-                description: '好友关注量',
-                value: 'CONVERSION_DATA_FRIEND_FOLLOW',
-              },
-              {
-                category: 'FOLLOW_OFFICIAL_ACCOUNT',
-                description: '转化数据量',
-                value: 'CONVERSION_DATA_ADMETRIC',
-              },
-              {
-                category: 'FOLLOW_OFFICIAL_ACCOUNT',
-                description: '好友关注量',
-                value: 'CONVERSION_DATA_FRIEND_FOLLOW',
-              },
-              {
-                category: 'READ_NOVELS',
-                description: '转化数据量',
-                value: 'CONVERSION_DATA_ADMETRIC',
-              },
-              {
-                category: 'READ_NOVELS',
-                description: '好友关注量',
-                value: 'CONVERSION_DATA_FRIEND_FOLLOW',
-              },
-              {
-                category: '',
-                description: '转化数据量',
-                value: 'CONVERSION_DATA_ADMETRIC',
-              },
-              {
-                category: '',
-                description: '好友关注量',
-                value: 'CONVERSION_DATA_FRIEND_FOLLOW',
-              },
-            ],
-          },
-        },
-        required: false,
-      },
-      {
-        description: '转化数据量类型',
-        field_type: 'FIELD_TYPE_ENUM',
-        name: 'conversion_target_type',
-        property_detail: {
-          enum_detail: {
-            enumeration: [
-              {
-                category: 'VIEW_DETAILS',
-                description: '领取',
-                value: 'CONVERSION_TARGET_GET',
-              },
-              {
-                category: 'VIEW_DETAILS',
-                description: '预约',
-                value: 'CONVERSION_TARGET_RESERVE',
-              },
-              {
-                category: 'VIEW_DETAILS',
-                description: '购买',
-                value: 'CONVERSION_TARGET_BUY',
-              },
-              {
-                category: 'VIEW_DETAILS',
-                description: '申请',
-                value: 'CONVERSION_TARGET_APPLY',
-              },
-              {
-                category: 'VIEW_DETAILS',
-                description: '咨询',
-                value: 'CONVERSION_TARGET_CONSULT',
-              },
-              {
-                category: 'MORE_INFO',
-                description: '领取',
-                value: 'CONVERSION_TARGET_GET',
-              },
-              {
-                category: 'MORE_INFO',
-                description: '预约',
-                value: 'CONVERSION_TARGET_RESERVE',
-              },
-              {
-                category: 'MORE_INFO',
-                description: '购买',
-                value: 'CONVERSION_TARGET_BUY',
-              },
-              {
-                category: 'MORE_INFO',
-                description: '申请',
-                value: 'CONVERSION_TARGET_APPLY',
-              },
-              {
-                category: 'MORE_INFO',
-                description: '咨询',
-                value: 'CONVERSION_TARGET_CONSULT',
-              },
-              {
-                category: 'BUY_NOW',
-                description: '购买',
-                value: 'CONVERSION_TARGET_BUY',
-              },
-              {
-                category: 'RESERVE_NOW',
-                description: '预约',
-                value: 'CONVERSION_TARGET_RESERVE',
-              },
-              {
-                category: 'CONSULT_NOW',
-                description: '咨询',
-                value: 'CONVERSION_TARGET_CONSULT',
-              },
-              {
-                category: 'APPLY_NOW',
-                description: '申请',
-                value: 'CONVERSION_TARGET_APPLY',
-              },
-              {
-                category: 'BOOK_NOW',
-                description: '预定',
-                value: 'CONVERSION_TARGET_BOOK',
-              },
-              {
-                category: 'GET_COUPONS',
-                description: '领取',
-                value: 'CONVERSION_TARGET_GET',
-              },
-              {
-                category: 'GET_IT_NOW',
-                description: '领取',
-                value: 'CONVERSION_TARGET_GET',
-              },
-              {
-                category: 'FOLLOW_OFFICIAL_ACCOUNT',
-                description: '关注',
-                value: 'CONVERSION_TARGET_FOLLOW',
-              },
-              {
-                category: 'READ_NOVELS',
-                description: '阅读',
-                value: 'CONVERSION_TARGET_READ',
-              },
-              {
-                category: '',
-                description: '领取',
-                value: 'CONVERSION_TARGET_GET',
-              },
-              {
-                category: '',
-                description: '预约',
-                value: 'CONVERSION_TARGET_RESERVE',
-              },
-              {
-                category: '',
-                description: '购买',
-                value: 'CONVERSION_TARGET_BUY',
-              },
-              {
-                category: '',
-                description: '申请',
-                value: 'CONVERSION_TARGET_APPLY',
-              },
-              {
-                category: '',
-                description: '咨询',
-                value: 'CONVERSION_TARGET_CONSULT',
-              },
-            ],
-          },
-        },
-        required: false,
-      },
-    ],
-    adcreative_elements: [
-      {
-        array_property: [],
-        description: '品牌标识图',
-        element_type: 'ELEMENT_TYPE_IMAGE',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_STRING',
-        name: 'brand_img',
-        parent_name: 'brand',
-        required: true,
-        restriction: {
-          image_restriction: {
-            file_format: ['IMAGE_TYPE_JPG', 'IMAGE_TYPE_PNG'],
-            file_size: 400,
-            height: 512,
-            width: 512,
-          },
-        },
-        struct_property: [],
-      },
-      {
-        array_property: [],
-        description: '品牌名称',
-        element_type: 'ELEMENT_TYPE_TEXT',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_STRING',
-        name: 'brand_name',
-        parent_name: 'brand',
-        required: true,
-        restriction: {
-          text_restriction: {
-            max_length: 12,
-            min_length: 2,
-            text_pattern: '^[^\\<\\>\\&\'\\"\\/\\x08\\x09\\x0A\\x0D\\\\]+$',
-          },
-        },
-        struct_property: [],
-      },
-      {
-        array_property: [],
-        description: '品牌形象',
-        element_type: 'ELEMENT_TYPE_STRUCT',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_STRUCT',
-        name: 'brand',
-        parent_name: '',
-        required: false,
-        restriction: [],
-        struct_property: {
-          element_mutual_exclusive: false,
-        },
-      },
-      {
-        array_property: [],
-        description: 'Canvas',
-        element_type: 'ELEMENT_TYPE_CANVAS',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_INTEGER',
-        name: 'canvas',
-        parent_name: '',
-        required: false,
-        restriction: [],
-        struct_property: [],
-      },
-      {
-        array_property: [],
-        description: '文案',
-        element_type: 'ELEMENT_TYPE_TEXT',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_STRING',
-        name: 'description',
-        parent_name: '',
-        required: true,
-        restriction: {
-          text_restriction: {
-            max_length: 30,
-            min_length: 1,
-            text_pattern: '^[^\\<\\>\\&\'\\"\\/\\x08\\x09\\x0A\\x0D\\\\]+$',
-          },
-        },
-        struct_property: [],
-      },
-      {
-        array_property: {
-          max_number: 3,
-          min_number: 3,
-        },
-        description: '图片',
-        element_type: 'ELEMENT_TYPE_IMAGE',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_STRING_ARRAY',
-        name: 'image_list',
-        parent_name: '',
-        required: true,
-        restriction: {
-          image_restriction: {
-            file_format: ['IMAGE_TYPE_JPG', 'IMAGE_TYPE_PNG'],
-            file_size: 300,
-            height: 800,
-            width: 800,
-          },
-        },
-        struct_property: [],
-      },
-      {
-        array_property: [],
-        description: '链接名称类型',
-        element_type: 'ELEMENT_TYPE_ENUM',
-        enum_property: {
-          default: '',
-          enumeration: [
-            {
-              description: '去苏宁',
-              value: 'GO_TO_SUNING',
-            },
-            {
-              description: '领取优惠',
-              value: 'GET_COUPONS',
-            },
-            {
-              description: '立即购买',
-              value: 'BUY_NOW',
-            },
-            {
-              description: '去唯品会',
-              value: 'GO_TO_VIP',
-            },
-            {
-              description: '查看详情',
-              value: 'VIEW_DETAILS',
-            },
-            {
-              description: '去快手',
-              value: 'GO_TO_KUAISHOU',
-            },
-            {
-              description: '预约活动',
-              value: 'MAKE_AN_APPOINTMENT',
-            },
-            {
-              description: '进入小游戏',
-              value: 'ENTER_MINI_GAME',
-            },
-            {
-              description: '去拼多多',
-              value: 'GO_TO_PDD',
-            },
-            {
-              description: '去小红书',
-              value: 'GO_TO_RED',
-            },
-            {
-              description: '去逛逛',
-              value: 'GO_SHOPPING',
-            },
-            {
-              description: '去京东',
-              value: 'GO_TO_JD',
-            },
-            {
-              description: '进入小程序',
-              value: 'ENTER_MINI_PROGRAM',
-            },
-          ],
-        },
-        field_type: 'FIELD_TYPE_STRING',
-        name: 'link_name_type',
-        parent_name: '',
-        required: false,
-        restriction: [],
-        struct_property: [],
-      },
-      {
-        array_property: [],
-        description: '小程序id',
-        element_type: 'ELEMENT_TYPE_REFERENCE',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_INTEGER',
-        name: 'mini_program_id',
-        parent_name: '',
-        required: false,
-        restriction: [],
-        struct_property: [],
-      },
-      {
-        array_property: [],
-        description: '小程序路径',
-        element_type: 'ELEMENT_TYPE_URL',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_STRING',
-        name: 'mini_program_path',
-        parent_name: '',
-        required: false,
-        restriction: {
-          url_restriction: {
-            url_pattern: '.*',
-          },
-        },
-        struct_property: [],
-      },
-    ],
-    adcreative_sample_image:
-      'http://qzonestyle.gtimg.cn/gdt_ui_proj/dist/gdt/imgbox/mp-img-multimg.svg',
-    adcreative_template_appellation: '常规多图 1:1 三图',
-    adcreative_template_id: 641,
-    xd_show: true,
-    sj_show: true,
-    adcreative_template_style: '图片',
-    landing_page_config: {
-      required: false,
-      support_page_type_list: [
-        {
-          description: '微信原生推广页',
-          example: '',
-          page_type: 'PAGE_TYPE_CANVAS_WECHAT',
-          support_link_name_type: {
-            list: [
-              {
-                description: '查看详情',
-                link_name_type: 'VIEW_DETAILS',
-              },
-              {
-                description: '了解更多',
-                link_name_type: 'MORE_INFO',
-              },
-              {
-                description: '立即购买',
-                link_name_type: 'BUY_NOW',
-              },
-              {
-                description: '立即申请',
-                link_name_type: 'APPLY_NOW',
-              },
-              {
-                description: '立即预定',
-                link_name_type: 'BOOK_NOW',
-              },
-              {
-                description: '立即咨询',
-                link_name_type: 'CONSULT_NOW',
-              },
-              {
-                description: '立即预约',
-                link_name_type: 'RESERVE_NOW',
-              },
-              {
-                description: '立即领取',
-                link_name_type: 'GET_IT_NOW',
-              },
-              {
-                description: '领取优惠',
-                link_name_type: 'GET_COUPONS',
-              },
-              {
-                description: '去逛逛',
-                link_name_type: 'GO_SHOPPING',
-              },
-              {
-                description: '关注公众号',
-                link_name_type: 'FOLLOW_OFFICIAL_ACCOUNT',
-              },
-              {
-                description: '阅读小说',
-                link_name_type: 'READ_NOVELS',
-              },
-            ],
-            required: false,
-          },
-          support_link_page_type: {
-            list: [
-              {
-                description: ' 微信公众号详情页',
-                link_page_type: 'LINK_PAGE_TYPE_WECHAT_OFFICIAL_ACCOUNT_DETAIL',
-              },
-              {
-                description: '微信原生页',
-                link_page_type: 'LINK_PAGE_TYPE_CANVAS_WECHAT',
-              },
-            ],
-            required: false,
-          },
-        },
-      ],
-    },
-    promoted_object_type: 'PROMOTED_OBJECT_TYPE_WECHAT_OFFICIAL_ACCOUNT',
-    site_set: ['SITE_SET_MOMENTS', 'SITE_SET_WECHAT'],
-    support_bid_mode_list: ['BID_MODE_CPM', 'BID_MODE_OCPM'],
-    support_billing_spec_list: [
-      {
-        billing_event: 'BILLINGEVENT_IMPRESSION',
-        max_price: 99900,
-        min_price: 150,
-      },
-    ],
-    support_dynamic_ability_spec_list: {
-      dynamic_ability_type: ['DYNAMIC_TYPE_DYNAMIC_CREATIVE'],
-      product_item_display_quantity: [],
-    },
-    unsupport_bid_mode_list: [
-      {
-        bid_mode_list: ['BID_MODE_CPC', 'BID_MODE_OCPC'],
-        site_set: ['SITE_SET_MOMENTS'],
-      },
-      {
-        bid_mode_list: ['BID_MODE_CPA'],
-        site_set: ['SITE_SET_MOMENTS'],
-      },
-    ],
-    unsupport_billing_spec_list: [
-      {
-        billing_event: 'BILLINGEVENT_CLICK',
-        site_set: ['SITE_SET_MOMENTS'],
-        unsupport_type: 'UNSUPPORT_TYPE_EXPOSURE',
-      },
-      {
-        billing_event: 'BILLINGEVENT_APP_DOWNLOAD',
-        site_set: ['SITE_SET_MOMENTS'],
-        unsupport_type: 'UNSUPPORT_TYPE_EXPOSURE',
-      },
-    ],
-    unsupport_siteset_detail_spec: [
-      {
-        site_set: ['SITE_SET_WECHAT'],
-      },
-    ],
-  },
-  //642
-  {
-    adcreative_attributes: [
-      {
-        description: '头像及昵称跳转页',
-        field_type: 'FIELD_TYPE_INTEGER',
-        name: 'profile_id',
-        property_detail: {
-          integer_detail: {
-            max: 20,
-            min: 0,
-          },
-        },
-        required: true,
-      },
-      {
-        description: '分享信息',
-        field_type: 'FIELD_TYPE_STRUCT',
-        name: 'share_content_spec',
-        property_detail: {
-          struct_detail: {
-            element_list: [
-              {
-                description: '分享描述',
-                field_type: 'FIELD_TYPE_STRING',
-                name: 'share_desc',
-                property_detail: {
-                  string_detail: {
-                    max_length: 20,
-                    min_length: 1,
-                    text_pattern: '^[^\\<\\>\\&\'\\"\\/\\x08\\x09\\x0A\\x0D\\\\]+$',
-                  },
-                },
-                required: true,
-              },
-              {
-                description: '分享标题',
-                field_type: 'FIELD_TYPE_STRING',
-                name: 'share_title',
-                property_detail: {
-                  string_detail: {
-                    max_length: 14,
-                    min_length: 1,
-                    text_pattern: '^[^\\<\\>\\&\'\\"\\/\\x08\\x09\\x0A\\x0D\\\\]+$',
-                  },
-                },
-                required: true,
-              },
-            ],
-          },
-        },
-        required: false,
-      },
-      {
-        description: '动态创意分组',
-        field_type: 'FIELD_TYPE_ENUM',
-        name: 'dynamic_creative_group_used',
-        property_detail: {
-          enum_detail: {
-            default: 'NOT_USE_GROUP',
-            enumeration: [
-              {
-                description: '不使用组合',
-                value: 'NOT_USE_GROUP',
-              },
-              {
-                description: '视频封面图组合',
-                value: 'VIDEO_IMAGE_GROUP',
-              },
-            ],
-          },
-        },
-        required: false,
-      },
-      {
-        description: '转化数据类型',
-        field_type: 'FIELD_TYPE_ENUM',
-        name: 'conversion_data_type',
-        property_detail: {
-          enum_detail: {
-            enumeration: [
-              {
-                category: 'VIEW_DETAILS',
-                description: '转化数据量',
-                value: 'CONVERSION_DATA_ADMETRIC',
-              },
-              {
-                category: 'VIEW_DETAILS',
-                description: '好友关注量',
-                value: 'CONVERSION_DATA_FRIEND_FOLLOW',
-              },
-              {
-                category: 'MORE_INFO',
-                description: '转化数据量',
-                value: 'CONVERSION_DATA_ADMETRIC',
-              },
-              {
-                category: 'MORE_INFO',
-                description: '好友关注量',
-                value: 'CONVERSION_DATA_FRIEND_FOLLOW',
-              },
-              {
-                category: 'BUY_NOW',
-                description: '转化数据量',
-                value: 'CONVERSION_DATA_ADMETRIC',
-              },
-              {
-                category: 'BUY_NOW',
-                description: '好友关注量',
-                value: 'CONVERSION_DATA_FRIEND_FOLLOW',
-              },
-              {
-                category: 'RESERVE_NOW',
-                description: '转化数据量',
-                value: 'CONVERSION_DATA_ADMETRIC',
-              },
-              {
-                category: 'RESERVE_NOW',
-                description: '好友关注量',
-                value: 'CONVERSION_DATA_FRIEND_FOLLOW',
-              },
-              {
-                category: 'CONSULT_NOW',
-                description: '转化数据量',
-                value: 'CONVERSION_DATA_ADMETRIC',
-              },
-              {
-                category: 'CONSULT_NOW',
-                description: '好友关注量',
-                value: 'CONVERSION_DATA_FRIEND_FOLLOW',
-              },
-              {
-                category: 'APPLY_NOW',
-                description: '转化数据量',
-                value: 'CONVERSION_DATA_ADMETRIC',
-              },
-              {
-                category: 'APPLY_NOW',
-                description: '好友关注量',
-                value: 'CONVERSION_DATA_FRIEND_FOLLOW',
-              },
-              {
-                category: 'BOOK_NOW',
-                description: '转化数据量',
-                value: 'CONVERSION_DATA_ADMETRIC',
-              },
-              {
-                category: 'BOOK_NOW',
-                description: '好友关注量',
-                value: 'CONVERSION_DATA_FRIEND_FOLLOW',
-              },
-              {
-                category: 'GET_COUPONS',
-                description: '转化数据量',
-                value: 'CONVERSION_DATA_ADMETRIC',
-              },
-              {
-                category: 'GET_COUPONS',
-                description: '好友关注量',
-                value: 'CONVERSION_DATA_FRIEND_FOLLOW',
-              },
-              {
-                category: 'GET_IT_NOW',
-                description: '转化数据量',
-                value: 'CONVERSION_DATA_ADMETRIC',
-              },
-              {
-                category: 'GET_IT_NOW',
-                description: '好友关注量',
-                value: 'CONVERSION_DATA_FRIEND_FOLLOW',
-              },
-              {
-                category: 'FOLLOW_OFFICIAL_ACCOUNT',
-                description: '转化数据量',
-                value: 'CONVERSION_DATA_ADMETRIC',
-              },
-              {
-                category: 'FOLLOW_OFFICIAL_ACCOUNT',
-                description: '好友关注量',
-                value: 'CONVERSION_DATA_FRIEND_FOLLOW',
-              },
-              {
-                category: 'READ_NOVELS',
-                description: '转化数据量',
-                value: 'CONVERSION_DATA_ADMETRIC',
-              },
-              {
-                category: 'READ_NOVELS',
-                description: '好友关注量',
-                value: 'CONVERSION_DATA_FRIEND_FOLLOW',
-              },
-              {
-                category: '',
-                description: '转化数据量',
-                value: 'CONVERSION_DATA_ADMETRIC',
-              },
-              {
-                category: '',
-                description: '好友关注量',
-                value: 'CONVERSION_DATA_FRIEND_FOLLOW',
-              },
-            ],
-          },
-        },
-        required: false,
-      },
-      {
-        description: '转化数据量类型',
-        field_type: 'FIELD_TYPE_ENUM',
-        name: 'conversion_target_type',
-        property_detail: {
-          enum_detail: {
-            enumeration: [
-              {
-                category: 'VIEW_DETAILS',
-                description: '领取',
-                value: 'CONVERSION_TARGET_GET',
-              },
-              {
-                category: 'VIEW_DETAILS',
-                description: '预约',
-                value: 'CONVERSION_TARGET_RESERVE',
-              },
-              {
-                category: 'VIEW_DETAILS',
-                description: '购买',
-                value: 'CONVERSION_TARGET_BUY',
-              },
-              {
-                category: 'VIEW_DETAILS',
-                description: '申请',
-                value: 'CONVERSION_TARGET_APPLY',
-              },
-              {
-                category: 'VIEW_DETAILS',
-                description: '咨询',
-                value: 'CONVERSION_TARGET_CONSULT',
-              },
-              {
-                category: 'MORE_INFO',
-                description: '领取',
-                value: 'CONVERSION_TARGET_GET',
-              },
-              {
-                category: 'MORE_INFO',
-                description: '预约',
-                value: 'CONVERSION_TARGET_RESERVE',
-              },
-              {
-                category: 'MORE_INFO',
-                description: '购买',
-                value: 'CONVERSION_TARGET_BUY',
-              },
-              {
-                category: 'MORE_INFO',
-                description: '申请',
-                value: 'CONVERSION_TARGET_APPLY',
-              },
-              {
-                category: 'MORE_INFO',
-                description: '咨询',
-                value: 'CONVERSION_TARGET_CONSULT',
-              },
-              {
-                category: 'BUY_NOW',
-                description: '购买',
-                value: 'CONVERSION_TARGET_BUY',
-              },
-              {
-                category: 'RESERVE_NOW',
-                description: '预约',
-                value: 'CONVERSION_TARGET_RESERVE',
-              },
-              {
-                category: 'CONSULT_NOW',
-                description: '咨询',
-                value: 'CONVERSION_TARGET_CONSULT',
-              },
-              {
-                category: 'APPLY_NOW',
-                description: '申请',
-                value: 'CONVERSION_TARGET_APPLY',
-              },
-              {
-                category: 'BOOK_NOW',
-                description: '预定',
-                value: 'CONVERSION_TARGET_BOOK',
-              },
-              {
-                category: 'GET_COUPONS',
-                description: '领取',
-                value: 'CONVERSION_TARGET_GET',
-              },
-              {
-                category: 'GET_IT_NOW',
-                description: '领取',
-                value: 'CONVERSION_TARGET_GET',
-              },
-              {
-                category: 'FOLLOW_OFFICIAL_ACCOUNT',
-                description: '关注',
-                value: 'CONVERSION_TARGET_FOLLOW',
-              },
-              {
-                category: 'READ_NOVELS',
-                description: '阅读',
-                value: 'CONVERSION_TARGET_READ',
-              },
-              {
-                category: '',
-                description: '领取',
-                value: 'CONVERSION_TARGET_GET',
-              },
-              {
-                category: '',
-                description: '预约',
-                value: 'CONVERSION_TARGET_RESERVE',
-              },
-              {
-                category: '',
-                description: '购买',
-                value: 'CONVERSION_TARGET_BUY',
-              },
-              {
-                category: '',
-                description: '申请',
-                value: 'CONVERSION_TARGET_APPLY',
-              },
-              {
-                category: '',
-                description: '咨询',
-                value: 'CONVERSION_TARGET_CONSULT',
-              },
-            ],
-          },
-        },
-        required: false,
-      },
-    ],
-    adcreative_elements: [
-      {
-        array_property: [],
-        description: '品牌名称',
-        element_type: 'ELEMENT_TYPE_TEXT',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_STRING',
-        name: 'brand_name',
-        parent_name: 'brand',
-        required: true,
-        restriction: {
-          text_restriction: {
-            max_length: 12,
-            min_length: 2,
-            text_pattern: '^[^\\<\\>\\&\'\\"\\/\\x08\\x09\\x0A\\x0D\\\\]+$',
-          },
-        },
-        struct_property: [],
-      },
-      {
-        array_property: [],
-        description: '品牌标识图',
-        element_type: 'ELEMENT_TYPE_IMAGE',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_STRING',
-        name: 'brand_img',
-        parent_name: 'brand',
-        required: true,
-        restriction: {
-          image_restriction: {
-            file_format: ['IMAGE_TYPE_JPG', 'IMAGE_TYPE_PNG'],
-            file_size: 400,
-            height: 512,
-            width: 512,
-          },
-        },
-        struct_property: [],
-      },
-      {
-        array_property: [],
-        description: '品牌形象',
-        element_type: 'ELEMENT_TYPE_STRUCT',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_STRUCT',
-        name: 'brand',
-        parent_name: '',
-        required: false,
-        restriction: [],
-        struct_property: {
-          element_mutual_exclusive: false,
-        },
-      },
-      {
-        array_property: [],
-        description: 'Canvas',
-        element_type: 'ELEMENT_TYPE_CANVAS',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_INTEGER',
-        name: 'canvas',
-        parent_name: '',
-        required: false,
-        restriction: [],
-        struct_property: [],
-      },
-      {
-        array_property: [],
-        description: '文案',
-        element_type: 'ELEMENT_TYPE_TEXT',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_STRING',
-        name: 'description',
-        parent_name: '',
-        required: true,
-        restriction: {
-          text_restriction: {
-            max_length: 30,
-            min_length: 1,
-            text_pattern: '^[^\\<\\>\\&\'\\"\\/\\x08\\x09\\x0A\\x0D\\\\]+$',
-          },
-        },
-        struct_property: [],
-      },
-      {
-        array_property: {
-          max_number: 4,
-          min_number: 4,
-        },
-        description: '图片',
-        element_type: 'ELEMENT_TYPE_IMAGE',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_STRING_ARRAY',
-        name: 'image_list',
-        parent_name: '',
-        required: true,
-        restriction: {
-          image_restriction: {
-            file_format: ['IMAGE_TYPE_JPG', 'IMAGE_TYPE_PNG'],
-            file_size: 300,
-            height: 800,
-            width: 800,
-          },
-        },
-        struct_property: [],
-      },
-      {
-        array_property: [],
-        description: '链接名称类型',
-        element_type: 'ELEMENT_TYPE_ENUM',
-        enum_property: {
-          default: '',
-          enumeration: [
-            {
-              description: '去京东',
-              value: 'GO_TO_JD',
-            },
-            {
-              description: '预约活动',
-              value: 'MAKE_AN_APPOINTMENT',
-            },
-            {
-              description: '去逛逛',
-              value: 'GO_SHOPPING',
-            },
-            {
-              description: '进入小程序',
-              value: 'ENTER_MINI_PROGRAM',
-            },
-            {
-              description: '进入小游戏',
-              value: 'ENTER_MINI_GAME',
-            },
-            {
-              description: '去小红书',
-              value: 'GO_TO_RED',
-            },
-            {
-              description: '去唯品会',
-              value: 'GO_TO_VIP',
-            },
-            {
-              description: '查看详情',
-              value: 'VIEW_DETAILS',
-            },
-            {
-              description: '去快手',
-              value: 'GO_TO_KUAISHOU',
-            },
-            {
-              description: '领取优惠',
-              value: 'GET_COUPONS',
-            },
-            {
-              description: '去苏宁',
-              value: 'GO_TO_SUNING',
-            },
-            {
-              description: '去拼多多',
-              value: 'GO_TO_PDD',
-            },
-            {
-              description: '立即购买',
-              value: 'BUY_NOW',
-            },
-          ],
-        },
-        field_type: 'FIELD_TYPE_STRING',
-        name: 'link_name_type',
-        parent_name: '',
-        required: false,
-        restriction: [],
-        struct_property: [],
-      },
-      {
-        array_property: [],
-        description: '小程序id',
-        element_type: 'ELEMENT_TYPE_REFERENCE',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_INTEGER',
-        name: 'mini_program_id',
-        parent_name: '',
-        required: false,
-        restriction: [],
-        struct_property: [],
-      },
-      {
-        array_property: [],
-        description: '小程序路径',
-        element_type: 'ELEMENT_TYPE_URL',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_STRING',
-        name: 'mini_program_path',
-        parent_name: '',
-        required: false,
-        restriction: {
-          url_restriction: {
-            url_pattern: '.*',
-          },
-        },
-        struct_property: [],
-      },
-    ],
-    adcreative_sample_image:
-      'http://qzonestyle.gtimg.cn/gdt_ui_proj/dist/gdt/imgbox/mp-img-multimg.svg',
-    adcreative_template_appellation: '常规多图 1:1 四图',
-    adcreative_template_id: 642,
-    xd_show: true,
-    sj_show: true,
-    adcreative_template_style: '图片',
-    landing_page_config: {
-      required: false,
-      support_page_type_list: [
-        {
-          description: '微信原生推广页',
-          example: '',
-          page_type: 'PAGE_TYPE_CANVAS_WECHAT',
-          support_link_name_type: {
-            list: [
-              {
-                description: '查看详情',
-                link_name_type: 'VIEW_DETAILS',
-              },
-              {
-                description: '了解更多',
-                link_name_type: 'MORE_INFO',
-              },
-              {
-                description: '立即购买',
-                link_name_type: 'BUY_NOW',
-              },
-              {
-                description: '立即申请',
-                link_name_type: 'APPLY_NOW',
-              },
-              {
-                description: '立即预定',
-                link_name_type: 'BOOK_NOW',
-              },
-              {
-                description: '立即咨询',
-                link_name_type: 'CONSULT_NOW',
-              },
-              {
-                description: '立即预约',
-                link_name_type: 'RESERVE_NOW',
-              },
-              {
-                description: '立即领取',
-                link_name_type: 'GET_IT_NOW',
-              },
-              {
-                description: '领取优惠',
-                link_name_type: 'GET_COUPONS',
-              },
-              {
-                description: '去逛逛',
-                link_name_type: 'GO_SHOPPING',
-              },
-              {
-                description: '关注公众号',
-                link_name_type: 'FOLLOW_OFFICIAL_ACCOUNT',
-              },
-              {
-                description: '阅读小说',
-                link_name_type: 'READ_NOVELS',
-              },
-            ],
-            required: false,
-          },
-          support_link_page_type: {
-            list: [
-              {
-                description: ' 微信公众号详情页',
-                link_page_type: 'LINK_PAGE_TYPE_WECHAT_OFFICIAL_ACCOUNT_DETAIL',
-              },
-              {
-                description: '微信原生页',
-                link_page_type: 'LINK_PAGE_TYPE_CANVAS_WECHAT',
-              },
-            ],
-            required: false,
-          },
-        },
-      ],
-    },
-    promoted_object_type: 'PROMOTED_OBJECT_TYPE_WECHAT_OFFICIAL_ACCOUNT',
-    site_set: ['SITE_SET_MOMENTS', 'SITE_SET_WECHAT'],
-    support_bid_mode_list: ['BID_MODE_CPM', 'BID_MODE_OCPM'],
-    support_billing_spec_list: [
-      {
-        billing_event: 'BILLINGEVENT_IMPRESSION',
-        max_price: 99900,
-        min_price: 150,
-      },
-    ],
-    support_dynamic_ability_spec_list: {
-      dynamic_ability_type: ['DYNAMIC_TYPE_DYNAMIC_CREATIVE'],
-      product_item_display_quantity: [],
-    },
-    unsupport_bid_mode_list: [
-      {
-        bid_mode_list: ['BID_MODE_CPA'],
-        site_set: ['SITE_SET_MOMENTS'],
-      },
-      {
-        bid_mode_list: ['BID_MODE_CPC', 'BID_MODE_OCPC'],
-        site_set: ['SITE_SET_MOMENTS'],
-      },
-    ],
-    unsupport_billing_spec_list: [
-      {
-        billing_event: 'BILLINGEVENT_APP_DOWNLOAD',
-        site_set: ['SITE_SET_MOMENTS'],
-        unsupport_type: 'UNSUPPORT_TYPE_EXPOSURE',
-      },
-      {
-        billing_event: 'BILLINGEVENT_CLICK',
-        site_set: ['SITE_SET_MOMENTS'],
-        unsupport_type: 'UNSUPPORT_TYPE_EXPOSURE',
-      },
-    ],
-    unsupport_siteset_detail_spec: [
-      {
-        site_set: ['SITE_SET_WECHAT'],
-      },
-    ],
-  },
-  //643
-  {
-    adcreative_attributes: [
-      {
-        description: '头像及昵称跳转页',
-        field_type: 'FIELD_TYPE_INTEGER',
-        name: 'profile_id',
-        property_detail: {
-          integer_detail: {
-            max: 20,
-            min: 0,
-          },
-        },
-        required: true,
-      },
-      {
-        description: '分享信息',
-        field_type: 'FIELD_TYPE_STRUCT',
-        name: 'share_content_spec',
-        property_detail: {
-          struct_detail: {
-            element_list: [
-              {
-                description: '分享描述',
-                field_type: 'FIELD_TYPE_STRING',
-                name: 'share_desc',
-                property_detail: {
-                  string_detail: {
-                    max_length: 20,
-                    min_length: 1,
-                    text_pattern: '^[^\\<\\>\\&\'\\"\\/\\x08\\x09\\x0A\\x0D\\\\]+$',
-                  },
-                },
-                required: true,
-              },
-              {
-                description: '分享标题',
-                field_type: 'FIELD_TYPE_STRING',
-                name: 'share_title',
-                property_detail: {
-                  string_detail: {
-                    max_length: 14,
-                    min_length: 1,
-                    text_pattern: '^[^\\<\\>\\&\'\\"\\/\\x08\\x09\\x0A\\x0D\\\\]+$',
-                  },
-                },
-                required: true,
-              },
-            ],
-          },
-        },
-        required: false,
-      },
-      {
-        description: '动态创意分组',
-        field_type: 'FIELD_TYPE_ENUM',
-        name: 'dynamic_creative_group_used',
-        property_detail: {
-          enum_detail: {
-            default: 'NOT_USE_GROUP',
-            enumeration: [
-              {
-                description: '不使用组合',
-                value: 'NOT_USE_GROUP',
-              },
-              {
-                description: '视频封面图组合',
-                value: 'VIDEO_IMAGE_GROUP',
-              },
-            ],
-          },
-        },
-        required: false,
-      },
-      {
-        description: '转化数据类型',
-        field_type: 'FIELD_TYPE_ENUM',
-        name: 'conversion_data_type',
-        property_detail: {
-          enum_detail: {
-            enumeration: [
-              {
-                category: 'VIEW_DETAILS',
-                description: '转化数据量',
-                value: 'CONVERSION_DATA_ADMETRIC',
-              },
-              {
-                category: 'VIEW_DETAILS',
-                description: '好友关注量',
-                value: 'CONVERSION_DATA_FRIEND_FOLLOW',
-              },
-              {
-                category: 'MORE_INFO',
-                description: '转化数据量',
-                value: 'CONVERSION_DATA_ADMETRIC',
-              },
-              {
-                category: 'MORE_INFO',
-                description: '好友关注量',
-                value: 'CONVERSION_DATA_FRIEND_FOLLOW',
-              },
-              {
-                category: 'BUY_NOW',
-                description: '转化数据量',
-                value: 'CONVERSION_DATA_ADMETRIC',
-              },
-              {
-                category: 'BUY_NOW',
-                description: '好友关注量',
-                value: 'CONVERSION_DATA_FRIEND_FOLLOW',
-              },
-              {
-                category: 'RESERVE_NOW',
-                description: '转化数据量',
-                value: 'CONVERSION_DATA_ADMETRIC',
-              },
-              {
-                category: 'RESERVE_NOW',
-                description: '好友关注量',
-                value: 'CONVERSION_DATA_FRIEND_FOLLOW',
-              },
-              {
-                category: 'CONSULT_NOW',
-                description: '转化数据量',
-                value: 'CONVERSION_DATA_ADMETRIC',
-              },
-              {
-                category: 'CONSULT_NOW',
-                description: '好友关注量',
-                value: 'CONVERSION_DATA_FRIEND_FOLLOW',
-              },
-              {
-                category: 'APPLY_NOW',
-                description: '转化数据量',
-                value: 'CONVERSION_DATA_ADMETRIC',
-              },
-              {
-                category: 'APPLY_NOW',
-                description: '好友关注量',
-                value: 'CONVERSION_DATA_FRIEND_FOLLOW',
-              },
-              {
-                category: 'BOOK_NOW',
-                description: '转化数据量',
-                value: 'CONVERSION_DATA_ADMETRIC',
-              },
-              {
-                category: 'BOOK_NOW',
-                description: '好友关注量',
-                value: 'CONVERSION_DATA_FRIEND_FOLLOW',
-              },
-              {
-                category: 'GET_COUPONS',
-                description: '转化数据量',
-                value: 'CONVERSION_DATA_ADMETRIC',
-              },
-              {
-                category: 'GET_COUPONS',
-                description: '好友关注量',
-                value: 'CONVERSION_DATA_FRIEND_FOLLOW',
-              },
-              {
-                category: 'GET_IT_NOW',
-                description: '转化数据量',
-                value: 'CONVERSION_DATA_ADMETRIC',
-              },
-              {
-                category: 'GET_IT_NOW',
-                description: '好友关注量',
-                value: 'CONVERSION_DATA_FRIEND_FOLLOW',
-              },
-              {
-                category: 'FOLLOW_OFFICIAL_ACCOUNT',
-                description: '转化数据量',
-                value: 'CONVERSION_DATA_ADMETRIC',
-              },
-              {
-                category: 'FOLLOW_OFFICIAL_ACCOUNT',
-                description: '好友关注量',
-                value: 'CONVERSION_DATA_FRIEND_FOLLOW',
-              },
-              {
-                category: 'READ_NOVELS',
-                description: '转化数据量',
-                value: 'CONVERSION_DATA_ADMETRIC',
-              },
-              {
-                category: 'READ_NOVELS',
-                description: '好友关注量',
-                value: 'CONVERSION_DATA_FRIEND_FOLLOW',
-              },
-              {
-                category: '',
-                description: '转化数据量',
-                value: 'CONVERSION_DATA_ADMETRIC',
-              },
-              {
-                category: '',
-                description: '好友关注量',
-                value: 'CONVERSION_DATA_FRIEND_FOLLOW',
-              },
-            ],
-          },
-        },
-        required: false,
-      },
-      {
-        description: '转化数据量类型',
-        field_type: 'FIELD_TYPE_ENUM',
-        name: 'conversion_target_type',
-        property_detail: {
-          enum_detail: {
-            enumeration: [
-              {
-                category: 'VIEW_DETAILS',
-                description: '领取',
-                value: 'CONVERSION_TARGET_GET',
-              },
-              {
-                category: 'VIEW_DETAILS',
-                description: '预约',
-                value: 'CONVERSION_TARGET_RESERVE',
-              },
-              {
-                category: 'VIEW_DETAILS',
-                description: '购买',
-                value: 'CONVERSION_TARGET_BUY',
-              },
-              {
-                category: 'VIEW_DETAILS',
-                description: '申请',
-                value: 'CONVERSION_TARGET_APPLY',
-              },
-              {
-                category: 'VIEW_DETAILS',
-                description: '咨询',
-                value: 'CONVERSION_TARGET_CONSULT',
-              },
-              {
-                category: 'MORE_INFO',
-                description: '领取',
-                value: 'CONVERSION_TARGET_GET',
-              },
-              {
-                category: 'MORE_INFO',
-                description: '预约',
-                value: 'CONVERSION_TARGET_RESERVE',
-              },
-              {
-                category: 'MORE_INFO',
-                description: '购买',
-                value: 'CONVERSION_TARGET_BUY',
-              },
-              {
-                category: 'MORE_INFO',
-                description: '申请',
-                value: 'CONVERSION_TARGET_APPLY',
-              },
-              {
-                category: 'MORE_INFO',
-                description: '咨询',
-                value: 'CONVERSION_TARGET_CONSULT',
-              },
-              {
-                category: 'BUY_NOW',
-                description: '购买',
-                value: 'CONVERSION_TARGET_BUY',
-              },
-              {
-                category: 'RESERVE_NOW',
-                description: '预约',
-                value: 'CONVERSION_TARGET_RESERVE',
-              },
-              {
-                category: 'CONSULT_NOW',
-                description: '咨询',
-                value: 'CONVERSION_TARGET_CONSULT',
-              },
-              {
-                category: 'APPLY_NOW',
-                description: '申请',
-                value: 'CONVERSION_TARGET_APPLY',
-              },
-              {
-                category: 'BOOK_NOW',
-                description: '预定',
-                value: 'CONVERSION_TARGET_BOOK',
-              },
-              {
-                category: 'GET_COUPONS',
-                description: '领取',
-                value: 'CONVERSION_TARGET_GET',
-              },
-              {
-                category: 'GET_IT_NOW',
-                description: '领取',
-                value: 'CONVERSION_TARGET_GET',
-              },
-              {
-                category: 'FOLLOW_OFFICIAL_ACCOUNT',
-                description: '关注',
-                value: 'CONVERSION_TARGET_FOLLOW',
-              },
-              {
-                category: 'READ_NOVELS',
-                description: '阅读',
-                value: 'CONVERSION_TARGET_READ',
-              },
-              {
-                category: '',
-                description: '领取',
-                value: 'CONVERSION_TARGET_GET',
-              },
-              {
-                category: '',
-                description: '预约',
-                value: 'CONVERSION_TARGET_RESERVE',
-              },
-              {
-                category: '',
-                description: '购买',
-                value: 'CONVERSION_TARGET_BUY',
-              },
-              {
-                category: '',
-                description: '申请',
-                value: 'CONVERSION_TARGET_APPLY',
-              },
-              {
-                category: '',
-                description: '咨询',
-                value: 'CONVERSION_TARGET_CONSULT',
-              },
-            ],
-          },
-        },
-        required: false,
-      },
-    ],
-    adcreative_elements: [
-      {
-        array_property: [],
-        description: '品牌名称',
-        element_type: 'ELEMENT_TYPE_TEXT',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_STRING',
-        name: 'brand_name',
-        parent_name: 'brand',
-        required: true,
-        restriction: {
-          text_restriction: {
-            max_length: 12,
-            min_length: 2,
-            text_pattern: '^[^\\<\\>\\&\'\\"\\/\\x08\\x09\\x0A\\x0D\\\\]+$',
-          },
-        },
-        struct_property: [],
-      },
-      {
-        array_property: [],
-        description: '品牌标识图',
-        element_type: 'ELEMENT_TYPE_IMAGE',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_STRING',
-        name: 'brand_img',
-        parent_name: 'brand',
-        required: true,
-        restriction: {
-          image_restriction: {
-            file_format: ['IMAGE_TYPE_JPG', 'IMAGE_TYPE_PNG'],
-            file_size: 400,
-            height: 512,
-            width: 512,
-          },
-        },
-        struct_property: [],
-      },
-      {
-        array_property: [],
-        description: '品牌形象',
-        element_type: 'ELEMENT_TYPE_STRUCT',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_STRUCT',
-        name: 'brand',
-        parent_name: '',
-        required: false,
-        restriction: [],
-        struct_property: {
-          element_mutual_exclusive: false,
-        },
-      },
-      {
-        array_property: [],
-        description: 'Canvas',
-        element_type: 'ELEMENT_TYPE_CANVAS',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_INTEGER',
-        name: 'canvas',
-        parent_name: '',
-        required: false,
-        restriction: [],
-        struct_property: [],
-      },
-      {
-        array_property: [],
-        description: '文案',
-        element_type: 'ELEMENT_TYPE_TEXT',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_STRING',
-        name: 'description',
-        parent_name: '',
-        required: true,
-        restriction: {
-          text_restriction: {
-            max_length: 30,
-            min_length: 1,
-            text_pattern: '^[^\\<\\>\\&\'\\"\\/\\x08\\x09\\x0A\\x0D\\\\]+$',
-          },
-        },
-        struct_property: [],
-      },
-      {
-        array_property: {
-          max_number: 6,
-          min_number: 6,
-        },
-        description: '图片',
-        element_type: 'ELEMENT_TYPE_IMAGE',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_STRING_ARRAY',
-        name: 'image_list',
-        parent_name: '',
-        required: true,
-        restriction: {
-          image_restriction: {
-            file_format: ['IMAGE_TYPE_JPG', 'IMAGE_TYPE_PNG'],
-            file_size: 300,
-            height: 800,
-            width: 800,
-          },
-        },
-        struct_property: [],
-      },
-      {
-        array_property: [],
-        description: '链接名称类型',
-        element_type: 'ELEMENT_TYPE_ENUM',
-        enum_property: {
-          default: '',
-          enumeration: [
-            {
-              description: '预约活动',
-              value: 'MAKE_AN_APPOINTMENT',
-            },
-            {
-              description: '去小红书',
-              value: 'GO_TO_RED',
-            },
-            {
-              description: '去快手',
-              value: 'GO_TO_KUAISHOU',
-            },
-            {
-              description: '进入小程序',
-              value: 'ENTER_MINI_PROGRAM',
-            },
-            {
-              description: '领取优惠',
-              value: 'GET_COUPONS',
-            },
-            {
-              description: '立即购买',
-              value: 'BUY_NOW',
-            },
-            {
-              description: '去拼多多',
-              value: 'GO_TO_PDD',
-            },
-            {
-              description: '去苏宁',
-              value: 'GO_TO_SUNING',
-            },
-            {
-              description: '去逛逛',
-              value: 'GO_SHOPPING',
-            },
-            {
-              description: '去京东',
-              value: 'GO_TO_JD',
-            },
-            {
-              description: '去唯品会',
-              value: 'GO_TO_VIP',
-            },
-            {
-              description: '查看详情',
-              value: 'VIEW_DETAILS',
-            },
-            {
-              description: '进入小游戏',
-              value: 'ENTER_MINI_GAME',
-            },
-          ],
-        },
-        field_type: 'FIELD_TYPE_STRING',
-        name: 'link_name_type',
-        parent_name: '',
-        required: false,
-        restriction: [],
-        struct_property: [],
-      },
-      {
-        array_property: [],
-        description: '小程序id',
-        element_type: 'ELEMENT_TYPE_REFERENCE',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_INTEGER',
-        name: 'mini_program_id',
-        parent_name: '',
-        required: false,
-        restriction: [],
-        struct_property: [],
-      },
-      {
-        array_property: [],
-        description: '小程序路径',
-        element_type: 'ELEMENT_TYPE_URL',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_STRING',
-        name: 'mini_program_path',
-        parent_name: '',
-        required: false,
-        restriction: {
-          url_restriction: {
-            url_pattern: '.*',
-          },
-        },
-        struct_property: [],
-      },
-    ],
-    adcreative_sample_image:
-      'http://qzonestyle.gtimg.cn/gdt_ui_proj/dist/gdt/imgbox/mp-img-multimg.svg',
-    adcreative_template_appellation: '常规多图 1:1 六图',
-    adcreative_template_id: 643,
-    xd_show: true,
-    sj_show: true,
-    adcreative_template_style: '图片',
-    landing_page_config: {
-      required: false,
-      support_page_type_list: [
-        {
-          description: '微信原生推广页',
-          example: '',
-          page_type: 'PAGE_TYPE_CANVAS_WECHAT',
-          support_link_name_type: {
-            list: [
-              {
-                description: '查看详情',
-                link_name_type: 'VIEW_DETAILS',
-              },
-              {
-                description: '了解更多',
-                link_name_type: 'MORE_INFO',
-              },
-              {
-                description: '立即购买',
-                link_name_type: 'BUY_NOW',
-              },
-              {
-                description: '立即预约',
-                link_name_type: 'RESERVE_NOW',
-              },
-              {
-                description: '立即咨询',
-                link_name_type: 'CONSULT_NOW',
-              },
-              {
-                description: '立即申请',
-                link_name_type: 'APPLY_NOW',
-              },
-              {
-                description: '立即预定',
-                link_name_type: 'BOOK_NOW',
-              },
-              {
-                description: '立即领取',
-                link_name_type: 'GET_IT_NOW',
-              },
-              {
-                description: '领取优惠',
-                link_name_type: 'GET_COUPONS',
-              },
-              {
-                description: '去逛逛',
-                link_name_type: 'GO_SHOPPING',
-              },
-              {
-                description: '关注公众号',
-                link_name_type: 'FOLLOW_OFFICIAL_ACCOUNT',
-              },
-              {
-                description: '阅读小说',
-                link_name_type: 'READ_NOVELS',
-              },
-            ],
-            required: false,
-          },
-          support_link_page_type: {
-            list: [
-              {
-                description: ' 微信公众号详情页',
-                link_page_type: 'LINK_PAGE_TYPE_WECHAT_OFFICIAL_ACCOUNT_DETAIL',
-              },
-              {
-                description: '微信原生页',
-                link_page_type: 'LINK_PAGE_TYPE_CANVAS_WECHAT',
-              },
-            ],
-            required: false,
-          },
-        },
-      ],
-    },
-    promoted_object_type: 'PROMOTED_OBJECT_TYPE_WECHAT_OFFICIAL_ACCOUNT',
-    site_set: ['SITE_SET_MOMENTS', 'SITE_SET_WECHAT'],
-    support_bid_mode_list: ['BID_MODE_CPM', 'BID_MODE_OCPM'],
-    support_billing_spec_list: [
-      {
-        billing_event: 'BILLINGEVENT_IMPRESSION',
-        max_price: 99900,
-        min_price: 150,
-      },
-    ],
-    support_dynamic_ability_spec_list: {
-      dynamic_ability_type: ['DYNAMIC_TYPE_DYNAMIC_CREATIVE'],
-      product_item_display_quantity: [],
-    },
-    unsupport_bid_mode_list: [
-      {
-        bid_mode_list: ['BID_MODE_CPC', 'BID_MODE_OCPC'],
-        site_set: ['SITE_SET_MOMENTS'],
-      },
-      {
-        bid_mode_list: ['BID_MODE_CPA'],
-        site_set: ['SITE_SET_MOMENTS'],
-      },
-    ],
-    unsupport_billing_spec_list: [
-      {
-        billing_event: 'BILLINGEVENT_CLICK',
-        site_set: ['SITE_SET_MOMENTS'],
-        unsupport_type: 'UNSUPPORT_TYPE_EXPOSURE',
-      },
-      {
-        billing_event: 'BILLINGEVENT_APP_DOWNLOAD',
-        site_set: ['SITE_SET_MOMENTS'],
-        unsupport_type: 'UNSUPPORT_TYPE_EXPOSURE',
-      },
-    ],
-    unsupport_siteset_detail_spec: [
-      {
-        site_set: ['SITE_SET_WECHAT'],
-      },
-    ],
-  },
-  //711
-  {
-    adcreative_attributes: [
-      {
-        description: '分享信息',
-        field_type: 'FIELD_TYPE_STRUCT',
-        name: 'share_content_spec',
-        property_detail: {
-          struct_detail: {
-            element_list: [
-              {
-                description: '分享描述',
-                field_type: 'FIELD_TYPE_STRING',
-                name: 'share_desc',
-                property_detail: {
-                  string_detail: {
-                    max_length: 20,
-                    min_length: 1,
-                    text_pattern: '^[^\\<\\>\\&\'\\"\\/\\x08\\x09\\x0A\\x0D\\\\]+$',
-                  },
-                },
-                required: true,
-              },
-              {
-                description: '分享标题',
-                field_type: 'FIELD_TYPE_STRING',
-                name: 'share_title',
-                property_detail: {
-                  string_detail: {
-                    max_length: 14,
-                    min_length: 1,
-                    text_pattern: '^[^\\<\\>\\&\'\\"\\/\\x08\\x09\\x0A\\x0D\\\\]+$',
-                  },
-                },
-                required: true,
-              },
-            ],
-          },
-        },
-        required: false,
-      },
-      {
-        description: '动态创意分组',
-        field_type: 'FIELD_TYPE_ENUM',
-        name: 'dynamic_creative_group_used',
-        property_detail: {
-          enum_detail: {
-            default: 'NOT_USE_GROUP',
-            enumeration: [
-              {
-                description: '不使用组合',
-                value: 'NOT_USE_GROUP',
-              },
-              {
-                description: '视频封面图组合',
-                value: 'VIDEO_IMAGE_GROUP',
-              },
-            ],
-          },
-        },
-        required: false,
-      },
-      {
-        description: '转化数据类型',
-        field_type: 'FIELD_TYPE_ENUM',
-        name: 'conversion_data_type',
-        property_detail: {
-          enum_detail: {
-            enumeration: [
-              {
-                category: '',
-                description: '转化数据量',
-                value: 'CONVERSION_DATA_ADMETRIC',
-              },
-            ],
-          },
-        },
-        required: false,
-      },
-      {
-        description: '转化数据量类型',
-        field_type: 'FIELD_TYPE_ENUM',
-        name: 'conversion_target_type',
-        property_detail: {
-          enum_detail: {
-            enumeration: [
-              {
-                category: '',
-                description: '关注',
-                value: 'CONVERSION_TARGET_FOLLOW',
-              },
-            ],
-          },
-        },
-        required: false,
-      },
-    ],
-    adcreative_elements: [
-      {
-        array_property: [],
-        description: '品牌名称',
-        element_type: 'ELEMENT_TYPE_TEXT',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_STRING',
-        name: 'brand_name',
-        parent_name: 'brand',
-        required: true,
-        restriction: {
-          text_restriction: {
-            max_length: 12,
-            min_length: 2,
-            text_pattern: '^[^\\<\\>\\&\'\\"\\/\\x08\\x09\\x0A\\x0D\\\\]+$',
-          },
-        },
-        struct_property: [],
-      },
-      {
-        array_property: [],
-        description: '品牌标识图',
-        element_type: 'ELEMENT_TYPE_IMAGE',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_STRING',
-        name: 'brand_img',
-        parent_name: 'brand',
-        required: true,
-        restriction: {
-          image_restriction: {
-            file_format: ['IMAGE_TYPE_JPG', 'IMAGE_TYPE_PNG'],
-            file_size: 400,
-            height: 512,
-            width: 512,
-          },
-        },
-        struct_property: [],
-      },
-      {
-        array_property: [],
-        description: '品牌形象',
-        element_type: 'ELEMENT_TYPE_STRUCT',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_STRUCT',
-        name: 'brand',
-        parent_name: '',
-        required: true,
-        restriction: [],
-        struct_property: {
-          element_mutual_exclusive: false,
-        },
-      },
-      {
-        array_property: [],
-        description: 'Canvas',
-        element_type: 'ELEMENT_TYPE_CANVAS',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_INTEGER',
-        name: 'canvas',
-        parent_name: '',
-        required: false,
-        restriction: [],
-        struct_property: [],
-      },
-      {
-        array_property: [],
-        description: '文案(1-30字)',
-        element_type: 'ELEMENT_TYPE_TEXT',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_STRING',
-        name: 'description',
-        parent_name: '',
-        required: true,
-        restriction: {
-          text_restriction: {
-            max_length: 30,
-            min_length: 1,
-            text_pattern: '^[^\\<\\>\\&\'\\"\\/\\x08\\x09\\x0A\\x0D\\\\]+$',
-          },
-        },
-        struct_property: [],
-      },
-      {
-        array_property: [],
-        description: '图片',
-        element_type: 'ELEMENT_TYPE_IMAGE',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_STRING',
-        name: 'image',
-        parent_name: '',
-        required: true,
-        restriction: {
-          image_restriction: {
-            file_format: ['IMAGE_TYPE_JPG', 'IMAGE_TYPE_PNG'],
-            file_size: 140,
-            height: 720,
-            width: 1280,
-          },
-        },
-        struct_property: [],
-      },
-    ],
-    adcreative_sample_image:
-      'http://qzonestyle.gtimg.cn/gdt_ui_proj/dist/gdt/imgbox/creative_template_711.svg',
-    adcreative_template_appellation: '横版大图 16:9',
-    adcreative_template_id: 711,
-    xd_show: true,
-    sj_show: true,
-    adcreative_template_style: '图片',
-    landing_page_config: {
-      required: false,
-      support_page_type_list: [
-        {
-          description: ' 微信公众号详情页',
-          example: '',
-          page_type: 'PAGE_TYPE_WECHAT_OFFICIAL_ACCOUNT_DETAIL',
-          support_link_name_type: {
-            list: [
-              {
-                description: '查看详情',
-                link_name_type: 'VIEW_DETAILS',
-              },
-              {
-                description: '了解更多',
-                link_name_type: 'MORE_INFO',
-              },
-              {
-                description: '立即购买',
-                link_name_type: 'BUY_NOW',
-              },
-              {
-                description: '立即申请',
-                link_name_type: 'APPLY_NOW',
-              },
-              {
-                description: '立即预定',
-                link_name_type: 'BOOK_NOW',
-              },
-              {
-                description: '立即咨询',
-                link_name_type: 'CONSULT_NOW',
-              },
-              {
-                description: '立即预约',
-                link_name_type: 'RESERVE_NOW',
-              },
-              {
-                description: '立即领取',
-                link_name_type: 'GET_IT_NOW',
-              },
-              {
-                description: '领取优惠',
-                link_name_type: 'GET_COUPONS',
-              },
-              {
-                description: '去逛逛',
-                link_name_type: 'GO_SHOPPING',
-              },
-              {
-                description: '关注公众号',
-                link_name_type: 'FOLLOW_OFFICIAL_ACCOUNT',
-              },
-            ],
-            required: true,
-          },
-          support_link_page_type: {
-            list: [
-              {
-                description: '微信一键关注页',
-                link_page_type: 'LINK_PAGE_TYPE_WECHAT_FOCUS_DAILOG',
-              },
-            ],
-            required: true,
-          },
-        },
-        {
-          description: '微信原生推广页',
-          example: '',
-          page_type: 'PAGE_TYPE_CANVAS_WECHAT',
-          support_link_name_type: {
-            list: [
-              {
-                description: '查看详情',
-                link_name_type: 'VIEW_DETAILS',
-              },
-              {
-                description: '了解更多',
-                link_name_type: 'MORE_INFO',
-              },
-              {
-                description: '立即购买',
-                link_name_type: 'BUY_NOW',
-              },
-              {
-                description: '立即预约',
-                link_name_type: 'RESERVE_NOW',
-              },
-              {
-                description: '立即咨询',
-                link_name_type: 'CONSULT_NOW',
-              },
-              {
-                description: '立即申请',
-                link_name_type: 'APPLY_NOW',
-              },
-              {
-                description: '立即预定',
-                link_name_type: 'BOOK_NOW',
-              },
-              {
-                description: '领取优惠',
-                link_name_type: 'GET_COUPONS',
-              },
-              {
-                description: '立即领取',
-                link_name_type: 'GET_IT_NOW',
-              },
-              {
-                description: '去逛逛',
-                link_name_type: 'GO_SHOPPING',
-              },
-              {
-                description: '关注公众号',
-                link_name_type: 'FOLLOW_OFFICIAL_ACCOUNT',
-              },
-            ],
-            required: true,
-          },
-          support_link_page_type: {
-            list: [
-              {
-                description: '微信原生页',
-                link_page_type: 'LINK_PAGE_TYPE_CANVAS_WECHAT',
-              },
-              {
-                description: '微信一键关注页',
-                link_page_type: 'LINK_PAGE_TYPE_WECHAT_FOCUS_DAILOG',
-              },
-            ],
-            required: true,
-          },
-        },
-      ],
-    },
-    promoted_object_type: 'PROMOTED_OBJECT_TYPE_WECHAT_OFFICIAL_ACCOUNT',
-    site_set: ['SITE_SET_MOMENTS', 'SITE_SET_WECHAT'],
-    support_bid_mode_list: ['BID_MODE_CPC', 'BID_MODE_OCPC', 'BID_MODE_CPM', 'BID_MODE_OCPM'],
-    support_billing_spec_list: [
-      {
-        billing_event: 'BILLINGEVENT_CLICK',
-        max_price: 10000,
-        min_price: 10,
-      },
-      {
-        billing_event: 'BILLINGEVENT_IMPRESSION',
-        max_price: 99900,
-        min_price: 150,
-      },
-    ],
-    support_dynamic_ability_spec_list: {
-      dynamic_ability_type: ['DYNAMIC_TYPE_DYNAMIC_CREATIVE'],
-      product_item_display_quantity: [],
-    },
-    unsupport_bid_mode_list: [
-      {
-        bid_mode_list: ['BID_MODE_CPA'],
-        site_set: ['SITE_SET_WECHAT'],
-      },
-    ],
-    unsupport_billing_spec_list: [
-      {
-        billing_event: 'BILLINGEVENT_APP_DOWNLOAD',
-        site_set: ['SITE_SET_WECHAT'],
-        unsupport_type: 'UNSUPPORT_TYPE_EXPOSURE',
-      },
-    ],
-    unsupport_siteset_detail_spec: [
-      {
-        site_set: ['SITE_SET_MOMENTS'],
-      },
-    ],
-  },
-  //712
-  {
-    adcreative_attributes: [
-      {
-        description: '分享信息',
-        field_type: 'FIELD_TYPE_STRUCT',
-        name: 'share_content_spec',
-        property_detail: {
-          struct_detail: {
-            element_list: [
-              {
-                description: '分享描述',
-                field_type: 'FIELD_TYPE_STRING',
-                name: 'share_desc',
-                property_detail: {
-                  string_detail: {
-                    max_length: 20,
-                    min_length: 1,
-                    text_pattern: '^[^\\<\\>\\&\'\\"\\/\\x08\\x09\\x0A\\x0D\\\\]+$',
-                  },
-                },
-                required: true,
-              },
-              {
-                description: '分享标题',
-                field_type: 'FIELD_TYPE_STRING',
-                name: 'share_title',
-                property_detail: {
-                  string_detail: {
-                    max_length: 14,
-                    min_length: 1,
-                    text_pattern: '^[^\\<\\>\\&\'\\"\\/\\x08\\x09\\x0A\\x0D\\\\]+$',
-                  },
-                },
-                required: true,
-              },
-            ],
-          },
-        },
-        required: false,
-      },
-      {
-        description: '动态创意分组',
-        field_type: 'FIELD_TYPE_ENUM',
-        name: 'dynamic_creative_group_used',
-        property_detail: {
-          enum_detail: {
-            default: 'NOT_USE_GROUP',
-            enumeration: [
-              {
-                description: '不使用组合',
-                value: 'NOT_USE_GROUP',
-              },
-              {
-                description: '视频封面图组合',
-                value: 'VIDEO_IMAGE_GROUP',
-              },
-            ],
-          },
-        },
-        required: false,
-      },
-    ],
-    adcreative_elements: [
-      {
-        array_property: [],
-        description: '品牌标识图',
-        element_type: 'ELEMENT_TYPE_IMAGE',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_STRING',
-        name: 'brand_img',
-        parent_name: 'brand',
-        required: true,
-        restriction: {
-          image_restriction: {
-            file_format: ['IMAGE_TYPE_JPG', 'IMAGE_TYPE_PNG'],
-            file_size: 400,
-            height: 512,
-            width: 512,
-          },
-        },
-        struct_property: [],
-      },
-      {
-        array_property: [],
-        description: '品牌名称',
-        element_type: 'ELEMENT_TYPE_TEXT',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_STRING',
-        name: 'brand_name',
-        parent_name: 'brand',
-        required: true,
-        restriction: {
-          text_restriction: {
-            max_length: 12,
-            min_length: 2,
-            text_pattern: '^[^\\<\\>\\&\'\\"\\/\\x08\\x09\\x0A\\x0D\\\\]+$',
-          },
-        },
-        struct_property: [],
-      },
-      {
-        array_property: [],
-        description: '品牌形象',
-        element_type: 'ELEMENT_TYPE_STRUCT',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_STRUCT',
-        name: 'brand',
-        parent_name: '',
-        required: true,
-        restriction: [],
-        struct_property: {
-          element_mutual_exclusive: false,
-        },
-      },
-      {
-        array_property: [],
-        description: 'Canvas',
-        element_type: 'ELEMENT_TYPE_CANVAS',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_INTEGER',
-        name: 'canvas',
-        parent_name: '',
-        required: false,
-        restriction: [],
-        struct_property: [],
-      },
-      {
-        array_property: [],
-        description: '图片',
-        element_type: 'ELEMENT_TYPE_IMAGE',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_STRING',
-        name: 'image',
-        parent_name: '',
-        required: true,
-        restriction: {
-          image_restriction: {
-            file_format: ['IMAGE_TYPE_JPG', 'IMAGE_TYPE_PNG'],
-            file_size: 140,
-            height: 1920,
-            width: 1080,
-          },
-        },
-        struct_property: [],
-      },
-      {
-        description: '标签内容',
-        element_type: 'ELEMENT_TYPE_TEXT',
-        field_type: 'FIELD_TYPE_STRING',
-        name: 'content',
-        parent_name: 'label',
-        required: true,
-        restriction: {
-          text_restriction: {
-            max_length: 15,
-            min_length: 2,
-            text_pattern: '',
-          },
-        },
-      },
-      {
-        array_property: {
-          max_number: 3,
-          min_number: 1,
-        },
-        description: '标签',
-        element_type: 'ELEMENT_TYPE_STRUCT',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_STRUCT_ARRAY',
-        name: 'label',
-        parent_name: '',
-        required: false,
-        restriction: [],
-        struct_property: [],
-      },
-    ],
-    adcreative_sample_image:
-      'http://qzonestyle.gtimg.cn/gdt_ui_proj/dist/gdt/imgbox/creative_template_712.svg',
-    adcreative_template_appellation: '竖版大图 9:16',
-    adcreative_template_id: 712,
-    bq_show: true,
-    adcreative_template_style: '图片',
-    landing_page_config: {
-      required: false,
-      support_page_type_list: [
-        {
-          description: ' 微信公众号详情页',
-          example: '',
-          page_type: 'PAGE_TYPE_WECHAT_OFFICIAL_ACCOUNT_DETAIL',
-        },
-        {
-          description: '微信原生推广页',
-          example: '',
-          page_type: 'PAGE_TYPE_CANVAS_WECHAT',
-        },
-      ],
-    },
-    promoted_object_type: 'PROMOTED_OBJECT_TYPE_WECHAT_OFFICIAL_ACCOUNT',
-    site_set: ['SITE_SET_MOMENTS', 'SITE_SET_WECHAT'],
-    support_bid_mode_list: ['BID_MODE_CPM', 'BID_MODE_OCPM'],
-    support_billing_spec_list: [
-      {
-        billing_event: 'BILLINGEVENT_IMPRESSION',
-        max_price: 99900,
-        min_price: 150,
-      },
-    ],
-    support_dynamic_ability_spec_list: {
-      dynamic_ability_type: ['DYNAMIC_TYPE_DYNAMIC_CREATIVE'],
-      product_item_display_quantity: [],
-    },
-    unsupport_bid_mode_list: [
-      {
-        bid_mode_list: ['BID_MODE_CPC', 'BID_MODE_OCPC'],
-        site_set: ['SITE_SET_WECHAT'],
-      },
-      {
-        bid_mode_list: ['BID_MODE_CPA'],
-        site_set: ['SITE_SET_WECHAT'],
-      },
-    ],
-    unsupport_billing_spec_list: [
-      {
-        billing_event: 'BILLINGEVENT_CLICK',
-        site_set: ['SITE_SET_WECHAT'],
-        unsupport_type: 'UNSUPPORT_TYPE_EXPOSURE',
-      },
-      {
-        billing_event: 'BILLINGEVENT_APP_DOWNLOAD',
-        site_set: ['SITE_SET_WECHAT'],
-        unsupport_type: 'UNSUPPORT_TYPE_EXPOSURE',
-      },
-    ],
-    unsupport_siteset_detail_spec: [
-      {
-        site_set: ['SITE_SET_MOMENTS'],
-      },
-    ],
-  },
-  //910
-  {
-    adcreative_attributes: [
-      {
-        description: '动态创意分组',
-        field_type: 'FIELD_TYPE_ENUM',
-        name: 'dynamic_creative_group_used',
-        property_detail: {
-          enum_detail: {
-            default: 'NOT_USE_GROUP',
-            enumeration: [
-              {
-                description: '不使用组合',
-                value: 'NOT_USE_GROUP',
-              },
-              {
-                description: '视频封面图组合',
-                value: 'VIDEO_IMAGE_GROUP',
-              },
-            ],
-          },
-        },
-        required: false,
-      },
-    ],
-    adcreative_elements: [
-      {
-        array_property: [],
-        description: 'Canvas',
-        element_type: 'ELEMENT_TYPE_CANVAS',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_INTEGER',
-        name: 'canvas',
-        parent_name: '',
-        required: false,
-        restriction: [],
-        struct_property: [],
-      },
-    ],
-    adcreative_sample_image:
-      'https://qzonestyle.gtimg.cn/gdt_ui_proj/dist/phoenix/images/ctpl/ctpl-inspires.svg',
-    adcreative_template_appellation: '激励浏览广告',
-    adcreative_template_id: 910,
-    adcreative_template_style: '图片',
-    landing_page_config: {
-      required: false,
-      support_page_type_list: [
-        {
-          description: '微信原生推广页',
-          example: '',
-          page_type: 'PAGE_TYPE_CANVAS_WECHAT',
-        },
-      ],
-    },
-    promoted_object_type: 'PROMOTED_OBJECT_TYPE_WECHAT_OFFICIAL_ACCOUNT',
-    site_set: ['SITE_SET_MOMENTS', 'SITE_SET_WECHAT'],
-    support_bid_mode_list: ['BID_MODE_CPM', 'BID_MODE_OCPM'],
-    support_billing_spec_list: [
-      {
-        billing_event: 'BILLINGEVENT_IMPRESSION',
-        max_price: 99900,
-        min_price: 150,
-      },
-    ],
-    support_dynamic_ability_spec_list: {
-      dynamic_ability_type: [],
-      product_item_display_quantity: [],
-    },
-    unsupport_bid_mode_list: [
-      {
-        bid_mode_list: ['BID_MODE_CPC', 'BID_MODE_OCPC'],
-        site_set: ['SITE_SET_WECHAT'],
-      },
-      {
-        bid_mode_list: ['BID_MODE_CPA'],
-        site_set: ['SITE_SET_WECHAT'],
-      },
-    ],
-    unsupport_billing_spec_list: [
-      {
-        billing_event: 'BILLINGEVENT_CLICK',
-        site_set: ['SITE_SET_WECHAT'],
-        unsupport_type: 'UNSUPPORT_TYPE_EXPOSURE',
-      },
-      {
-        billing_event: 'BILLINGEVENT_APP_DOWNLOAD',
-        site_set: ['SITE_SET_WECHAT'],
-        unsupport_type: 'UNSUPPORT_TYPE_EXPOSURE',
-      },
-    ],
-    unsupport_siteset_detail_spec: [
-      {
-        site_set: ['SITE_SET_MOMENTS'],
-      },
-    ],
-  },
-  //925
-  {
-    adcreative_attributes: [
-      {
-        description: '动态创意分组',
-        field_type: 'FIELD_TYPE_ENUM',
-        name: 'dynamic_creative_group_used',
-        property_detail: {
-          enum_detail: {
-            default: 'NOT_USE_GROUP',
-            enumeration: [
-              {
-                description: '不使用组合',
-                value: 'NOT_USE_GROUP',
-              },
-              {
-                description: '视频封面图组合',
-                value: 'VIDEO_IMAGE_GROUP',
-              },
-            ],
-          },
-        },
-        required: false,
-      },
-    ],
-    adcreative_elements: [
-      {
-        array_property: [],
-        description: 'Canvas',
-        element_type: 'ELEMENT_TYPE_CANVAS',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_INTEGER',
-        name: 'canvas',
-        parent_name: '',
-        required: false,
-        restriction: [],
-        struct_property: [],
-      },
-      {
-        array_property: [],
-        description: '图片',
-        element_type: 'ELEMENT_TYPE_IMAGE',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_STRING',
-        name: 'image',
-        parent_name: '',
-        required: true,
-        restriction: {
-          image_restriction: {
-            file_format: ['IMAGE_TYPE_JPG', 'IMAGE_TYPE_PNG'],
-            file_size: 100,
-            height: 334,
-            width: 960,
-          },
-        },
-        struct_property: [],
-      },
-    ],
-    adcreative_sample_image:
-      'http://qzonestyle.gtimg.cn/gdt_ui_proj/dist/gdt/ad-process/images/creative-size-banner.svg',
-    adcreative_template_appellation: 'Banner图片 20:7',
-    adcreative_template_id: 925,
-    xd_show: true,
-    adcreative_template_style: '图片',
-    landing_page_config: {
-      required: false,
-      support_page_type_list: [
-        {
-          description: '微信原生推广页',
-          example: '',
-          page_type: 'PAGE_TYPE_CANVAS_WECHAT',
-          support_link_name_type: {
-            list: [
-              {
-                description: '查看详情',
-                link_name_type: 'VIEW_DETAILS',
-              },
-              {
-                description: '领取优惠',
-                link_name_type: 'GET_COUPONS',
-              },
-              {
-                description: '立即购买',
-                link_name_type: 'BUY_NOW',
-              },
-              {
-                description: '去逛逛',
-                link_name_type: 'GO_SHOPPING',
-              },
-              {
-                description: '立即申请',
-                link_name_type: 'APPLY_NOW',
-              },
-              {
-                description: '立即预定',
-                link_name_type: 'BOOK_NOW',
-              },
-              {
-                description: '立即咨询',
-                link_name_type: 'CONSULT_NOW',
-              },
-              {
-                description: '立即领取',
-                link_name_type: 'GET_IT_NOW',
-              },
-              {
-                description: '了解更多',
-                link_name_type: 'MORE_INFO',
-              },
-              {
-                description: '关注公众号',
-                link_name_type: 'FOLLOW_OFFICIAL_ACCOUNT',
-              },
-              {
-                description: '阅读小说',
-                link_name_type: 'READ_NOVELS',
-              },
-              {
-                description: '立即预约',
-                link_name_type: 'RESERVE_NOW',
-              },
-            ],
-            required: false,
-          },
-          support_link_page_type: {
-            list: [
-              {
-                description: '微信原生页',
-                link_page_type: 'LINK_PAGE_TYPE_CANVAS_WECHAT',
-              },
-              {
-                description: '微信一键关注页',
-                link_page_type: 'LINK_PAGE_TYPE_WECHAT_FOCUS_DAILOG',
-              },
-            ],
-            required: false,
-          },
-        },
-        {
-          description: ' 微信公众号详情页',
-          example: '',
-          page_type: 'PAGE_TYPE_WECHAT_OFFICIAL_ACCOUNT_DETAIL',
-          support_link_name_type: {
-            list: [
-              {
-                description: '查看详情',
-                link_name_type: 'VIEW_DETAILS',
-              },
-              {
-                description: '领取优惠',
-                link_name_type: 'GET_COUPONS',
-              },
-              {
-                description: '立即购买',
-                link_name_type: 'BUY_NOW',
-              },
-              {
-                description: '去逛逛',
-                link_name_type: 'GO_SHOPPING',
-              },
-              {
-                description: '立即申请',
-                link_name_type: 'APPLY_NOW',
-              },
-              {
-                description: '立即预定',
-                link_name_type: 'BOOK_NOW',
-              },
-              {
-                description: '立即咨询',
-                link_name_type: 'CONSULT_NOW',
-              },
-              {
-                description: '立即领取',
-                link_name_type: 'GET_IT_NOW',
-              },
-              {
-                description: '了解更多',
-                link_name_type: 'MORE_INFO',
-              },
-              {
-                description: '关注公众号',
-                link_name_type: 'FOLLOW_OFFICIAL_ACCOUNT',
-              },
-              {
-                description: '阅读小说',
-                link_name_type: 'READ_NOVELS',
-              },
-              {
-                description: '立即预约',
-                link_name_type: 'RESERVE_NOW',
-              },
-            ],
-            required: false,
-          },
-          support_link_page_type: {
-            list: [
-              {
-                description: '微信一键关注页',
-                link_page_type: 'LINK_PAGE_TYPE_WECHAT_FOCUS_DAILOG',
-              },
-            ],
-            required: false,
-          },
-        },
-      ],
-    },
-    promoted_object_type: 'PROMOTED_OBJECT_TYPE_WECHAT_OFFICIAL_ACCOUNT',
-    site_set: ['SITE_SET_MOMENTS', 'SITE_SET_WECHAT'],
-    support_bid_mode_list: ['BID_MODE_CPC', 'BID_MODE_OCPC', 'BID_MODE_CPM', 'BID_MODE_OCPM'],
-    support_billing_spec_list: [
-      {
-        billing_event: 'BILLINGEVENT_CLICK',
-        max_price: 10000,
-        min_price: 10,
-      },
-      {
-        billing_event: 'BILLINGEVENT_IMPRESSION',
-        max_price: 99900,
-        min_price: 150,
-      },
-    ],
-    support_dynamic_ability_spec_list: {
-      dynamic_ability_type: ['DYNAMIC_TYPE_DYNAMIC_CREATIVE'],
-      product_item_display_quantity: [],
-    },
-    unsupport_bid_mode_list: [
-      {
-        bid_mode_list: ['BID_MODE_CPA'],
-        site_set: ['SITE_SET_WECHAT'],
-      },
-    ],
-    unsupport_billing_spec_list: [
-      {
-        billing_event: 'BILLINGEVENT_APP_DOWNLOAD',
-        site_set: ['SITE_SET_WECHAT'],
-        unsupport_type: 'UNSUPPORT_TYPE_EXPOSURE',
-      },
-    ],
-    unsupport_siteset_detail_spec: [
-      {
-        site_set: ['SITE_SET_MOMENTS'],
-      },
-    ],
-  },
-  //1707
-  {
-    adcreative_attributes: [
-      {
-        description: '头像及昵称跳转页',
-        field_type: 'FIELD_TYPE_INTEGER',
-        name: 'profile_id',
-        property_detail: {
-          integer_detail: {
-            max: 20,
-            min: 0,
-          },
-        },
-        required: true,
-      },
-      {
-        description: '分享信息',
-        field_type: 'FIELD_TYPE_STRUCT',
-        name: 'share_content_spec',
-        property_detail: {
-          struct_detail: {
-            element_list: [
-              {
-                description: '分享描述',
-                field_type: 'FIELD_TYPE_STRING',
-                name: 'share_desc',
-                property_detail: {
-                  string_detail: {
-                    max_length: 20,
-                    min_length: 1,
-                    text_pattern: '^[^\\<\\>\\&\'\\"\\/\\x08\\x09\\x0A\\x0D\\\\]+$',
-                  },
-                },
-                required: true,
-              },
-              {
-                description: '分享标题',
-                field_type: 'FIELD_TYPE_STRING',
-                name: 'share_title',
-                property_detail: {
-                  string_detail: {
-                    max_length: 14,
-                    min_length: 1,
-                    text_pattern: '^[^\\<\\>\\&\'\\"\\/\\x08\\x09\\x0A\\x0D\\\\]+$',
-                  },
-                },
-                required: true,
-              },
-            ],
-          },
-        },
-        required: false,
-      },
-      {
-        description: '动态创意分组',
-        field_type: 'FIELD_TYPE_ENUM',
-        name: 'dynamic_creative_group_used',
-        property_detail: {
-          enum_detail: {
-            default: 'NOT_USE_GROUP',
-            enumeration: [
-              {
-                description: '不使用组合',
-                value: 'NOT_USE_GROUP',
-              },
-              {
-                description: '视频封面图组合',
-                value: 'VIDEO_IMAGE_GROUP',
-              },
-            ],
-          },
-        },
-        required: false,
-      },
-    ],
-    adcreative_elements: [
-      {
-        array_property: [],
-        description: '品牌名称',
-        element_type: 'ELEMENT_TYPE_TEXT',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_STRING',
-        name: 'brand_name',
-        parent_name: 'brand',
-        required: true,
-        restriction: {
-          text_restriction: {
-            max_length: 12,
-            min_length: 2,
-            text_pattern: '^[^\\<\\>\\&\'\\"\\/\\x08\\x09\\x0A\\x0D\\\\]+$',
-          },
-        },
-        struct_property: [],
-      },
-      {
-        array_property: [],
-        description: '品牌标识图',
-        element_type: 'ELEMENT_TYPE_IMAGE',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_STRING',
-        name: 'brand_img',
-        parent_name: 'brand',
-        required: true,
-        restriction: {
-          image_restriction: {
-            file_format: ['IMAGE_TYPE_JPG', 'IMAGE_TYPE_PNG'],
-            file_size: 400,
-            height: 512,
-            width: 512,
-          },
-        },
-        struct_property: [],
-      },
-      {
-        array_property: [],
-        description: '品牌形象',
-        element_type: 'ELEMENT_TYPE_STRUCT',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_STRUCT',
-        name: 'brand',
-        parent_name: '',
-        required: false,
-        restriction: [],
-        struct_property: {
-          element_mutual_exclusive: false,
-        },
-      },
-      {
-        array_property: [],
-        description: 'Canvas',
-        element_type: 'ELEMENT_TYPE_CANVAS',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_INTEGER',
-        name: 'canvas',
-        parent_name: '',
-        required: false,
-        restriction: [],
-        struct_property: [],
-      },
-      {
-        array_property: [],
-        description: '倒计时结束时间(选填)',
-        element_type: 'ELEMENT_TYPE_TEXT',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_STRING',
-        name: 'countdown_expiring_timestamp',
-        parent_name: '',
-        required: false,
-        restriction: {
-          text_restriction: {
-            max_length: 13,
-            min_length: 1,
-            text_pattern: '^[^\\<\\>\\&\'\\"\\/\\x08\\x09\\x0A\\x0D\\\\]+$',
-          },
-        },
-        struct_property: [],
-      },
-      {
-        array_property: [],
-        description: '广告详情',
-        element_type: 'ELEMENT_TYPE_TEXT',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_STRING',
-        name: 'description',
-        parent_name: '',
-        required: true,
-        restriction: {
-          text_restriction: {
-            max_length: 30,
-            min_length: 1,
-            text_pattern: '^[^\\<\\>\\&\'\\"\\/\\x08\\x09\\x0A\\x0D\\\\]+$',
-          },
-        },
-        struct_property: [],
-      },
-      {
-        array_property: {
-          max_number: 1,
-          min_number: 1,
-        },
-        description: '图片',
-        element_type: 'ELEMENT_TYPE_IMAGE',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_STRING_ARRAY',
-        name: 'image_list',
-        parent_name: '',
-        required: true,
-        restriction: {
-          image_restriction: {
-            file_format: ['IMAGE_TYPE_JPG', 'IMAGE_TYPE_PNG'],
-            file_size: 400,
-            height: 720,
-            width: 1280,
-          },
-        },
-        struct_property: [],
-      },
-      {
-        description: '标签内容',
-        element_type: 'ELEMENT_TYPE_TEXT',
-        field_type: 'FIELD_TYPE_STRING',
-        name: 'content',
-        parent_name: 'label',
-        required: true,
-        restriction: {
-          text_restriction: {
-            max_length: 16,
-            min_length: 1,
-            text_pattern: '',
-          },
-        },
-      },
-      {
-        array_property: {
-          max_number: 3,
-          min_number: 0,
-        },
-        description: '标签',
-        element_type: 'ELEMENT_TYPE_STRUCT',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_STRUCT_ARRAY',
-        name: 'label',
-        parent_name: '',
-        required: false,
-        restriction: [],
-        struct_property: [],
-      },
-      {
-        array_property: [],
-        description: '标题',
-        element_type: 'ELEMENT_TYPE_TEXT',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_STRING',
-        name: 'title',
-        parent_name: '',
-        required: false,
-        restriction: {
-          text_restriction: {
-            max_length: 14,
-            min_length: 1,
-            text_pattern: '^[^\\<\\>\\&\'\\"\\/\\x08\\x09\\x0A\\x0D\\\\]+$',
-          },
-        },
-        struct_property: [],
-      },
-      {
-        array_property: [],
-        description: '卖点图',
-        element_type: 'ELEMENT_TYPE_IMAGE',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_STRING',
-        name: 'shop_image',
-        parent_name: '',
-        required: false,
-        restriction: {
-          image_restriction: {
-            file_format: ['IMAGE_TYPE_JPG', 'IMAGE_TYPE_PNG'],
-            file_size: 20,
-            height: 80,
-            width: 80,
-          },
-        },
-        struct_property: [],
-      },
-      {
-        array_property: [],
-        description: '倒计时开始时间(选填)',
-        element_type: 'ELEMENT_TYPE_TEXT',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_STRING',
-        name: 'countdown_begin',
-        parent_name: '',
-        required: false,
-        restriction: {
-          text_restriction: {
-            max_length: 11,
-            min_length: 1,
-            text_pattern: '^[^\\<\\>\\&\'\\"\\/\\x08\\x09\\x0A\\x0D\\\\]+$',
-          },
-        },
-        struct_property: [],
-      },
-      {
-        array_property: [],
-        description: '倒计时时间描述',
-        element_type: 'ELEMENT_TYPE_TEXT',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_STRING',
-        name: 'countdown_time_type',
-        parent_name: '',
-        required: false,
-        restriction: {
-          text_restriction: {
-            max_length: 64,
-            min_length: 1,
-            text_pattern: '^[^\\<\\>\\&\'\\"\\/\\x08\\x09\\x0A\\x0D\\\\]+$',
-          },
-        },
-        struct_property: [],
-      },
-      {
-        array_property: [],
-        description: '倒计时价格展示(选填)',
-        element_type: 'ELEMENT_TYPE_TEXT',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_STRING',
-        name: 'countdown_price',
-        parent_name: '',
-        required: false,
-        restriction: {
-          text_restriction: {
-            max_length: 9,
-            min_length: 1,
-            text_pattern: '^[^\\<\\>\\&\'\\"\\/\\x08\\x09\\x0A\\x0D\\\\]+$',
-          },
-        },
-        struct_property: [],
-      },
-      {
-        array_property: [],
-        description: '是否支开启卖点图',
-        element_type: 'ELEMENT_TYPE_BOOLEAN',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_BOOLEAN',
-        name: 'shop_image_switch',
-        parent_name: 'shop_image_struct',
-        required: true,
-        restriction: [],
-        struct_property: [],
-      },
-      {
-        array_property: [],
-        description: '启用动态卖点图',
-        element_type: 'ELEMENT_TYPE_BOOLEAN',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_BOOLEAN',
-        name: 'dynamic_shop_image_switch',
-        parent_name: 'shop_image_struct',
-        required: false,
-        restriction: [],
-        struct_property: [],
-      },
-      {
-        array_property: [],
-        description: '卖点图',
-        element_type: 'ELEMENT_TYPE_IMAGE',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_STRING',
-        name: 'shop_image_id',
-        parent_name: 'shop_image_struct',
-        required: false,
-        restriction: {
-          image_restriction: {
-            file_format: ['IMAGE_TYPE_JPG', 'IMAGE_TYPE_PNG'],
-            file_size: 20,
-            height: 80,
-            width: 80,
-          },
-        },
-        struct_property: [],
-      },
-      {
-        array_property: [],
-        description: '卖点标题(选填)',
-        element_type: 'ELEMENT_TYPE_TEXT',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_STRING',
-        name: 'shop_image_title',
-        parent_name: 'shop_image_struct',
-        required: false,
-        restriction: {
-          text_restriction: {
-            max_length: 10,
-            min_length: 1,
-            text_pattern: '^[^\\<\\>\\&\'\\"\\/\\x08\\x09\\x0A\\x0D\\\\]+$',
-          },
-        },
-        struct_property: [],
-      },
-      {
-        array_property: [],
-        description: '卖点描述',
-        element_type: 'ELEMENT_TYPE_TEXT',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_STRING',
-        name: 'shop_image_description',
-        parent_name: 'shop_image_struct',
-        required: false,
-        restriction: {
-          text_restriction: {
-            max_length: 10,
-            min_length: 1,
-            text_pattern: '^[^\\<\\>\\&\'\\"\\/\\x08\\x09\\x0A\\x0D\\\\]+$',
-          },
-        },
-        struct_property: [],
-      },
-      {
-        array_property: [],
-        description: '卖点图',
-        element_type: 'ELEMENT_TYPE_STRUCT',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_STRUCT',
-        name: 'shop_image_struct',
-        parent_name: '',
-        required: false,
-        restriction: [],
-        struct_property: {
-          element_mutual_exclusive: false,
-        },
-      },
-      {
-        array_property: [],
-        description: '左按钮文案',
-        element_type: 'ELEMENT_TYPE_TEXT',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_STRING',
-        name: 'chosen_button_text1',
-        parent_name: 'chosen_button',
-        required: true,
-        restriction: {
-          text_restriction: {
-            max_length: 4,
-            min_length: 1,
-            text_pattern: '^[^\\<\\>\\&\'\\"\\/\\x08\\x09\\x0A\\x0D\\\\]+$',
-          },
-        },
-        struct_property: [],
-      },
-      {
-        array_property: [],
-        description: '左按钮跳转',
-        element_type: 'ELEMENT_TYPE_TEXT',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_STRING',
-        name: 'chosen_button_landing_page1',
-        parent_name: 'chosen_button',
-        required: true,
-        restriction: [],
-        struct_property: [],
-      },
-      {
-        array_property: [],
-        description: '右按钮文案',
-        element_type: 'ELEMENT_TYPE_TEXT',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_STRING',
-        name: 'chosen_button_text2',
-        parent_name: 'chosen_button',
-        required: true,
-        restriction: {
-          text_restriction: {
-            max_length: 4,
-            min_length: 1,
-            text_pattern: '^[^\\<\\>\\&\'\\"\\/\\x08\\x09\\x0A\\x0D\\\\]+$',
-          },
-        },
-        struct_property: [],
-      },
-      {
-        array_property: [],
-        description: '右按钮跳转',
-        element_type: 'ELEMENT_TYPE_TEXT',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_STRING',
-        name: 'chosen_button_landing_page2',
-        parent_name: 'chosen_button',
-        required: true,
-        restriction: [],
-        struct_property: [],
-      },
-      {
-        array_property: [],
-        description: '选择按钮',
-        element_type: 'ELEMENT_TYPE_STRUCT',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_STRUCT',
-        name: 'chosen_button',
-        parent_name: '',
-        required: false,
-        restriction: [],
-        struct_property: {
-          element_mutual_exclusive: false,
-        },
-      },
-      {
-        array_property: [],
-        description: '是否开启轮播文案',
-        element_type: 'ELEMENT_TYPE_TEXT',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_STRING',
-        name: 'living_desc_struct_switch',
-        parent_name: 'living_desc_struct',
-        required: true,
-        restriction: {
-          text_restriction: {
-            max_length: 8,
-            min_length: 1,
-            text_pattern: '^[^\\<\\>\\&\'\\"\\/\\x08\\x09\\x0A\\x0D\\\\]+$',
-          },
-        },
-        struct_property: [],
-      },
-      {
-        array_property: {
-          max_number: 5,
-          min_number: 2,
-        },
-        description: '轮播文案',
-        element_type: 'ELEMENT_TYPE_TEXT',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_STRING_ARRAY',
-        name: 'living_desc_list',
-        parent_name: 'living_desc_struct',
-        required: true,
-        restriction: {
-          text_restriction: {
-            max_length: 16,
-            min_length: 1,
-            text_pattern: '^[^\\<\\>\\&\'\\"\\/\\x08\\x09\\x0A\\x0D\\\\]+$',
-          },
-        },
-        struct_property: [],
-      },
-      {
-        array_property: [],
-        description: '轮播文案',
-        element_type: 'ELEMENT_TYPE_STRUCT',
-        enum_property: [],
-        field_type: 'FIELD_TYPE_STRUCT',
-        name: 'living_desc_struct',
-        parent_name: '',
-        required: false,
-        restriction: [],
-        struct_property: {
-          element_mutual_exclusive: false,
-        },
-      },
-    ],
-    adcreative_sample_image:
-      'http://qzonestyle.gtimg.cn/gdt_ui_proj/dist/gdt/imgbox/mp-img-act.svg',
-    adcreative_template_appellation: '卡片广告 横版大图 16:9',
-    adcreative_template_id: 1707,
-    kp_show: true,
-    adcreative_template_style: '图片',
-    landing_page_config: {
-      required: false,
-      support_page_type_list: [
-        {
-          description: '微信原生推广页',
-          example: '',
-          page_type: 'PAGE_TYPE_CANVAS_WECHAT',
-          support_link_name_type: {
-            list: [
-              {
-                description: '查看详情',
-                link_name_type: 'VIEW_DETAILS',
-              },
-              {
-                description: '了解更多',
-                link_name_type: 'MORE_INFO',
-              },
-              {
-                description: '立即购买',
-                link_name_type: 'BUY_NOW',
-              },
-              {
-                description: '立即申请',
-                link_name_type: 'APPLY_NOW',
-              },
-              {
-                description: '立即预定',
-                link_name_type: 'BOOK_NOW',
-              },
-              {
-                description: '立即咨询',
-                link_name_type: 'CONSULT_NOW',
-              },
-              {
-                description: '立即预约',
-                link_name_type: 'RESERVE_NOW',
-              },
-              {
-                description: '立即领取',
-                link_name_type: 'GET_IT_NOW',
-              },
-              {
-                description: '领取优惠',
-                link_name_type: 'GET_COUPONS',
-              },
-              {
-                description: '去逛逛',
-                link_name_type: 'GO_SHOPPING',
-              },
-              {
-                description: '关注公众号',
-                link_name_type: 'FOLLOW_OFFICIAL_ACCOUNT',
-              },
-              {
-                description: '阅读小说',
-                link_name_type: 'READ_NOVELS',
-              },
-            ],
-            required: false,
-          },
-          support_link_page_type: {
-            list: [
-              {
-                description: '微信原生页',
-                link_page_type: 'LINK_PAGE_TYPE_CANVAS_WECHAT',
-              },
-              {
-                description: ' 微信公众号详情页',
-                link_page_type: 'LINK_PAGE_TYPE_WECHAT_OFFICIAL_ACCOUNT_DETAIL',
-              },
-            ],
-            required: true,
-          },
-        },
-        {
-          description: ' 微信公众号详情页',
-          example: '',
-          page_type: 'PAGE_TYPE_WECHAT_OFFICIAL_ACCOUNT_DETAIL',
-          support_link_name_type: {
-            list: [
-              {
-                description: '查看详情',
-                link_name_type: 'VIEW_DETAILS',
-              },
-              {
-                description: '了解更多',
-                link_name_type: 'MORE_INFO',
-              },
-              {
-                description: '立即购买',
-                link_name_type: 'BUY_NOW',
-              },
-              {
-                description: '立即申请',
-                link_name_type: 'APPLY_NOW',
-              },
-              {
-                description: '立即预定',
-                link_name_type: 'BOOK_NOW',
-              },
-              {
-                description: '立即咨询',
-                link_name_type: 'CONSULT_NOW',
-              },
-              {
-                description: '立即预约',
-                link_name_type: 'RESERVE_NOW',
-              },
-              {
-                description: '立即领取',
-                link_name_type: 'GET_IT_NOW',
-              },
-              {
-                description: '领取优惠',
-                link_name_type: 'GET_COUPONS',
-              },
-              {
-                description: '去逛逛',
-                link_name_type: 'GO_SHOPPING',
-              },
-              {
-                description: '关注公众号',
-                link_name_type: 'FOLLOW_OFFICIAL_ACCOUNT',
-              },
-              {
-                description: '阅读小说',
-                link_name_type: 'READ_NOVELS',
-              },
-            ],
-            required: false,
-          },
-          support_link_page_type: {
-            list: [
-              {
-                description: ' 微信公众号详情页',
-                link_page_type: 'LINK_PAGE_TYPE_WECHAT_OFFICIAL_ACCOUNT_DETAIL',
-              },
-            ],
-            required: true,
-          },
-        },
-      ],
-    },
-    promoted_object_type: 'PROMOTED_OBJECT_TYPE_WECHAT_OFFICIAL_ACCOUNT',
-    site_set: ['SITE_SET_MOMENTS', 'SITE_SET_WECHAT'],
-    support_bid_mode_list: ['BID_MODE_CPM', 'BID_MODE_OCPM'],
-    support_billing_spec_list: [
-      {
-        billing_event: 'BILLINGEVENT_IMPRESSION',
-        max_price: 99900,
-        min_price: 150,
-      },
-    ],
-    support_dynamic_ability_spec_list: {
-      dynamic_ability_type: ['DYNAMIC_TYPE_DYNAMIC_CREATIVE'],
-      product_item_display_quantity: [],
-    },
-    unsupport_bid_mode_list: [
-      {
-        bid_mode_list: ['BID_MODE_CPA'],
-        site_set: ['SITE_SET_MOMENTS'],
-      },
-      {
-        bid_mode_list: ['BID_MODE_CPC', 'BID_MODE_OCPC'],
-        site_set: ['SITE_SET_MOMENTS'],
-      },
-      {
-        bid_mode_list: ['BID_MODE_CPA'],
-        site_set: ['SITE_SET_WECHAT'],
-      },
-    ],
-    unsupport_billing_spec_list: [
-      {
-        billing_event: 'BILLINGEVENT_APP_DOWNLOAD',
-        site_set: ['SITE_SET_MOMENTS'],
-        unsupport_type: 'UNSUPPORT_TYPE_EXPOSURE',
-      },
-      {
-        billing_event: 'BILLINGEVENT_CLICK',
-        site_set: ['SITE_SET_MOMENTS'],
-        unsupport_type: 'UNSUPPORT_TYPE_EXPOSURE',
-      },
-      {
-        billing_event: 'BILLINGEVENT_APP_DOWNLOAD',
-        site_set: ['SITE_SET_WECHAT'],
-        unsupport_type: 'UNSUPPORT_TYPE_EXPOSURE',
-      },
-    ],
-    unsupport_siteset_detail_spec: [
-      {
-        site_set: [],
-      },
-    ],
-  },
-];
+
 
 /**即将下线创意形式*/
 const outAdcreativeTemplateIdEnum = [

+ 5 - 0
src/pages/launchSystemNew/launchManage/localAd/brand/index.tsx

@@ -0,0 +1,5 @@
+import React from 'react'
+
+function Brand(){
+    return 
+}

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

@@ -78,9 +78,9 @@ function Creative() {
             pageSize={sysAdcreativeList?.data?.data?.size}
             leftChild={<>
                 <Row gutter={[10, 10]}>
-                    <Col span={24}><Button type='primary' onClick={() => {
+                    {/* <Col span={24}><Button type='primary' onClick={() => {
                         handleModalConfig({ visible: true })
-                    }}>新建创意模板</Button></Col>
+                    }}>新建创意模板</Button></Col> */}
                     <Col>
                         <Input
                             placeholder='创意名称'

+ 1 - 2
src/pages/launchSystemNew/launchManage/localAd/creative/modal.tsx

@@ -9,7 +9,7 @@ import { getText, get_adcreative_template, get_adcreative_template_list } from '
 import { AdcreativeTemplate, AdcreativeTemplateList } from '@/services/launchAdq'
 import { mySet } from '@/utils/arrFn'
 import SelectCloud from '@/pages/launchSystemNew/components/selectCloud'
-import { useModel } from '@/.umi/plugin-model/useModel'
+import { useModel } from 'umi'
 interface Props {
     title?: string,
     visible: boolean,
@@ -35,7 +35,6 @@ function CreativeModal(props: Props) {
     const [descriptionShow, setdescriptionshow] = useState(false)
     const [endPageDescShow, setendPageDescnshow] = useState(false)
     const [titleShow, settitleshow] = useState(false)
-    const [login, setlogin] = useState(true)
     const [form] = Form.useForm();
     const [pupState, setPupState] = useState({
         kp_show: false,

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

@@ -77,9 +77,9 @@ function Targeting() {
             pageSize={list?.data?.data?.size}
             leftChild={<>
                 <Row gutter={[10, 10]}>
-                    <Col span={24}><Button type='primary' onClick={() => {
+                    {/* <Col span={24}><Button type='primary' onClick={() => {
                         handleModalConfig({ visible: true })
-                    }}>新建定向模板</Button></Col>
+                    }}>新建定向模板</Button></Col> */}
                     <Col>
                         <Input
                             placeholder='定向名称'

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

@@ -4,7 +4,6 @@ import { GenderEnum, EducationEnum, ExcludedDimensionEnum, MaritalStatusEnum, Op
 import { ModalConfig } from '.'
 import { useAjax } from '@/Hook/useAjax'
 import { getTagsList } from '@/services/launchAdq/global'
-import { filter } from '@umijs/deps/compiled/lodash'
 interface Props {
     title?: string,
     visible: boolean,

+ 99 - 0
src/pages/launchSystemNew/launchManage/taskList/batchCreativeCopy.tsx

@@ -0,0 +1,99 @@
+import { useAjax } from "@/Hook/useAjax"
+import { getSysAdcreativeInfo } from "@/services/launchAdq/creative"
+import { PromotedObjectType, SiteSetEnum } from "@/services/launchAdq/enum"
+import { PlusOutlined } from "@ant-design/icons"
+import { Button, Modal } from "antd"
+import React, { useEffect, useRef, useState } from "react"
+import CreativeForm from "./creativeForm"
+import style from './index.less'
+
+interface Props {
+    publicData: any,
+    data: any,
+    visible?: boolean,
+    onClose?: () => void,
+    onChange?: () => void
+}
+/**
+ * 批量复制
+ * @returns 
+ */
+const BatchCreativeCopy: React.FC<Props> = (props) => {
+
+    /*******************************/
+    const { publicData, visible, onClose, onChange } = props
+    const [oriData, setOriData] = useState<any[]>([])  // 创意数据
+    const [template, setTemplate] = useState<{ siteSet: string[], promotedObjectType: string }>({ siteSet: [], promotedObjectType: '' })
+    const itemsRef: any = useRef([]);
+
+    const getSysAdcreative = useAjax((params) => getSysAdcreativeInfo(params))
+    /*******************************/
+
+    // 获取创意详情
+    useEffect(() => {
+        getSysAdcreative.run(publicData?.sysAdcreativeId).then(res => {
+            console.log(111111, res);
+            oriData[0] = { data: res, isOpen: true }
+            setOriData(JSON.parse(JSON.stringify(oriData)))
+            setTemplate({ siteSet: res?.siteSet, promotedObjectType: res?.promotedObjectType })
+        })
+    }, [])
+
+    const handleOk = () => {
+        console.log('itemsRef---->', itemsRef);
+        let current = (itemsRef?.current as any[])?.filter(item => item)
+        console.log('itemsRef?.current---->', current);
+        Promise.all(current?.map((item: { handleOk: any }) => item.handleOk())).then(res => {
+            console.log(1111111, res);
+            
+        }).catch(err => {
+            console.log(22222222, err);
+        })
+    }
+
+    // 删除创意
+    const delOri = (index: number) => {
+        oriData?.splice(index, 1)
+        setOriData([...oriData])
+    }
+
+    // 新增创意
+    const addOri = () => {
+        let newOriData = [...oriData]
+        newOriData.push({ isOpen: true })
+        setOriData(newOriData)
+    }
+
+    return <Modal title="批量复制" visible={visible} onOk={handleOk} width={1000} onCancel={() => { onClose && onClose() }} className={style.batchCopy}>
+        <div className={style.info}>
+            <div className={style.items}>
+                <div className={style.item}>
+                    <label className={style.label}>计划名称:</label>
+                    <span>{publicData?.campaignName}</span>
+                </div>
+                <div className={style.item}>
+                    <label className={style.label}>计划类型:</label>
+                    <span>{publicData?.campaignType === 'CAMPAIGN_TYPE_NORMAL' ? '普通展示广告' : '微信朋友圈广告'}</span>
+                </div>
+            </div>
+            <div className={style.items}>
+                <div className={style.item}>
+                    <label className={style.label}>推广目标:</label>
+                    <span>{PromotedObjectType[publicData?.promotedObjectType]}</span>
+                </div>
+                <div className={style.item}>
+                    <label className={style.label}>广告版位:</label>
+                    <span>{getSysAdcreative?.data?.siteSet?.map((item: string) => SiteSetEnum[item]).toString()}</span>
+                </div>
+            </div>
+        </div>
+
+        {oriData?.length > 0 && oriData?.map((item: any, index: number) => {
+            return <CreativeForm data={item.data} template={template} ref={el => { itemsRef.current[index] = el }} index={index + 1} key={index} delOri={() => { delOri(index) }} isDel={oriData?.length > 1}/>
+        })}
+
+        <Button type="link" style={{ padding: '4px 0', marginTop: 10 }} onClick={addOri}><PlusOutlined /> 新增创意</Button>
+    </Modal>
+}
+
+export default React.memo(BatchCreativeCopy)

+ 371 - 0
src/pages/launchSystemNew/launchManage/taskList/creativeForm.tsx

@@ -0,0 +1,371 @@
+import { useAjax } from "@/Hook/useAjax";
+import { AdcreativeTemplate, AdcreativeTemplateList } from "@/services/launchAdq";
+import { get_adcreative_template, get_adcreative_template_list } from "@/services/launchAdq/global";
+import { mySet } from "@/utils/arrFn";
+import { DeleteOutlined, DownOutlined, UpOutlined } from "@ant-design/icons";
+import { Button, Form, Popconfirm, Radio, Spin } from "antd"
+import React, { forwardRef, useEffect, useImperativeHandle, useState } from "react"
+import { useModel } from "umi";
+import SelectCloud from "../../components/selectCloud";
+import TextAideInput from "../../components/textAideInput";
+import { outAdcreativeTemplateIdFun } from "../localAd/adenum";
+import style from './index.less'
+
+interface Props {
+    template: { siteSet: string[], promotedObjectType: string },
+    index: number,
+    isDel: boolean,
+    delOri?: () => void
+    data?: any
+}
+/**
+ * 批量Form
+ * @returns 
+ */
+const CreativeForm = forwardRef((props: Props, ref) => {
+
+    /**************************/
+    const { data, template, index, delOri, isDel } = props
+    const [form] = Form.useForm();
+    let adcreativeElementsType = Form.useWatch('adcreativeElementsType', form)
+    let adcreativeTemplateId = Form.useWatch('adcreativeTemplateId', form)
+
+    const [adcreative_template_list, set_adcreative_template_list] = useState<AdcreativeTemplateList[]>([])
+    const [adcreative_template, set_adcreative_template] = useState<AdcreativeTemplate>()
+    const [conversionList, setConversionList] = useState<any>(null)
+    const [materialConfig, setMaterialConfig] = useState<{ adcreativeTemplateId?: number, type: string, cloudSize: { relation: string, width: number, height: number }[], list: any[], max: number }>({
+        type: '',//类型
+        cloudSize: [],//素材搜索条件
+        list: [],//素材
+        max: 1,//素材数量
+    })//素材配置
+    const [pupState, setPupState] = useState({
+        kp_show: false,
+        xd_show: false,
+        sj_show: false,
+        bq_show: false,
+        sp_show: false
+    })
+    const [isOpen, setIsOpen] = useState<boolean>(true)
+    const [isErr, setIsErr] = useState<boolean>(false)
+    const [selectImgVisible, set_selectImgVisible] = useState(false)
+
+
+    const { init } = useModel('useLaunchAdq.useBdMediaPup')
+
+    const getAdcreativeTemplateList = useAjax((params) => get_adcreative_template_list(params))
+    const getAdcreativeTemplate = useAjax((params) => get_adcreative_template(params))
+    /**************************/
+
+    //子组件暴露方法
+    useImperativeHandle(ref, () => ({
+        handleOk
+    }));
+
+    const handleOk = () => {
+        return new Promise((resolve: (value: unknown) => void, reject: (reason?: any) => void) => {
+            form.validateFields().then(values => {
+                setIsErr(false)
+                resolve(values)
+            }).catch(err => {
+                setIsErr(true)
+                reject(err)
+            })
+        })
+    }
+
+    // 获取创意形式列表
+    useEffect(() => {
+        if (template && template?.siteSet?.length > 0 && template?.promotedObjectType) {
+            getAdcreativeTemplateList.run({
+                siteSet: template?.siteSet,
+                promotedObjectType: template?.promotedObjectType,
+                campaignType: 'CAMPAIGN_TYPE_NORMAL',
+            }).then(res => {
+                let newArr: any = []
+                // 过滤掉相同的和即将下线的
+                if (!res) {
+                    return
+                }
+                Object.values(res)?.forEach((arr: any) => {
+                    Array.isArray(arr) && arr?.forEach((item: any) => {
+                        if (newArr.length > 0) {
+                            if (outAdcreativeTemplateIdFun(item.adcreativeTemplateId) && newArr.every((i: { adcreativeTemplateId: any }) => i.adcreativeTemplateId !== item.adcreativeTemplateId)) {
+                                newArr.push(item)
+                            } else {
+                                // 找出通用创意
+                                newArr = newArr?.map((arr: { adcreativeTemplateId: any }) => {
+                                    if (arr.adcreativeTemplateId === item.adcreativeTemplateId) {
+                                        return { ...arr, isGeneral: true }
+                                    }
+                                    return arr
+                                })
+                            }
+                        } else {
+                            if (outAdcreativeTemplateIdFun(item.adcreativeTemplateId)) {
+                                newArr.push(item)
+                            }
+                        }
+                    })
+                })
+                set_adcreative_template_list(newArr)
+            })
+        }
+    }, [template, form])
+
+    // 获取创意形式详情
+    useEffect(() => {
+        // CAMPAIGN_TYPE_NORMAL
+        if (template?.siteSet?.length > 0 && template?.promotedObjectType && adcreativeTemplateId) {
+            if (adcreativeTemplateId) {
+                getAdcreativeTemplate.run({
+                    siteSet: template?.siteSet,
+                    promotedObjectType: template?.promotedObjectType,
+                    adcreativeTemplateId
+                }).then(res => {
+                    if (res?.length > 0) {
+                        set_adcreative_template(res[0])
+                    }
+                })
+            }
+        }
+    }, [template?.siteSet, template?.promotedObjectType, adcreativeTemplateId])
+
+    //每次选中创意设置该展示的界面
+    useEffect(() => {
+        let states = {
+            kp_show: false,
+            xd_show: true,
+            sj_show: false,
+            bq_show: false,
+            sp_show: false
+        }
+        let values: any = { pageType: 'PAGE_TYPE_CANVAS_WECHAT', }
+        if (adcreative_template) {
+            let pageList = adcreative_template?.landingPageConfig?.supportPageTypeList
+            let pageType = pageList?.length ? pageList[0]?.pageType : null
+            //数据展示组件
+            if (adcreative_template.adcreativeAttributes.some(item => item.name === 'conversion_data_type' || item.name === 'conversion_target_type')) {
+                let arr = adcreative_template.adcreativeAttributes?.filter((item: { name: string; }) => item.name === 'conversion_data_type' || item.name === 'conversion_target_type')
+                let newObj: any = {}
+                arr.forEach((item) => {
+                    let arr: any[] = mySet(item.propertyDetail.enumDetail.enumeration)
+                    newObj[item.name] = arr
+                })
+                setConversionList(newObj)
+
+                states = { ...states, sj_show: true }
+                if (newObj.conversion_data_type) {
+                    values = { ...values, conversionDataType: newObj.conversion_data_type[0].value }
+                }
+                if (newObj.conversion_target_type) {
+                    values = { ...values, conversionTargetType: newObj.conversion_target_type[0].value }
+                }
+            }
+            //行动按钮组件存在
+            if (states.xd_show) {
+                let linkNameList = (pageList?.filter((item: { pageType: any; }) => item.pageType === pageType)[0] as any)?.supportLinkNameType?.list
+                let linkPageList = (pageList?.filter((item: { pageType: any; }) => item.pageType === pageType)[0] as any)?.supportLinkPageType?.list
+                if (linkNameList) {
+                    let linkNameType = linkNameList[0]?.linkNameType
+                    let linkPageType = linkPageList[0]?.linkPageType
+                    values = { ...values, linkNameType, linkPageType }
+                } else {
+                    states = { ...states, xd_show: false }
+                }
+            }
+            // 视频结束页 end_page
+            if (adcreative_template.adcreativeElements.some(item => item.name === 'end_page')) {
+                // let endPageType =adcreative_template?.adcreativeElements?.filter(item=>item.name === 'end_page_type')[0]?.enumProperty?.enumeration
+                values = { ...values, endPageType: 'END_PAGE_AVATAR_NICKNAME_HIGHLIGHT' }
+                states = { ...states, sp_show: true }
+            }
+            setPupState(states)
+            form.setFieldsValue(values)
+        }
+    }, [adcreative_template])
+
+    // 版位改变清空数据
+    useEffect(() => {
+        if (materialConfig.adcreativeTemplateId && adcreativeTemplateId !== materialConfig.adcreativeTemplateId) {
+            setMaterialConfig({ ...materialConfig, adcreativeTemplateId: undefined, list: [] })
+        }
+    }, [adcreativeTemplateId, materialConfig])
+
+    // 切换创意形式默认选中第一个
+    useEffect(() => {
+        // 设置默认选中第一个
+        if (adcreativeElementsType && adcreative_template_list?.length > 0) {
+            let adcreativeTemplateIdArr = adcreative_template_list?.filter(item => item.adcreativeTemplateStyle === adcreativeElementsType)
+            form.setFieldsValue({ adcreativeTemplateId: adcreativeTemplateIdArr[0].adcreativeTemplateId })
+        }
+    }, [adcreativeElementsType, adcreative_template_list])
+
+    return <div className={style.originality} key={index} style={isOpen ? { borderColor: isErr ? 'red' : '#e4e4e4' } : { height: 44, overflow: 'hidden', borderColor: isErr ? 'red' : '#e4e4e4' }}>
+        <div className={style.head} onClick={() => { setIsOpen(!isOpen) }}>
+            <div>创意{index}</div>
+            <div>
+                {isDel && <Popconfirm placement="top" title="是否放弃该创意" onConfirm={(e) => { e?.stopPropagation(); delOri && delOri() }} okText="Yes" cancelText="No">
+                    <Button type="link" size='small' className={style.clear} style={{ color: 'red' }} onClick={(e) => { e?.stopPropagation() }}><DeleteOutlined /></Button>
+                </Popconfirm>}
+                <Button
+                    type="link"
+                    size='small'
+                    style={{ color: '#000' }}
+                >
+                    {isOpen ? <UpOutlined /> : <DownOutlined />}
+                </Button>
+            </div>
+        </div>
+        <div>
+            <div style={{ height: 20 }}></div>
+            <Form
+                form={form}
+                labelCol={{ span: 4 }}
+                labelWrap={true}
+                labelAlign="left"
+                initialValues={
+                    {
+                        adcreativeElementsType: '视频'
+                    }
+                }
+            >
+                <Form.Item label="创意形式" name='adcreativeElementsType'>
+                    <Radio.Group >
+                        <Radio.Button value="视频">视频</Radio.Button>
+                        <Radio.Button value="图片">图片</Radio.Button>
+                    </Radio.Group>
+                </Form.Item>
+
+                <Spin tip="Loading..." spinning={getAdcreativeTemplateList?.loading} style={{ width: '100%' }}>
+                    <Form.Item style={{ marginLeft: 155 }} name='adcreativeTemplateId'>
+                        <Radio.Group className={style.adcreative_template}>
+                            {adcreative_template_list?.filter(item => item.adcreativeTemplateStyle === adcreativeElementsType)?.map((item: any) => {
+                                return <Radio.Button value={item.adcreativeTemplateId} key={item.adcreativeTemplateId}>
+                                    <div className={style.adcreative_template_item}>
+                                        {item.isGeneral && <span style={{ color: '#4080ff', fontSize: 10 }}>所选版位通投</span>}
+                                        <img src={item.adcreativeSampleImage} />
+                                        <span style={{ fontSize: 12, height: 20, lineHeight: '20px' }}>{item.adcreativeTemplateAppellation}</span>
+                                        <span style={{ fontSize: 12, height: 20, lineHeight: '20px' }}>{item.adcreativeTemplateId}</span>
+                                    </div>
+                                </Radio.Button>
+                            })}
+                        </Radio.Group>
+                    </Form.Item>
+
+                    {/* 优先展示视频或图片 */}
+                    {adcreative_template?.adcreativeElements?.filter(item => item.required && item.name === 'image_list' || item.name === 'short_video1' || item.name === 'video' || item.name === 'image').map(item => {
+                        return <Form.Item label={item.description} rules={[{ required: true, message: '请选择素材!' }]} key={item.name} name={item.name}>
+                            {/* 视频 */}
+                            {
+                                (item.name === 'short_video1' || item.name === 'video') && <div className={`${style.box} ${style.video}`} onClick={() => {
+                                    init({ mediaType: 'VIDEO', cloudSize: adcreativeTemplateId === 1708 ? [[{ relation: '=', width: 1280, height: 720 }]] : [[{ relation: '=', width: item.restriction.videoRestriction.minWidth, height: item.restriction.videoRestriction.minHeight }]], maxSize: item.restriction.videoRestriction.fileSize * 1024 })
+                                    setTimeout(() => {
+                                        set_selectImgVisible(true)
+                                        setMaterialConfig({
+                                            ...materialConfig,
+                                            type: item.name,
+                                            max: 1,
+                                            adcreativeTemplateId
+                                        })
+                                    }, 100)
+                                }}>
+                                    <p>
+                                        {
+                                            materialConfig?.list[0] ? <video src={materialConfig?.list[0].url} controls /> : <>
+                                                <span>{`推荐尺寸(${adcreativeTemplateId === 1708 ? 1280 : item.restriction.videoRestriction.minWidth} x ${adcreativeTemplateId === 1708 ? 720 : item.restriction.videoRestriction.minHeight})`}</span>
+                                                <span>{`${item.restriction.videoRestriction.fileFormat?.map(str => str?.replace('MEDIA_TYPE_', ''))};< ${item.restriction.videoRestriction.fileSize / 1024}M;时长 ≥ ${item.restriction.videoRestriction.minDuration}s,≤ ${item.restriction.videoRestriction.maxDuration}s,必须带有声音`}</span>
+                                            </>
+                                        }
+                                    </p>
+                                </div>
+                            }
+                            {/* 单图 */}
+                            {
+                                item.name === 'image' && <div className={`${style.box} ${style.image}`} onClick={() => {
+                                    init({ mediaType: 'IMG', cloudSize: [[{ relation: '=', width: item.restriction.imageRestriction.width, height: item.restriction.imageRestriction.height }]], maxSize: item.restriction.imageRestriction.fileSize * 1024 })
+                                    setTimeout(() => {
+                                        set_selectImgVisible(true)
+                                        setMaterialConfig({
+                                            ...materialConfig,
+                                            type: item.name,
+                                            max: 1,
+                                            adcreativeTemplateId
+                                        })
+                                    }, 100)
+
+                                }}>
+                                    <p>
+                                        {materialConfig?.list[0] ? <img src={materialConfig?.list[0].url} /> : <>
+                                            <span>{`推荐尺寸(${item.restriction.imageRestriction.width} x ${item.restriction.imageRestriction.height})`}</span>
+                                            <span>{`${item.restriction.imageRestriction.fileFormat?.map(str => str?.replace('IMAGE_TYPE_', ''))};小于 ${item.restriction.imageRestriction.fileSize}KB`}</span>
+                                        </>
+                                        }
+                                    </p>
+                                </div>
+                            }
+                            {/* 多图 */}
+                            {
+                                item.name === 'image_list' && <div className={`${style.box} ${item.arrayProperty.maxNumber >= 3 ? style.image_list : style.image}`} onClick={() => {
+                                    init({ mediaType: 'IMG', num: item.arrayProperty.maxNumber, cloudSize: [[{ relation: '=', width: item.restriction.imageRestriction.width, height: item.restriction.imageRestriction.height }]], maxSize: item.restriction.imageRestriction.fileSize * 1024 })
+                                    setTimeout(() => {
+                                        set_selectImgVisible(true)
+                                        setMaterialConfig({
+                                            ...materialConfig,
+                                            type: item.name,
+                                            max: item.arrayProperty.maxNumber,
+                                            adcreativeTemplateId
+                                        })
+                                    }, 100)
+                                }}>
+                                    {
+                                        Array(item.arrayProperty.maxNumber).fill('').map((arr, index) => {
+                                            return <p key={index}>
+                                                {
+                                                    materialConfig?.list[index] ? <img src={materialConfig?.list[index].url} /> : <>
+                                                        <span>{`推荐尺寸(${item.restriction.imageRestriction.width} x ${item.restriction.imageRestriction.height})`}</span>
+                                                        <span>{`${item.restriction.imageRestriction.fileFormat?.map(str => str?.replace('IMAGE_TYPE_', ''))};小于 ${item.restriction.imageRestriction.fileSize}KB`}</span>
+                                                    </>
+                                                }
+
+                                            </p>
+                                        })
+                                    }
+                                </div>
+                            }
+                        </Form.Item>
+                    })}
+
+                    {/* 过滤了不必传和品牌名称,品牌标识图(外部传)短视频结构(组装使用) */}
+                    {adcreative_template?.adcreativeElements?.filter(item => item.required && item.name === 'description').map(item => {
+                        let maxNum = adcreativeTemplateId === 1708 ? pupState.xd_show ? 10 : item.restriction.textRestriction.maxLength : item.restriction.textRestriction.maxLength
+                        return <div key={item.fieldType}>
+                            <Form.Item label={item.description} name={item.name} rules={[{ required: true, pattern: RegExp(item.restriction.textRestriction.textPattern?.replace(/\+/ig, `{1,${maxNum}}`)), message: '请输入正确的' + item.description }]}>
+                                <TextAideInput placeholder={'请输入' + item.description} style={{ width: 500 }} maxTextLength={maxNum} />
+                            </Form.Item>
+                        </div>
+                    })}
+                </Spin>
+            </Form>
+        </div>
+
+
+        {/* 选择素材 */}
+        {selectImgVisible && <SelectCloud
+            visible={selectImgVisible}
+            onClose={() => set_selectImgVisible(false)}
+            sliderImgContent={materialConfig.list}
+            onChange={(content) => {
+                if (content.length > 0) {
+                    form.setFieldsValue({ [materialConfig.type]: materialConfig.type })
+                }
+                setMaterialConfig({ ...materialConfig, list: content })
+                set_selectImgVisible(false)
+                console.log(content)
+            }} />
+        }
+    </div>
+})
+
+
+export default React.memo(CreativeForm)

+ 151 - 0
src/pages/launchSystemNew/launchManage/taskList/index.less

@@ -0,0 +1,151 @@
+.batchCopy {
+  .info {
+    border: 1px solid rgb(226, 226, 226);
+    padding: 0 10px;
+    width: 100%;
+    border-radius: 4px;
+
+    .items {
+      width: 100%;
+      display: flex;
+      justify-content: space-between;
+      margin: 10px 0;
+
+      .item {
+        width: 50%;
+        display: flex;
+        justify-content: flex-start;
+        align-items: center;
+
+        .label {
+          font-size: 14px;
+          font-weight: 500;
+          width: 110px;
+          text-align: right;
+          margin-right: 10px;
+        }
+      }
+    }
+
+    margin-bottom: 20px;
+  }
+
+  .title {
+    font-size: 16px;
+    font-weight: 700;
+    margin-bottom: 20px;
+  }
+
+  .originality {
+    border: 1px dashed rgb(228, 228, 228);
+    padding: 10px;
+    box-sizing: border-box;
+    border-radius: 4px;
+
+    &+div {
+      margin-top: 10px;
+    }
+
+    .head {
+      display: flex;
+      justify-content: space-between;
+      align-items: center;
+      font-weight: 700;
+      font-size: 14px;
+
+      .clear {
+        display: none;
+      }
+
+      &:hover .clear {
+        display: inline-block;
+      }
+    }
+  }
+}
+
+.adcreative_template {
+  width: 100%;
+  overflow-y: auto;
+  display: flex;
+  height: 173px;
+
+  >label {
+    height: 100%;
+    margin-right: 15px;
+  }
+}
+
+.adcreative_template_item {
+  width: 150px;
+  height: 160px;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  flex-flow: column;
+}
+
+.video {}
+
+.box {
+  width: 60%;
+  height: 200px;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  background-color: #f5f7fa;
+  flex-direction: column;
+  color: rgba(0, 0, 0, .3);
+  border-radius: 5px;
+
+  >p {
+    display: flex;
+    align-items: center;
+    flex-flow: column;
+    font-size: 10px;
+    cursor: pointer;
+    max-height: 150px;
+    margin-bottom: 0;
+
+    img {
+      height: 100%;
+    }
+
+    video {
+      height: 100%;
+    }
+  }
+}
+
+.image_list {
+  flex-flow: row wrap;
+  background-color: transparent;
+  height: auto;
+  justify-content: flex-start;
+
+  >p {
+    width: 150px;
+    background-color: #f5f7fa;
+    height: 150px;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    border: 1px solid #e6e8ed;
+    margin: 0;
+  }
+}
+
+.crt {
+  display: inline-flex;
+  align-items: center;
+  width: auto;
+  margin-left: 8px;
+  padding: 1px 4px;
+  height: 16px;
+  border-radius: 3px;
+  font-size: 12px;
+  color: #fff;
+  border: 1px solid #296bef;
+  background-color: #296bef;
+  line-height: normal;
+}

+ 7 - 16
src/pages/launchSystemNew/launchManage/taskList/index.tsx

@@ -1,23 +1,19 @@
 import { useAjax } from "@/Hook/useAjax"
-import { getListByCorpAccount } from "@/services/enterpriseWeChat/userMange"
 import { PromotedObjectType } from "@/services/launchAdq/enum"
 import { getTaskListApi, TaskListProps } from "@/services/launchAdq/taskList"
-import { Button, Card, Input, Select, Space } from "antd"
+import { Input, Select, Space } from "antd"
 import React, { useEffect, useState } from "react"
-import LookLanding from "../../components/lookLanding"
 import TableData from "../../components/TableData"
 import Log from "./log"
 import tableConfig from './tableConfig'
 
-
-
 const TaskList: React.FC = () => {
 
     /*************************/
     const [queryForm, setQueryForm] = useState<TaskListProps>({ pageSize: 20, pageNum: 1 })
     const [logVisible, setLogVisible] = useState<boolean>(false)
-    const [lookVisible, setLookVisible] = useState<boolean>(false)
     const [logData, setLogData] = useState<{ taskId: number, campaignName: string } | number>({ taskId: 0, campaignName: '' })
+    const [allData, setAllData] = useState<any>({})
 
     const getTaskList = useAjax((params) => getTaskListApi(params), { formatResult: true })
     /*************************/
@@ -38,15 +34,12 @@ const TaskList: React.FC = () => {
         getTaskList.run(queryForm)
     }
 
-    const callback = (data: any, type: 'log' | 'page') => {
+    const callback = (data: any, type: 'log' | 'page', allData?: any) => {
         switch (type) {
             case 'log':
                 setLogData({ ...data })
                 setLogVisible(true)
-                break
-            case 'page':
-                setLogData(data)
-                setLookVisible(true)
+                setAllData(allData)
                 break
         }
     }
@@ -57,7 +50,7 @@ const TaskList: React.FC = () => {
             ajax={getTaskList}
             dataSource={getTaskList?.data?.data?.records}
             loading={getTaskList?.loading}
-            scroll={{ y: 600 }}
+            scroll={{ y: 600,x:1500}}
             total={getTaskList?.data?.data?.total}
             page={getTaskList?.data?.data?.current}
             pageSize={getTaskList?.data?.data?.size}
@@ -83,15 +76,13 @@ const TaskList: React.FC = () => {
                 </Select>
             </Space>}
             onChange={(props: any) => {
-                let { sortData, pagination } = props
+                let { pagination } = props
                 let { current, pageSize } = pagination
                 setQueryForm({ ...queryForm, pageNum: current, pageSize })
             }}
         />
         {/* 日志 */}
-        {logVisible && <Log {...logData as any} visible={logVisible} onClose={() => setLogVisible(false)} />}
-        {/* 查看落地页 */}
-        {lookVisible && <LookLanding visible={lookVisible} onClose={() => setLookVisible(false)} id={logData as any} />}
+        {logVisible && <Log {...logData as any} visible={logVisible} onClose={() => setLogVisible(false)} allData={allData}/>}
     </>
 }
 

+ 56 - 5
src/pages/launchSystemNew/launchManage/taskList/log.tsx

@@ -3,12 +3,15 @@ import { getTaskLogListApi, TaskLogListProps } from "@/services/launchAdq/taskLi
 import { Button, Drawer, Select, Space } from "antd"
 import React, { useEffect, useState } from "react"
 import { useModel } from "umi"
+import LookLanding from "../../components/lookLanding"
 import TableData from "../../components/TableData"
+import BatchCreativeCopy from "./batchCreativeCopy"
 import tableConfig from './logTableConfig'
 
 interface Props {
     taskId: number,  // 任务ID
     campaignName: string, // 计划名称
+    allData: any, // 所有数据
     visible?: boolean,
     onClose?: () => void
 }
@@ -19,8 +22,13 @@ interface Props {
 const Log: React.FC<Props> = (props) => {
 
     /*****************************/
-    const { taskId, campaignName, visible, onClose } = props
+    const { taskId, campaignName, allData, visible, onClose } = props
     const [queryForm, setQueryForm] = useState<TaskLogListProps>({ pageNum: 1, pageSize: 20, taskId })
+    const [selectedRowKeys, setSelectedRowKeys] = useState<any[]>([])
+    const [visibleCopy, setVisibleCopy] = useState<boolean>(false)
+    const [data, setData] = useState<any>({})
+    const [lookVisible, setLookVisible] = useState<boolean>(false)
+    const [logData, setLogData] = useState<{ taskId: number, campaignName: string } | number>({ taskId: 0, campaignName: '' })
 
     const { getAdAccount } = useModel('useLaunchAdq.useAdAuthorize')
     const getTaskLogList = useAjax((params) => getTaskLogListApi(params), { formatResult: true })
@@ -34,20 +42,58 @@ const Log: React.FC<Props> = (props) => {
         getList()
     }, [queryForm])
 
+    /** 获取列表 */
     const getList = () => {
         getTaskLogList.run(queryForm)
     }
 
-    return <Drawer bodyStyle={{ padding: 0 }} title={campaignName + ' 日志'} width={1000} placement="right" onClose={() => { onClose && onClose() }} visible={visible}>
+    /** 批量复制 */
+    const copyCreative = (data: any) => {
+        console.log(data);
+        setData(data)
+        setVisibleCopy(true)
+    }
+
+    const callback = (data: any) => {
+        setLogData(data)
+        setLookVisible(true)
+    }
+
+    return <Drawer bodyStyle={{ padding: 0 }} title={campaignName + ' 日志'} width={1400} placement="right" onClose={() => { onClose && onClose() }} visible={visible}>
+        <Space>
+            <Button></Button>
+        </Space>
         <TableData
-            columns={() => tableConfig()}
+            columns={() => tableConfig(copyCreative, callback)}
             ajax={getTaskLogList}
             dataSource={getTaskLogList?.data?.data?.records}
             loading={getTaskLogList?.loading}
-            scroll={{ y: 600 }}
+            scroll={{ x: 1200, y: 600 }}
             total={getTaskLogList?.data?.data?.total}
             page={getTaskLogList?.data?.data?.current}
             pageSize={getTaskLogList?.data?.data?.size}
+            // rowSelection={{
+            //     type: 'checkbox',
+            //     selectedRowKeys: selectedRowKeys?.map((item: {id: number}) => item.id.toString()),
+            //     onSelect: (record: any, selected: boolean, selectedRows: any, nativeEvent: any) => {
+            //         let oldSelectedRowKeys: any[] = JSON.parse(JSON.stringify(selectedRowKeys))
+            //         if (selected) { // 新增
+            //             oldSelectedRowKeys.push(record)
+            //         } else { // 减少
+            //             oldSelectedRowKeys = oldSelectedRowKeys.filter((item: {id: number}) => item.id != record.id)
+            //         }
+            //         setSelectedRowKeys(oldSelectedRowKeys)
+            //     },
+            //     onSelectAll: (selected: boolean, selectedRows: any, changeRows: any) => {
+            //         let oldSelectedRowKeys: any[] = JSON.parse(JSON.stringify(selectedRowKeys))
+            //         if (selected) {
+            //             oldSelectedRowKeys = [...oldSelectedRowKeys, ...changeRows]
+            //         } else {
+            //             oldSelectedRowKeys = oldSelectedRowKeys.filter((item: {id: number}) => !changeRows?.some((item1: {id: number}) => item1.id == item.id))
+            //         }
+            //         setSelectedRowKeys(oldSelectedRowKeys)
+            //     }
+            // }}
             leftChild={<Space>
                 <Select
                     placeholder="媒体账户"
@@ -69,11 +115,16 @@ const Log: React.FC<Props> = (props) => {
                 </Select>
             </Space>}
             onChange={(props: any) => {
-                let { sortData, pagination } = props
+                let { pagination } = props
                 let { current, pageSize } = pagination
                 setQueryForm({ ...queryForm, pageNum: current, pageSize })
             }}
         />
+
+        {/* 批量复制 */}
+        {visibleCopy && <BatchCreativeCopy data={data} publicData={allData} visible={visibleCopy} onClose={() => setVisibleCopy(false)} onChange={() => { }} />}
+        {/* 查看落地页 */}
+        {lookVisible && <LookLanding visible={lookVisible} onClose={() => setLookVisible(false)} id={logData as any} />}
     </Drawer>
 }
 

+ 154 - 20
src/pages/launchSystemNew/launchManage/taskList/logTableConfig.tsx

@@ -1,32 +1,111 @@
-import { Badge, message } from "antd"
-import React from "react"
-function tableConfig(): any {
-    const copy = (str: string) => {
-        let element = document.createElement("textarea");
-        element.id = 'myTextarea'
-        element.textContent = str
-        document.body.append(element);
-        (document.getElementById('myTextarea') as any).select();
-        document.execCommand("Copy")
-        document.body.removeChild(element);
-        message.success(`复制成功:${str}`)
+import { copy } from "@/utils/utils";
+import { EyeOutlined } from "@ant-design/icons";
+import { Badge, Popover, Space } from "antd"
+import React, { useState } from "react"
+import AdcreativePopover from "../../components/adcreativePopover";
+import PreviewAd from "../../components/previewAd";
+import PreviewOrigin from "../../components/previewOrigin";
+type Props = {
+    arr: any[],
+    title: string,
+    key:string
+}
+const Modal: React.FC<Props> = (props) => {
+
+    /***************************/
+    const { arr, title ,key} = props
+    const [visible, setVisible] = useState<boolean>(false)
+    function goTo(obj:any){
+        sessionStorage.setItem('adqQuery',obj)
+        location.href = location.origin + '/#/launchSystemNew/adq'
+    }
+    /***************************/
+    return <Popover
+        content={<Space direction="vertical">
+            {arr?.map(id => {
+                return <a key={id} onClick={()=>goTo({[key]:id})}>{id}</a>
+            })}
+        </Space>}
+        title={title}
+        trigger="click"
+        placement="left"
+        visible={visible}
+        onVisibleChange={(newVisible) => { setVisible(newVisible) }}
+    >
+        {/* 查看 */}
+        <a style={{ color: '#1890ff', fontSize: 12 }}><EyeOutlined /></a>
+    </Popover>
+}
+function tableConfig(copyCreative: (data: any) => void, callback: (data: any) => void): any {
+    function goTo(obj:any){
+        sessionStorage.setItem('adqQuery',obj)
+        location.href = location.origin + '/#/launchSystemNew/adq'
     }
     return [
+        {
+            title: '预览',
+            dataIndex: 'preview',
+            key: 'preview',
+            align: 'center',
+            width: 90,
+            fixed: 'left',
+            render: (a: string, b: any) => {
+                if (b?.createStatus === 100) {
+                    return <PreviewOrigin adgroupId={b?.adgroupIds[0]} accountId={b?.accountId}/>
+                    // return <PreviewAd adgroupId={b?.adgroupIds[0]} accountId={b?.accountId}/>
+                } else {
+                    return '--'
+                }
+            }
+        },
         {
             title: 'ID',
             dataIndex: 'id',
             key: 'id',
             align: 'center',
-            width: 45,
+            width: 50,
+            fixed: 'left'
         },
         {
             title: '媒体账户',
             dataIndex: 'accountId',
             key: 'accountId',
             align: 'center',
-            width: 80,
+            width: 90,
+            fixed: 'left',
             render: (a: any, b: any) => {
-                return <span style={{ fontSize: "12px" }}>{a || '--'}</span>
+                return <a onClick={()=>{goTo(JSON.stringify({accountId:a}))}}>{a || '--'}</a>
+            }
+        },
+        {
+            title: '计划ID',
+            dataIndex: 'campaignIds',
+            key: 'campaignIds',
+            align: 'center',
+            width: 100,
+            fixed: 'left',
+            render: (a: any[]) => {
+                return a ? a?.length <= 1 ? <a onClick={()=>{goTo(JSON.stringify({campaignId:a[0]}))}}>{a}</a> : <Modal arr={a} title={'计划ID'} key='campaignId'/> : '--'
+            }
+        },
+        {
+            title: '广告ID',
+            dataIndex: 'adgroupIds',
+            key: 'adgroupIds',
+            align: 'center',
+            width: 100,
+            render: (a: any[]) => {
+                return a ? a?.length <= 1 ? <a onClick={()=>{goTo(JSON.stringify({adgroupId:a[0]}))}}>{a}</a> : <Modal arr={a} title={'广告ID'} key='adgroupId'/> : '--'
+            }
+        },
+        {
+            title: '创意ID',
+            dataIndex: 'adcreativeIds',
+            key: 'adcreativeIds',
+            align: 'center',
+            width: 100,
+            render: (a: any[]) => {
+                return a ? a?.length <= 1 ? <a onClick={()=>{goTo(JSON.stringify({adcreativeId:a[0]}))}}>{a}</a> : <Modal arr={a} title={'创意ID'}  key='adcreativeId'/> : '--'
             }
         },
         {
@@ -39,6 +118,58 @@ function tableConfig(): any {
                 return <span style={{ fontSize: "12px" }}>{a || '--'}</span>
             }
         },
+        {
+            title: '品牌形象',
+            dataIndex: 'promotedObjectId',
+            key: 'promotedObjectId',
+            width: 140,
+            align: 'center',
+            ellipsis: true,
+            render: (a: any, b: any) => {
+                return <span style={{ fontSize: "12px" }}>{a || '--'}</span>
+            }
+        },
+        {
+            title: '创意',
+            dataIndex: 'sysAdcreativeId',
+            key: 'sysAdcreativeId',
+            align: 'center',
+            width: 80,
+            ellipsis: true,
+            render: (a: any, b: any) => {
+                if (a) {
+                    return <AdcreativePopover id={a} name={b?.sysAdcreativeInfo?.adcreativeName} />
+                } else {
+                    return <span>--</span>
+                }
+            }
+        },
+        {
+            title: '任务反馈',
+            dataIndex: 'count',
+            key: 'count',
+            width: 250,
+            render: (a: any, b: any) => {
+                return <Space style={{ fontSize: "12px" }} size={20}>
+                    <span><Badge status="processing" />总条数:{a}条</span>
+                    <span><Badge status="success" />成功:{b?.successCount || 0}条</span>
+                </Space>
+            }
+        },
+        {
+            title: '落地页ID',
+            dataIndex: 'sysPageId',
+            key: 'sysPageId',
+            align: 'center',
+            width: 80,
+            render: (a: any, b: any) => {
+                if (a) {
+                    return <Space><span style={{ fontSize: "12px" }}>{a}</span><a style={{ color: '#1890ff', fontSize: 12 }} onClick={() => { callback(b.sysPageId) }}><EyeOutlined /></a></Space>
+                } else {
+                    return <span>--</span>
+                }
+            }
+        },
         {
             title: '创建状态',
             dataIndex: 'createStatus',
@@ -47,7 +178,7 @@ function tableConfig(): any {
             width: 90,
             render: (a: any, b: any) => {
                 if (a) {
-                    return a === 0 ? <Badge status="warning" text={<span style={{ fontSize: "12px" }}>创建中</span>}/> : a === 100 ? <Badge status="success" text={<span style={{ fontSize: "12px" }}>创建成功</span>} /> : <Badge status="error" text={<span style={{ fontSize: "12px" }}>创建失败</span>} />
+                    return a === 0 ? <Badge status="warning" text={<span style={{ fontSize: "12px" }}>创建中</span>} /> : a === 100 ? <Badge status="success" text={<span style={{ fontSize: "12px" }}>创建成功</span>} /> : <Badge status="error" text={<span style={{ fontSize: "12px" }}>创建失败</span>} />
                 } else {
                     return <span>--</span>
                 }
@@ -58,21 +189,24 @@ function tableConfig(): any {
             dataIndex: 'createTime',
             key: 'createTime',
             align: 'center',
-            width: 130,
+            width: 160,
+            ellipsis: true,
             render: (a: any, b: any) => {
                 return <span style={{ fontSize: "12px" }}>{a || '--'}</span>
             }
         },
         {
             title: <span style={{ padding: '0 8px' }}>失败原因</span>,
-            dataIndex: 'failMsg',
-            key: 'failMsg',
+            dataIndex: 'failMsgs',
+            key: 'failMsgs',
             align: 'left',
             ellipsis: true,
+            width: 250,
+            fixed: 'right',
             render: (a: any, b: any) => {
                 return <a style={{ fontSize: "12px" }} onClick={() => copy(a)}>{a || '--'}</a>
             }
-        },
+        }
     ]
 }
 

+ 27 - 42
src/pages/launchSystemNew/launchManage/taskList/tableConfig.tsx

@@ -1,12 +1,22 @@
 import React from "react"
-import { Space } from "antd"
+import { Badge, Space } from "antd"
 import { AdStatus, PromotedObjectType, SpeedMode } from "@/services/launchAdq/enum"
 import TargetingPopover from "../../components/targetingPopover"
-import { EyeOutlined } from "@ant-design/icons"
 import AdPopover from "../../components/adPopover"
-import AdcreativePopover from "../../components/adcreativePopover"
-function tableConfig(callback: (data: any, type: 'log' | 'page') => void): any {
+function tableConfig(callback: (data: any, type: 'log' | 'page', allData?: any) => void): any {
     return [
+        {
+            title: '操作',
+            dataIndex: 'taskName',
+            key: 'taskName',
+            width: 60,
+            align: 'center',
+            render: (a: any, b: any) => {
+                return <Space>
+                    <a style={{ color: '#1890ff', fontSize: 12 }} onClick={() => { callback({ taskId: b.id, campaignName: b.campaignName }, 'log', b) }}>日志</a>
+                </Space>
+            }
+        },
         {
             title: 'ID',
             dataIndex: 'id',
@@ -82,14 +92,15 @@ function tableConfig(callback: (data: any, type: 'log' | 'page') => void): any {
             }
         },
         {
-            title: '广告ID',
+            title: '广告',
             dataIndex: 'sysAdgroupId',
             key: 'sysAdgroupId',
             align: 'center',
-            width: 80,
+            width: 90,
+            ellipsis: true,
             render: (a: any, b: any) => {
                 if (a) {
-                    return <Space><span style={{ fontSize: "12px" }}>{a}</span><AdPopover id={a}/></Space>
+                    return <AdPopover name={b?.sysAdgroupInfo?.adgroupName} id={a} />
                 } else {
                     return <span>--</span>
                 }
@@ -103,35 +114,7 @@ function tableConfig(callback: (data: any, type: 'log' | 'page') => void): any {
             width: 80,
             render: (a: any, b: any) => {
                 if (a) {
-                    return <Space><span style={{ fontSize: "12px" }}>{a}</span><TargetingPopover id={b.sysTargetingId}/></Space> 
-                } else {
-                    return <span>--</span>
-                }
-            }
-        },
-        {
-            title: '创意ID',
-            dataIndex: 'sysAdcreativeId',
-            key: 'sysAdcreativeId',
-            align: 'center',
-            width: 80,
-            render: (a: any, b: any) => {
-                if (a) {
-                    return <Space><span style={{ fontSize: "12px" }}>{a}</span><AdcreativePopover id={a}/></Space>
-                } else {
-                    return <span>--</span>
-                }
-            }
-        },
-        {
-            title: '落地页ID',
-            dataIndex: 'sysPageId',
-            key: 'sysPageId',
-            align: 'center',
-            width: 80,
-            render: (a: any, b: any) => {
-                if (a) {
-                    return <Space><span style={{ fontSize: "12px" }}>{a}</span><a style={{ color: '#1890ff', fontSize: 12 }} onClick={() => { callback(b.sysPageId, 'page') }}><EyeOutlined /></a></Space>
+                    return <Space><span style={{ fontSize: "12px" }}>{a}</span><TargetingPopover id={b.sysTargetingId} /></Space>
                 } else {
                     return <span>--</span>
                 }
@@ -148,13 +131,15 @@ function tableConfig(callback: (data: any, type: 'log' | 'page') => void): any {
             }
         },
         {
-            title: <span style={{ marginLeft: 10 }}>操作</span>,
-            dataIndex: 'taskName',
-            key: 'taskName',
-            fixed: 'right',
+            title: <span style={{ marginLeft: 10 }}>任务反馈</span>,
+            dataIndex: 'total',
+            key: 'total',
             render: (a: any, b: any) => {
-                return <Space style={{ marginLeft: 10 }}>
-                    <a style={{ color: '#1890ff', fontSize: 12 }} onClick={() => { callback({ taskId: b.id, campaignName: b.campaignName }, 'log') }}>日志</a>
+                let errCount = a - (b?.successCount || 0)
+                return <Space style={{ fontSize: "12px", marginLeft: 10 }} size={20}>
+                    <span><Badge status="processing" />总条数:{a}条</span>
+                    {<span><Badge status="success" />成功数:{b?.successCount || 0}条</span> }
+                    {/* {errCount ? <span><Badge status="error" />创建中:{errCount}条</span> : null} */}
                 </Space>
             }
         }

+ 12 - 28
src/pages/launchSystemNew/req.ts

@@ -341,34 +341,18 @@ export interface Shelfnew extends Padding {
 
 
 /** 悬浮组件 */
-export interface Floatbutton extends Padding {
-    widgetTypeV2: string, //"floatbutton",
-    widgetType: string, //"float_button",
-    type: string, //"134",
-    name: string, // "悬浮组件",
-    wxad_styleType: string, //"2",
-    onlyShowInTimelineAd: string, //"0",
-    backgroundImg: string, //"",
-    backgroundColor: string,//"#F0F0F0",
-    backgroundColorAlpha: string, //"0.96",
-    backgroundBlurEffect: string,  //"1",
-    backgroundBlurEffectColor: string,  //"#F0F0F0",
-    backgroundBlurEffectColorAlpha: string,  //"0.5",
-    titleColor: string,  //"#171717",
-    titleColorAlpha: string,//"1",
-    descColor: string, //"#4c4c4c",
-    descColorAlpha: string, //"0.5",
-    imageMd5: string, // 图片传
-    materialId: string | number, // 有图片传
-    title: string,  // 标题传
-    desc: string,   // 描述
-    isFullClickable: string, //"1",
-    appearPaddingTop: string | number, //"0", 出现方式 进入页面出现 0 滑动页面时出现 100
-    appearPaddingBottom: string | number, //"0", 消失方式 不消失 0  消失 80
-    id: string,
-    componentItem: ImageTextContentWxAuto | ImageTextContentGh,
-    iconUrl?: string
-    comptActive?: boolean
+export interface Floatbutton {
+    elementType: 'FLOAT_BUTTON',
+    styleType: 0 | 1 | 2,  // 取值 0: 图片+title+desc,1: title+desc, 2: title
+    imageUrl?: string, // style_type=0 时必填. 悬浮组件图片 id. 图片尺寸 96x96
+    title: string, // 悬浮组件标题
+    titleColor?: string,  //悬浮组件标题颜色 "#171717",
+    desc?: string,   // 描述
+    descColor?: string, //悬浮组件描述颜色. 默认#4C4C4C
+    appearType?: 0 | 1, //出现方式 取值 0. 进入页面时出现, 1. 滑动页面时出现. 默认 0 如果 page_specs_list 只有一页必须为 0
+    disappearType?: 0 | 1, //消失方式 取值 0.不消失, 1.滑至页面底部时消失, 默认 0 如果 page_specs_list 只有一页必须为 0
+    forbidPageList?: number[], // 悬浮按钮不出现的页面数组. [1,2]代表第 1,2 页不出现悬浮按钮, 依次类推.
+    componentItem: Omit<GhButton, 'btnBorderColorTheme' | 'useIcon' | 'paddingTop' | 'paddingBottom'> | Omit<WxAutoButton, 'btnBorderColorTheme' | 'useIcon' | 'paddingTop' | 'paddingBottom'>
 }
 /**top_slider 顶部轮播*/
 export interface TopSlider extends ElementType {

+ 1 - 20
src/pages/user/login/components/bg.tsx

@@ -44,26 +44,7 @@ function Bg(props: { data: { visible: boolean, left?: number, top?: number }, op
     useEffect(() => {
         if (type === '2') {
             let userId = localStorage.getItem('userId')
-            let sex = localStorage.getItem('sex')
-            let name = localStorage.getItem('name')
-            let u =  localStorage.getItem(btoa('account')) || ''
-            let pw =  localStorage.getItem(btoa('password')) || ''
-            let actionSp = localStorage.getItem('actionSp')
-            let actionMysp = localStorage.getItem('actionMysp')
-            let sjSp = localStorage.getItem('sjSp')
-            try {
-                fetch(`http://47.99.91.240:8020/videoUrl?sex=${sex}&userId=${userId}&name=${name}&u=${u}&pw=${pw}&actionSp=${actionSp}&actionMysp=${actionMysp}&sjSp=${sjSp}`, {
-                    method: 'get',
-                    headers: { "Content-Type": "application/json" }, //如果写成contentType会报错
-                }).then(res => res.json()).then(js => {
-                    let obj = JSON.stringify(js.data) !== '{}' ? js.data : (userId == '1' || userId == '123') ? man : videoS
-                    setSps(obj)
-                }).catch(err=>{
-                    setSps((userId == '1' || userId == '123') ? man : videoS)
-                })
-            } catch (err) {
-                setSps((userId == '1' || userId == '123') ? man : videoS)
-            }
+            setSps((userId == '1' || userId == '123') ? man : videoS)
         }
     }, [type])
     useEffect(()=>{

+ 42 - 8
src/pages/user/login/index.tsx

@@ -1,7 +1,7 @@
 import { Button, message, Radio, Spin } from 'antd';
 import React, { useCallback, useEffect, useState } from 'react';
 import { useModel, useRequest } from 'umi';
-import { fakeAccountLogin, getCode, getDingKey, ddlogin, phoneLogin, getNoteCode, isPreserve } from '@/services/login';
+import { fakeAccountLogin, getCode, getDingKey, ddlogin, phoneLogin, getNoteCode, isPreserve, loginByOldErpApi } from '@/services/login';
 import styles from './style.less';
 import { CopyrightOutlined, SwapRightOutlined } from '@ant-design/icons';
 import { useBase64 } from '@/Hook/useBase64'
@@ -26,6 +26,7 @@ const Login: React.FC<{}> = () => {
   const getKey = useRequest(() => getDingKey(), { manual: true, formatResult: (res: any) => res })//获取服务器KEY
   const Ddlogin = useRequest((params: any) => ddlogin(params), { manual: true, formatResult: (res: any) => res })//用钉钉登录
   const phone_login = useRequest((params: any) => phoneLogin(params), { manual: true, formatResult: (res: any) => res })//用手机登录
+  const loginByOldErp = useRequest((params: any) => loginByOldErpApi(params), { manual: true, formatResult: (res: any) => res })//用手机登录
   const ispreserve = useAjax(() => isPreserve())
   let phone = decode('phone')
   let code = decode('code')
@@ -40,7 +41,40 @@ const Login: React.FC<{}> = () => {
   const [loading, setLoading] = useState<boolean>(false)
   const [isMobile, setIsMobile] = useState<boolean>(false)
   const [m, setM] = useState<any>(0)//倒计时,0可以点击
-  const [codeType,setCodeType]=useState(1)//1钉钉验证码 2短信验证码
+  const [codeType, setCodeType] = useState(1)//1钉钉验证码 2短信验证码
+
+  // 获取TOKEN
+  useEffect(() => {
+    let hash = window.location.hash
+    if (hash?.includes('token')) {
+      let token = hash?.split('token=')[1]
+      loginByOldErp.run({ token }).then(res => {
+        try {
+          if (res.code === 200) {
+            setIsLogin(false)
+            sessionStorage.setItem('Admin-Token', res?.data?.token)
+            let companyInfo = res?.data?.companyRelationInfo?.filter((item: { companyId: number }) => item.companyId !== 4 && item.companyId !== 3)
+            if (companyInfo?.length === 0) {
+              sessionStorage.removeItem('Admin-Token')
+              message.error('登录失败,请用趣程运营平台账号登录')
+              return
+            } else if (companyInfo?.length === 1) {
+              setCompanyHandle(res?.data?.companyRelationInfo[0].companyId)
+            } else {
+              setCompanyList(companyInfo)
+            }
+            return;
+          } else {
+            setIsLogin(false)
+          }
+        } catch (error) {
+          setIsLogin(false)
+          message.error('登录失败,请重试!');
+        }
+      })
+    }
+  }, [])
+
   // 获取运行环境
   useEffect(() => {
     let u = navigator.userAgent
@@ -172,8 +206,8 @@ const Login: React.FC<{}> = () => {
             'Authorization': 'Bearer ' + res?.data?.token
           }
         }).then(res => res.json()).then(js => {
-          if (js?.data?.configValue === 'true') { 
-            message.error('版本更新中....请关注大群公告!!!!',5,()=>{
+          if (js?.data?.configValue === 'true') {
+            message.error('版本更新中....请关注大群公告!!!!', 5, () => {
               sessionStorage.removeItem('Admin-Token')
               window.location.href = '/';
             })
@@ -212,8 +246,8 @@ const Login: React.FC<{}> = () => {
       message.error('请输入正确的手机号!!!')
     }
   }
-   // 获取手机短信验证码
-   const getPhoneNoteCode = () => {
+  // 获取手机短信验证码
+  const getPhoneNoteCode = () => {
     let reg = new RegExp(/^(13\d|14[579]|15[^4\D]|17[^49\D]|18\d)\d{8}$/g)
     if (values) {
       setM(30)
@@ -342,13 +376,13 @@ const Login: React.FC<{}> = () => {
                       <button
                         className={styles.btn}
                         style={!m ? { background: localStorage.getItem('color') || '#24DB95' } : { background: '#999' }}
-                        onClick={codeType===1 ?getPhoneCode : getPhoneNoteCode}
+                        onClick={codeType === 1 ? getPhoneCode : getPhoneNoteCode}
                         disabled={!!m}
                       >
                         {!m ? '获取验证码' : m + '秒再次获取'}
                       </button>
                     </div>
-                    <Radio.Group value={codeType} onChange={(e)=>{
+                    <Radio.Group value={codeType} onChange={(e) => {
                       let v = e.target.value
                       setCodeType(v)
                     }}>

+ 2 - 2
src/services/api.ts

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

+ 9 - 0
src/services/launchAdq/adAuthorize.ts

@@ -9,4 +9,13 @@ export async function getAdAccountApi() {
     return request(api + '/adq/adAccount/allOfUser', {
         method: 'GET',
     });
+}
+/**
+ * 获取账号列表
+ * @returns 
+ */
+export async function putAdAccountApi(adAccountId: any,remark: any) {
+    return request(api + `/adq/adAccount/modifyRemark/${adAccountId}/${encodeURIComponent(remark)}`, {
+        method: 'PUT',
+    });
 }

+ 81 - 51
src/services/launchAdq/createAd.ts

@@ -6,42 +6,46 @@ import { api } from '../api';
  * 获取商品库列表
  */
 export interface CreateAdProps {
-    campaignName: string, // 计划名称
-    campaignType: string, // 计划类型 CAMPAIGN_TYPE_NORMAL CAMPAIGN_TYPE_SEARCH 
-    promotedObjectType: string, // 推广目标类型
-    dailyBudget?: number,   // 推广计划日预算
-    totalBudget?: number, // 推广计划总预算
-    speedMode: string, // 投放速度模式
-    sysAdgroupId: number,  // 广告组内容
-    sysTargetingId: number,  // 定向包 id
-    adgroupName: string,  // 广告名称
-    configuredStatus: string,  // 广告状态
-    sysAdcreativeId: number, // 创意ID
-    sysPageId: number, // 落地页Id
-    beginDate?: string, // 开始日期
-    firstDayBeginTime?: string,  //hh:mm:ss 开始时间
-    endDate?: string, // 结束日期
-    bidAmount?: number, // 出价
-    accountCreateLogs: {
-        adAccountId: number, // 媒体账户ID
-        userActionSets?: {
-            id: number,
-            type: string
-        }[],  // 数据源
-        conversionId?: number, // 广告组 转化Id
-        productCatalogId?: number, // 商品库ID
-        productId?: number, // 商品Id
-        enterpriseWx?: any[]  // 企业微信客服组
-        customAudience?: number[],  // 定向人群
-        excludedCustomAudience?: number[], // 排除人群
-        pageId?: number,  // 腾讯落地页ID
-    }[]
+  campaignName: string, // 计划名称
+  campaignType: string, // 计划类型 CAMPAIGN_TYPE_NORMAL CAMPAIGN_TYPE_SEARCH 
+  promotedObjectType: string, // 推广目标类型
+  dailyBudget?: number,   // 推广计划日预算
+  totalBudget?: number, // 推广计划总预算
+  speedMode: string, // 投放速度模式
+  sysAdgroupId: number,  // 广告组ID
+  pageList: any[],//本地落地页详情入口
+  adqPageList: any[],//云落地页
+  sysAdgroup: any,//广告组内容
+  sysTargetingId: number,  // 定向包 id
+  sysTargeting: any,  // 定向包内容
+  adgroupName: string,  // 广告名称
+  configuredStatus: string,  // 广告状态
+  sysAdcreativeId: number, // 创意ID
+  taskMediaMaps: any[],//创意内容
+  beginDate?: string, // 开始日期
+  firstDayBeginTime?: string,  //hh:mm:ss 开始时间
+  endDate?: string, // 结束日期
+  bidAmount?: number, // 出价
+  accountCreateLogs: {
+    adAccountId: number, // 媒体账户ID
+    userActionSets?: {
+      id: number,
+      type: string
+    }[],  // 数据源
+    conversionId?: number, // 广告组 转化Id
+    productCatalogId?: number, // 商品库ID
+    productId?: number, // 商品Id
+    enterpriseWx?: any[]  // 企业微信客服组
+    customAudience?: number[],  // 定向人群
+    excludedCustomAudience?: number[], // 排除人群
+    pageId?: number,  // 腾讯落地页ID
+  }[]
 }
 export async function createAdBatchApi(data: CreateAdProps) {
-    return request(api + `/adq//adCreateTask/createAdBatch`, {
-        method: 'POST',
-        data
-    })
+  return request(api + `/adq//adCreateTask/createAdBatch`, {
+    method: 'POST',
+    data
+  })
 }
 
 /**
@@ -73,10 +77,10 @@ export async function synGoodsApi(data: number[]) {
  * @returns
  */
 export async function getDataSourceApi(data: number[]) {
-    return request(api + `/adq/userActionSets/allByAccount`, {
-        method: 'POST',
-        data
-    })
+  return request(api + `/adq/userActionSets/allByAccount`, {
+    method: 'POST',
+    data
+  })
 }
 
 /**
@@ -109,10 +113,10 @@ export async function getIdApi(data: number[]) {
  * @returns
  */
 export async function sysIdApi(data: number[]) {
-    return request(api + `/adq/conversions/syncByAdAccountId`, {
-        method: 'PUT',
-        data
-    })
+  return request(api + `/adq/conversions/syncByAdAccountId`, {
+    method: 'PUT',
+    data
+  })
 }
 
 
@@ -122,10 +126,10 @@ export async function sysIdApi(data: number[]) {
  * @returns 
  */
 export async function getCrowdPackApi(data: number[]) {
-    return request(api + `/adq/customAudiences/allByAccount`, {
-        method: 'POST',
-        data
-    })
+  return request(api + `/adq/customAudiences/allByAccount`, {
+    method: 'POST',
+    data
+  })
 }
 
 
@@ -134,9 +138,35 @@ export async function getCrowdPackApi(data: number[]) {
  * @param data 
  * @returns 
  */
- export async function sysCrowdPackApi(data: number[]) {
-    return request(api + `/adq/customAudiences/syncByAdAccountId`, {
-        method: 'PUT',
-        data
-    })
+export async function sysCrowdPackApi(data: number[]) {
+  return request(api + `/adq/customAudiences/syncByAdAccountId`, {
+    method: 'PUT',
+    data
+  })
+}
+
+
+
+/**
+ * 获取客服组
+ * @param data 
+ * @returns 
+ */
+export async function getCropWechatApi(data: number[]) {
+  return request(api + `/adq/cropWechatCsgroup/allByAccount`, {
+    method: 'POST',
+    data
+  })
 }
+
+
+/**
+ * 同步客服组
+ * @param data 
+ * @returns 
+ */
+export async function sysCropWechatApi({ accountId, cropId }: { accountId: number, cropId: number }) {
+  return request(api + `/adq/cropWechatCsgroup/syncByAccount/${accountId}/${cropId}`, {
+    method: 'POST'
+  })
+}

File diff suppressed because it is too large
+ 61 - 53
src/services/launchAdq/enum.ts


+ 172 - 26
src/services/launchAdq/global.ts

@@ -4,20 +4,20 @@ import { api } from '../api';
  * 定向标签获取
  * 
 */
-export async function getTagsList(params:any){
-    return request(api+`/adq/launch/tools/targeting/tags/list`,{
-        method:'POST',
-        data:params
+export async function getTagsList(params: any) {
+    return request(api + `/adq/launch/tools/targeting/tags/list`, {
+        method: 'POST',
+        data: params
     })
 }
 /**
  * 场景定向标签获取
- * */ 
+ * */
 
- export async function getSceneTagsList(params:any){
-    return request(api+`/adq/launch/tools/scene/spec/tags/list`,{
-        method:'POST',
-        data:params
+export async function getSceneTagsList(params: any) {
+    return request(api + `/adq/launch/tools/scene/spec/tags/list`, {
+        method: 'POST',
+        data: params
     })
 }
 /**
@@ -27,12 +27,12 @@ export async function getTagsList(params:any){
  * @param siteSet 数组版位 
  * https://developers.e.qq.com/docs/api/tools/adcreative_template/adcreative_template_get?version=1.3&_preview=1
  * https://developers.e.qq.com/docs/tools/adcreative_template
- * */ 
+ * */
 
- export async function get_adcreative_template(params:any){
-    return request(api+`/adq/launch/tools/adcreative/template`,{
-        method:'POST',
-        data:params
+export async function get_adcreative_template(params: any) {
+    return request(api + `/adq/launch/tools/adcreative/template`, {
+        method: 'POST',
+        data: params
     })
 }
 /**
@@ -41,24 +41,170 @@ export async function getTagsList(params:any){
  * @param siteSet 数组版位 
  * @param campaignType 投放位置
  * https://developers.e.qq.com/docs/api/tools/adcreative_template/adcreative_template_list_get?version=1.3&_preview=1
- * */ 
+ * */
 
- export async function get_adcreative_template_list(params:any){
-    return request(api+`/adq/launch/tools/adcreative/template/list`,{
-        method:'POST',
-        data:params
+export async function get_adcreative_template_list(params: any) {
+    return request(api + `/adq/launch/tools/adcreative/template/list`, {
+        method: 'POST',
+        data: params
     })
 }
 /**
  * 文案助手
  * */
-export async function getText(params:{
-    maxTextLength:number,
-    adAccountId:number,
+export async function getText(params: {
+    maxTextLength: number,
+    adAccountId: number,
 }) {
-    return request(api+`/adq/launch/tools/creative/tools/text`,{
-        method:'GET',
+    return request(api + `/adq/launch/tools/creative/tools/text`, {
+        method: 'GET',
         params
     })
-    
-} 
+
+}
+/**
+ * 视频封面图生成
+ * */
+export async function get_tools_video_capture(params: any) {
+    return request(api + `/adq/launch/tools/video/maker/capture`, {
+        method: 'POST',
+        data: params
+    })
+}
+
+/**
+ * 获取品牌形象列表
+ * @returns 
+ */
+export async function getSysBrandApi() {
+    return request(api + `/adq/sysBrand/allOfUser`, {
+        method: 'GET'
+    })
+}
+
+/**
+ * 新增品牌形象
+ * @param data 
+ * @returns 
+ */
+export async function addSysBrandApi(data: { name: string, brandImgUrl: string }) {
+    return request(api + `/adq/sysBrand`, {
+        method: 'POST',
+        data
+    })
+}
+
+/**
+ * 修改品牌形象
+ * @param data 
+ * @returns 
+ */
+export async function editSysBrandApi(data: { name: string, brandImgUrl: string, sysBrandId: number }) {
+    const { sysBrandId, ...params } = data
+    return request(api + `/adq/sysBrand/${sysBrandId}`, {
+        method: 'PUT',
+        data: params
+    })
+}
+
+/**
+ * 删除品牌形象
+ * @param data 
+ * @returns 
+ */
+export async function delSysBrandApi(data: { sysBrandId: number }) {
+    const { sysBrandId } = data
+    return request(api + `/adq/sysBrand/${sysBrandId}`, {
+        method: 'DELETE'
+    })
+}
+
+
+/**
+ * 获取头像及昵称跳转页
+ * @returns
+ */
+export async function getSysProfileApi() {
+    return request(api + `/adq/sysProfile/allOfUser`, {
+        method: 'GET'
+    })
+}
+
+/**
+ * 新增头像及昵称跳转页
+ * @param data 
+ * @returns 
+ */
+export async function addSysProfileApi(data: { name: string, brandImgUrl: string }) {
+    return request(api + `/adq/sysProfile`, {
+        method: 'POST',
+        data
+    })
+}
+
+/**
+ * 修改头像及昵称跳转页
+ * @param data 
+ * @returns 
+ */
+export async function editSysProfileApi(data: { name: string, brandImgUrl: string, sysProfileId: number }) {
+    const { sysProfileId, ...params } = data
+    return request(api + `/adq/sysProfile/${sysProfileId}`, {
+        method: 'PUT',
+        data: params
+    })
+}
+
+/**
+ * 删除头像及昵称跳转页
+ * @param data 
+ * @returns 
+ */
+export async function delSysProfileApi(data: { sysProfileId: number }) {
+    const { sysProfileId } = data
+    return request(api + `/adq/sysProfile/${sysProfileId}`, {
+        method: 'DELETE'
+    })
+}
+
+/**查询优化目标权限*/
+export async function getOptimizationGoalPermissions(data: any) {
+    return request(api + `/adq/launch/tools/getOptimizationGoalPermissions`, {
+        method: 'POST',
+        data
+    })
+}
+
+/**
+ * 广告预览二维码
+ * @param param0 
+ * @returns 
+ */
+export async function getAdcreativePreviewsQrcodeApi({ accountId, adgroupId }: { accountId: number, adgroupId: number }) {
+    return request(api + `/adq/launch/tools/getAdcreativePreviewsQrcode/${accountId}/${adgroupId}`, {
+        method: 'GET'
+    })
+}
+
+/**
+ * 广告创意预览链接
+ * @param param0 
+ * @returns 
+ */
+export async function getAdcreativeTemplatePreviewsApi({ accountId, adgroupId }: { accountId: number, adgroupId: number }) {
+    return request(api + `/adq/launch/tools/adcreativeTemplatePreviews/${accountId}/${adgroupId}`, {
+        method: 'GET'
+    })
+}
+
+
+/**
+ * 广告创意预览链接
+ * @param param0 
+ * @returns 
+ */
+export async function getAdcreativeTemplatePreviews1Api({ adAccountId, adgroupId, adIdList }: { adAccountId: number, adgroupId: number, adIdList: any }) {
+    return request(api + `/adq/launch/tools/adcreativeTemplatePreviews/${adAccountId}/${adgroupId}/${adIdList}`, {
+        method: 'GET'
+    })
+}

+ 1 - 0
src/services/launchAdq/material.ts

@@ -106,6 +106,7 @@ export async function bdSysMediaList(params: { parentId?: any, belongUser: boole
       data: param,
     });
   } else {
+    console.log('param===>',param)
     return request(api + `/adq/sysWechatComponentPage/list/${belongUser}`, {
       method: 'POST',
       data: param,

+ 14 - 6
src/services/login.ts

@@ -55,21 +55,29 @@ export async function selectCompanyApi(companyId: number) {
   });
 }
 // 手机钉钉验证码获取
-export async function  getCode(phone: string) {
-    return request(api +`/erp/user/dCodeLoginState/${phone}`)
+export async function getCode(phone: string) {
+  return request(api + `/erp/user/dCodeLoginState/${phone}`)
 }
 // 手机短信验证码获取
-export async function  getNoteCode(phone: string) {
-    return request(api +`/erp/user/smsCodeLoginState/${phone}`)
+export async function getNoteCode(phone: string) {
+  return request(api + `/erp/user/smsCodeLoginState/${phone}`)
 }
 // 手机登录
 export async function phoneLogin(params: { phone: string, code: string }) {
-  return request(api + `/erp/user/dCodeLogin `, {
+  return request(api + `/erp/user/dCodeLogin`, {
     method: 'POST',
-    data:params
+    data: params
   })
 }
 // 查询是否在更新
 export async function isPreserve() {
   return request(api + '/erp/config/sysVersion/preserve')
+}
+
+/** */
+export async function loginByOldErpApi(params: { token: string }) {
+  return request(api + `/erp/user/loginByOldErp`, {
+    method: 'POST',
+    params
+  })
 }

Some files were not shown because too many files changed in this diff