Kaynağa Gözat

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

wjx 22 saat önce
ebeveyn
işleme
3df896f136
31 değiştirilmiş dosya ile 2654 ekleme ve 1070 silme
  1. 11 0
      src/assets/x-miaosi-mini-brand.svg
  2. 60 21
      src/pages/launchSystemV3/adqv3/ad/index.tsx
  3. 21 2
      src/pages/launchSystemV3/adqv3/ad/tableConfig.tsx
  4. 32 31
      src/pages/launchSystemV3/adqv3/config.ts
  5. 9 1
      src/pages/launchSystemV3/adqv3/const.tsx
  6. 99 56
      src/pages/launchSystemV3/components/AdgroupTooltip/index.tsx
  7. 41 17
      src/pages/launchSystemV3/components/ConversionSelect/index.tsx
  8. 2 1
      src/pages/launchSystemV3/components/PageModal/tableConfig.tsx
  9. 1 1
      src/pages/launchSystemV3/components/TargetingTooltip/index.tsx
  10. 83 1
      src/pages/launchSystemV3/tencentAdPutIn/const.ts
  11. 3 2
      src/pages/launchSystemV3/tencentAdPutIn/create/Ad/adgroupsAdSetting.tsx
  12. 136 88
      src/pages/launchSystemV3/tencentAdPutIn/create/Ad/adgroupsMarketingContent.tsx
  13. 267 144
      src/pages/launchSystemV3/tencentAdPutIn/create/Ad/adgroupsPrice.tsx
  14. 63 0
      src/pages/launchSystemV3/tencentAdPutIn/create/Ad/adgroupsPutInType.tsx
  15. 25 20
      src/pages/launchSystemV3/tencentAdPutIn/create/Ad/adgroupsSitSet.tsx
  16. 38 0
      src/pages/launchSystemV3/tencentAdPutIn/create/Ad/deliveryMethod.tsx
  17. 32 0
      src/pages/launchSystemV3/tencentAdPutIn/create/Ad/index.less
  18. 114 64
      src/pages/launchSystemV3/tencentAdPutIn/create/Ad/index.tsx
  19. 15 1
      src/pages/launchSystemV3/tencentAdPutIn/create/Ad/newCreateAd.tsx
  20. 1 1
      src/pages/launchSystemV3/tencentAdPutIn/create/Dynamic/creativeTemplateContent.tsx
  21. 2 2
      src/pages/launchSystemV3/tencentAdPutIn/create/Dynamic/newDynamic.tsx
  22. 580 575
      src/pages/launchSystemV3/tencentAdPutIn/create/Target/addTarget.tsx
  23. 23 1
      src/pages/launchSystemV3/tencentAdPutIn/create/Target/index.tsx
  24. 32 4
      src/pages/launchSystemV3/tencentAdPutIn/create/Target/selectTarget.tsx
  25. 14 2
      src/pages/launchSystemV3/tencentAdPutIn/create/Target/tableConfig.tsx
  26. 15 2
      src/pages/launchSystemV3/tencentAdPutIn/create/addDynamic.tsx
  27. 10 4
      src/pages/launchSystemV3/tencentAdPutIn/create/index.tsx
  28. 33 3
      src/pages/launchSystemV3/tencentAdPutIn/create/tableConfig.tsx
  29. 842 21
      src/pages/launchSystemV3/tencentAdPutIn/rules.ts
  30. 40 4
      src/pages/launchSystemV3/tencentAdPutIn/typings.d.ts
  31. 10 1
      src/utils/utils.ts

+ 11 - 0
src/assets/x-miaosi-mini-brand.svg

@@ -0,0 +1,11 @@
+<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g clip-path="url(#clip0_11257_16153)">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M7.39286 1.39285C7.39286 3.16715 8.83283 4.60715 10.6072 4.60715C10.9607 4.60715 11.25 4.89643 11.25 5.25C11.25 5.60357 10.9607 5.89286 10.6072 5.89286C8.83283 5.89286 7.39286 7.33286 7.39286 9.10718C7.39286 9.46073 7.10357 9.75 6.75 9.75C6.39643 9.75 6.10715 9.46073 6.10715 9.10718C6.10715 7.33286 4.66715 5.89286 2.89286 5.89286C2.53928 5.89286 2.25 5.60357 2.25 5.25C2.25 4.89643 2.53928 4.60715 2.89286 4.60715C4.66715 4.60715 6.10715 3.16715 6.10715 1.39285C6.10715 1.03928 6.39643 0.75 6.75 0.75C7.10357 0.75 7.39286 1.03928 7.39286 1.39285ZM2.24799 8.29583C2.27645 8.22975 2.29973 8.1609 2.31731 8.0898C2.34275 7.9869 2.35625 7.87935 2.35625 7.76873C2.35625 7.61873 2.475 7.5 2.625 7.5C2.775 7.5 2.89375 7.61873 2.89375 7.76873C2.89375 7.87935 2.90726 7.9869 2.9327 8.0898C2.95028 8.1609 2.97356 8.22975 3.00201 8.29583C3.13732 8.61023 3.3898 8.86268 3.70414 8.99798C3.77026 9.02648 3.83911 9.04973 3.91019 9.06728C4.01307 9.09278 4.12061 9.10628 4.23125 9.10628C4.38125 9.10628 4.5 9.225 4.5 9.375C4.5 9.525 4.38125 9.64373 4.23125 9.64373C4.12061 9.64373 4.01307 9.65723 3.91019 9.68273C3.83911 9.70028 3.77026 9.72353 3.70414 9.75203C3.3898 9.88733 3.13732 10.1398 3.00201 10.4542C2.97356 10.5203 2.95028 10.5891 2.9327 10.6602C2.90726 10.7631 2.89375 10.8707 2.89375 10.9813C2.89375 11.1313 2.775 11.25 2.625 11.25C2.475 11.25 2.35625 11.1313 2.35625 10.9813C2.35625 10.8707 2.34275 10.7631 2.31731 10.6602C2.29973 10.5891 2.27645 10.5203 2.24799 10.4542C2.11268 10.1398 1.8602 9.88733 1.54586 9.75203C1.47974 9.72353 1.41089 9.70028 1.33982 9.68273C1.23693 9.65723 1.12939 9.64373 1.01875 9.64373C0.868748 9.64373 0.75 9.525 0.75 9.375C0.75 9.225 0.868748 9.10628 1.01875 9.10628C1.12939 9.10628 1.23693 9.09278 1.33982 9.06728C1.41089 9.04973 1.47974 9.02648 1.54586 8.99798C1.8602 8.86268 2.11268 8.61023 2.24799 8.29583Z" fill="#455066" fill-opacity="0.25"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M7.39286 1.39285C7.39286 3.16715 8.83283 4.60715 10.6072 4.60715C10.9607 4.60715 11.25 4.89643 11.25 5.25C11.25 5.60357 10.9607 5.89286 10.6072 5.89286C8.83283 5.89286 7.39286 7.33286 7.39286 9.10718C7.39286 9.46073 7.10357 9.75 6.75 9.75C6.39643 9.75 6.10715 9.46073 6.10715 9.10718C6.10715 7.33286 4.66715 5.89286 2.89286 5.89286C2.53928 5.89286 2.25 5.60357 2.25 5.25C2.25 4.89643 2.53928 4.60715 2.89286 4.60715C4.66715 4.60715 6.10715 3.16715 6.10715 1.39285C6.10715 1.03928 6.39643 0.75 6.75 0.75C7.10357 0.75 7.39286 1.03928 7.39286 1.39285ZM2.24799 8.29583C2.27645 8.22975 2.29973 8.1609 2.31731 8.0898C2.34275 7.9869 2.35625 7.87935 2.35625 7.76873C2.35625 7.61873 2.475 7.5 2.625 7.5C2.775 7.5 2.89375 7.61873 2.89375 7.76873C2.89375 7.87935 2.90726 7.9869 2.9327 8.0898C2.95028 8.1609 2.97356 8.22975 3.00201 8.29583C3.13732 8.61023 3.3898 8.86268 3.70414 8.99798C3.77026 9.02648 3.83911 9.04973 3.91019 9.06728C4.01307 9.09278 4.12061 9.10628 4.23125 9.10628C4.38125 9.10628 4.5 9.225 4.5 9.375C4.5 9.525 4.38125 9.64373 4.23125 9.64373C4.12061 9.64373 4.01307 9.65723 3.91019 9.68273C3.83911 9.70028 3.77026 9.72353 3.70414 9.75203C3.3898 9.88733 3.13732 10.1398 3.00201 10.4542C2.97356 10.5203 2.95028 10.5891 2.9327 10.6602C2.90726 10.7631 2.89375 10.8707 2.89375 10.9813C2.89375 11.1313 2.775 11.25 2.625 11.25C2.475 11.25 2.35625 11.1313 2.35625 10.9813C2.35625 10.8707 2.34275 10.7631 2.31731 10.6602C2.29973 10.5891 2.27645 10.5203 2.24799 10.4542C2.11268 10.1398 1.8602 9.88733 1.54586 9.75203C1.47974 9.72353 1.41089 9.70028 1.33982 9.68273C1.23693 9.65723 1.12939 9.64373 1.01875 9.64373C0.868748 9.64373 0.75 9.525 0.75 9.375C0.75 9.225 0.868748 9.10628 1.01875 9.10628C1.12939 9.10628 1.23693 9.09278 1.33982 9.06728C1.41089 9.04973 1.47974 9.02648 1.54586 8.99798C1.8602 8.86268 2.11268 8.61023 2.24799 8.29583Z" fill="#296BEF"/>
+</g>
+<defs>
+<clipPath id="clip0_11257_16153">
+<rect width="12" height="12" fill="white"/>
+</clipPath>
+</defs>
+</svg>

+ 60 - 21
src/pages/launchSystemV3/adqv3/ad/index.tsx

@@ -10,7 +10,7 @@ import UpdateAd from "./updateAd";
 import TableData from "@/pages/launchSystemNew/components/TableData";
 import AddDynamic from "../../tencentAdPutIn/create/addDynamic";
 import { arraysHaveSameValues } from "@/utils/utils";
-import { MARKETING_CARRIER_TYPE_ENUM, MARKETING_GOAL_ENUM, MARKETING_SUB_GOAL_ENUM, MARKETING_TARGET_TYPE_ENUM, MARKETING_TARGET_TYPE_GAME_ENUM, SITE_SET_ENUM } from "../../tencentAdPutIn/const";
+import { MARKETING_CARRIER_TYPE_ENUM, MARKETING_GOAL_ENUM, MARKETING_SUB_GOAL_ENUM, MARKETING_TARGET_TYPE_ENUM, MARKETING_TARGET_TYPE_GAME_ENUM, SITE_SET_ENUM, SMART_DELIVERY_GOAL_ENUM, SMART_DELIVERY_PLATFORM_ENUM } from "../../tencentAdPutIn/const";
 import Log from "../components/log";
 import '../../tencentAdPutIn/index.less'
 import UserTactics from "../../tencentAdPutIn/create/TacticsS/userTactics";
@@ -303,7 +303,7 @@ const Ad: React.FC<ADQV3.AdProps> = ({ userId, creativeHandle }) => {
                                     {
                                         label: <span style={{ display: 'inline-block', width: 120 }}>修改出价</span>,
                                         key: '1',
-                                        disabled: selectedRows.length === 0,
+                                        disabled: selectedRows.length === 0 || selectedRows[0]?.smartDeliveryPlatform,
                                         onClick: () => { setUpdateDate({ visible: true, type: '修改出价' }) }
                                     },
                                     {
@@ -333,13 +333,13 @@ const Ad: React.FC<ADQV3.AdProps> = ({ userId, creativeHandle }) => {
                                     {
                                         label: '一键起量',
                                         key: '6',
-                                        disabled: selectedRows.length === 0,
+                                        disabled: selectedRows.length === 0 || selectedRows[0]?.smartDeliveryPlatform,
                                         onClick: () => { setAutoAcqVisible(true) }
                                     },
                                     {
                                         label: '关闭智能定向',
                                         key: '7',
-                                        disabled: selectedRows.length === 0,
+                                        disabled: selectedRows.length === 0 || selectedRows[0]?.smartDeliveryPlatform,
                                         onClick: () => { setUpdateDate({ visible: true, type: '关闭智能定向' }) }
                                     }
                                 ]
@@ -354,14 +354,14 @@ const Ad: React.FC<ADQV3.AdProps> = ({ userId, creativeHandle }) => {
                                 </Space>
                             </Button>
                         </Dropdown></Col>
-                        <Col>
-                            <AutoAcquisitionSetTask 
+                        {!selectedRows[0]?.smartDeliveryPlatform && <Col>
+                            <AutoAcquisitionSetTask
                                 selectAdList={selectedRows}
                                 onChange={(val) => {
                                     if (val) getAdqV3AdList.refresh()
                                 }}
                             />
-                        </Col>
+                        </Col>}
                     </> : handleType === 2 ? <>
                         <Col><UserTactics
                             type="updateAd"
@@ -381,12 +381,20 @@ const Ad: React.FC<ADQV3.AdProps> = ({ userId, creativeHandle }) => {
                                 </Tooltip>
                                 {selectedRows?.length > 0 && <div style={{ maxWidth: '380px' }}>
                                     <Text type="danger" ellipsis={{ tooltip: true }} strong style={{ fontSize: 12 }}>
-                                        {`当前广告选择:
+                                        {selectedRows[0]?.smartDeliveryPlatform ? `
+                                            当前广告选择:
+                                            投放场景:${SMART_DELIVERY_PLATFORM_ENUM[selectedRows[0].smartDeliveryPlatform as keyof typeof SMART_DELIVERY_PLATFORM_ENUM]},
+                                            营销目的:${['GAME', 'GAME_IAA'].includes(useType) ? MARKETING_SUB_GOAL_ENUM[selectedRows?.[0]?.marketingSubGoal as keyof typeof MARKETING_SUB_GOAL_ENUM] : MARKETING_GOAL_ENUM[selectedRows?.[0]?.marketingGoal as keyof typeof MARKETING_GOAL_ENUM]},
+                                            营销目的:${['GAME', 'GAME_IAA'].includes(useType) ? MARKETING_SUB_GOAL_ENUM[selectedRows?.[0]?.marketingSubGoal as keyof typeof MARKETING_SUB_GOAL_ENUM] : MARKETING_GOAL_ENUM[selectedRows?.[0]?.marketingGoal as keyof typeof MARKETING_GOAL_ENUM]},
+                                            推广产品类型:${['GAME', 'GAME_IAA'].includes(useType) ? MARKETING_TARGET_TYPE_GAME_ENUM[selectedRows?.[0]?.marketingTargetType as keyof typeof MARKETING_TARGET_TYPE_GAME_ENUM] : MARKETING_TARGET_TYPE_ENUM[selectedRows?.[0]?.marketingTargetType as keyof typeof MARKETING_TARGET_TYPE_ENUM]},
+                                            营销载体类型:${MARKETING_CARRIER_TYPE_ENUM[selectedRows?.[0]?.marketingCarrierType as keyof typeof MARKETING_CARRIER_TYPE_ENUM]},
+                                            投放目标:${SMART_DELIVERY_GOAL_ENUM[selectedRows[0]?.smartDeliverySceneSpec?.smartDeliveryGoal as keyof typeof SMART_DELIVERY_GOAL_ENUM]?.title},
+                                        `: `当前广告选择:
                                         营销目的:${['GAME', 'GAME_IAA'].includes(useType) ? MARKETING_SUB_GOAL_ENUM[selectedRows?.[0]?.marketingSubGoal as keyof typeof MARKETING_SUB_GOAL_ENUM] : MARKETING_GOAL_ENUM[selectedRows?.[0]?.marketingGoal as keyof typeof MARKETING_GOAL_ENUM]},
                                         推广产品类型:${['GAME', 'GAME_IAA'].includes(useType) ? MARKETING_TARGET_TYPE_GAME_ENUM[selectedRows?.[0]?.marketingTargetType as keyof typeof MARKETING_TARGET_TYPE_GAME_ENUM] : MARKETING_TARGET_TYPE_ENUM[selectedRows?.[0]?.marketingTargetType as keyof typeof MARKETING_TARGET_TYPE_ENUM]},
                                         营销载体类型:${MARKETING_CARRIER_TYPE_ENUM[selectedRows?.[0]?.marketingCarrierType as keyof typeof MARKETING_CARRIER_TYPE_ENUM]},
                                         版位选择:${selectedRows?.[0]?.automaticSiteEnabled ? '自动版位' : '选择特定版位'},
-                                        ${!selectedRows?.[0]?.automaticSiteEnabled && `广告版位:${selectedRows?.[0]?.siteSet.map((item: string | number) => SITE_SET_ENUM[item as keyof typeof SITE_SET_ENUM]).toString()}`}
+                                        ${!selectedRows?.[0]?.automaticSiteEnabled && `广告版位:${selectedRows?.[0]?.siteSet?.map((item: string | number) => SITE_SET_ENUM[item as keyof typeof SITE_SET_ENUM]).toString()}`}
                                         `}
                                     </Text>
                                 </div>}
@@ -408,9 +416,15 @@ const Ad: React.FC<ADQV3.AdProps> = ({ userId, creativeHandle }) => {
                 // hideSelectAll: handleType === 3,
                 getCheckboxProps: (record: any) => {
                     if (handleType === 2 && selectedRows?.length > 0) {
-                        const { siteSet, marketingCarrierType, marketingGoal, marketingSubGoal, marketingTargetType, sceneSpec, automaticSiteEnabled } = selectedRows[0]
+                        const { siteSet, marketingCarrierType, marketingGoal, marketingSubGoal, marketingTargetType, sceneSpec, automaticSiteEnabled, smartDeliveryPlatform, smartDeliverySceneSpec } = selectedRows[0]
                         return {
-                            disabled: record.isDeleted || !(
+                            disabled: record.isDeleted || smartDeliveryPlatform ? !(
+                                record?.marketingGoal === marketingGoal &&
+                                record?.marketingSubGoal === marketingSubGoal &&
+                                record?.marketingTargetType === marketingTargetType &&
+                                record?.smartDeliverySceneSpec?.smartDeliveryGoal === smartDeliverySceneSpec?.smartDeliveryGoal &&
+                                record?.smartDeliveryPlatform === smartDeliveryPlatform
+                            ) : !(
                                 record?.marketingGoal === marketingGoal &&  // 营销内容
                                 record?.marketingSubGoal === marketingSubGoal &&  // 二级营销内容
                                 record?.marketingCarrierType === marketingCarrierType && // 营销载体
@@ -420,6 +434,11 @@ const Ad: React.FC<ADQV3.AdProps> = ({ userId, creativeHandle }) => {
                                 arraysHaveSameValues(record?.sceneSpec?.wechatPosition || [], sceneSpec?.wechatPosition || []) // 微信公众号与小程序定投
                             )
                         }
+                    } else if (handleType === 1 && selectedRows?.length > 0) {
+                        const { smartDeliveryPlatform } = selectedRows[0]
+                        return {
+                            disabled: record.isDeleted || smartDeliveryPlatform ? !record?.smartDeliveryPlatform : record?.smartDeliveryPlatform
+                        }
                     } else {
                         return {
                             disabled:
@@ -448,16 +467,36 @@ const Ad: React.FC<ADQV3.AdProps> = ({ userId, creativeHandle }) => {
                             if (index === -1) {
                                 let data: any = { ...item }
                                 if (handleType === 2) {
-                                    const { siteSet, marketingCarrierType, marketingGoal, marketingTargetType, sceneSpec, automaticSiteEnabled } = firstRow
-                                    if (
-                                        data?.marketingGoal === marketingGoal &&  // 营销内容
-                                        data?.marketingCarrierType === marketingCarrierType && // 营销载体
-                                        data?.marketingTargetType === marketingTargetType && // 推广产品
-                                        data?.automaticSiteEnabled === automaticSiteEnabled &&   // 自动版位
-                                        arraysHaveSameValues(siteSet || [], data?.siteSet || []) && // 版位选择
-                                        arraysHaveSameValues(data?.sceneSpec?.wechatPosition || [], sceneSpec?.wechatPosition || []) // 微信公众号与小程序定投
-                                    ) {
-                                        newSelectAccData.push(data)
+                                    const { siteSet, marketingCarrierType, marketingGoal, marketingTargetType, sceneSpec, automaticSiteEnabled, smartDeliveryPlatform, smartDeliverySceneSpec } = firstRow
+                                    if (smartDeliveryPlatform) { // 智投
+                                        if (
+                                            data?.marketingGoal === marketingGoal &&  // 营销内容
+                                            data?.marketingCarrierType === marketingCarrierType && // 营销载体
+                                            data?.marketingTargetType === marketingTargetType && // 推广产品
+                                            data?.automaticSiteEnabled === automaticSiteEnabled &&   // 智能版位
+                                            data?.smartDeliveryPlatform === smartDeliveryPlatform &&
+                                            data?.smartDeliverySceneSpec?.smartDeliveryGoal === smartDeliverySceneSpec?.smartDeliveryGoal
+                                        ) {
+                                            newSelectAccData.push(data)
+                                        }
+                                    } else {
+                                        if (
+                                            data?.marketingGoal === marketingGoal &&  // 营销内容
+                                            data?.marketingCarrierType === marketingCarrierType && // 营销载体
+                                            data?.marketingTargetType === marketingTargetType && // 推广产品
+                                            data?.automaticSiteEnabled === automaticSiteEnabled &&   // 智能版位
+                                            arraysHaveSameValues(siteSet || [], data?.siteSet || []) && // 版位选择
+                                            arraysHaveSameValues(data?.sceneSpec?.wechatPosition || [], sceneSpec?.wechatPosition || []) // 微信公众号与小程序定投
+                                        ) {
+                                            newSelectAccData.push(data)
+                                        }
+                                    }
+                                } else if (handleType === 1) {
+                                    const { smartDeliveryPlatform } = firstRow
+                                    if (smartDeliveryPlatform) {
+                                        data?.smartDeliveryPlatform && newSelectAccData.push(data);
+                                    } else {
+                                        !data?.smartDeliveryPlatform && newSelectAccData.push(data);
                                     }
                                 } else {
                                     newSelectAccData.push(data)

+ 21 - 2
src/pages/launchSystemV3/adqv3/ad/tableConfig.tsx

@@ -7,7 +7,7 @@ import { ADGROUP_STATUS, AUTO_ACQUISTION_STATUS, GOAL_ENUM } from '../const'
 import SwitchStatus from './switchStatus'
 import TimeSeriesLook from '@/pages/launchSystemNew/adq/ad/timeSeriesLook'
 import CreativePreview from '../../adMonitorListV3/CreativePreview'
-import { BID_MODE_ENUM, BID_SCENE_NORMAL_ENUM, COST_GUARANTEE_STATUS_ENUM, MARKETING_CARRIER_TYPE_ENUM, MARKETING_GOAL_ENUM, MARKETING_TARGET_TYPE_ENUM, MARKETING_TARGET_TYPE_GAME_ENUM, OPTIMIZATIONGOAL_ENUM, SITE_SET_ENUM } from '../../tencentAdPutIn/const'
+import { BID_MODE_ENUM, BID_SCENE_NORMAL_ENUM, COST_GUARANTEE_STATUS_ENUM, MARKETING_CARRIER_TYPE_ENUM, MARKETING_GOAL_ENUM, MARKETING_TARGET_TYPE_ENUM, MARKETING_TARGET_TYPE_GAME_ENUM, OPTIMIZATIONGOAL_ENUM, SITE_SET_ENUM, SMART_DELIVERY_GOAL_ENUM } from '../../tencentAdPutIn/const'
 function tableConfig(onChange: () => void, useType: string, creativeHandle?: (id: number) => void): any {
     return [
         {
@@ -21,6 +21,17 @@ function tableConfig(onChange: () => void, useType: string, creativeHandle?: (id
                 return <SwitchStatus configuredStatus={a} accountId={b?.accountId} isDeleted={b?.isDeleted} adgroupId={b?.adgroupId} onChange={onChange} />
             }
         },
+        {
+            title: '是否智投',
+            dataIndex: 'smartDeliveryPlatform',
+            key: 'smartDeliveryPlatform',
+            align: 'center',
+            width: 40,
+            fixed: 'left',
+            render: (a: string) => {
+                return <Badge status={a ? "processing" : "error"} text={a ? '是' : '否'} />
+            }
+        },
         {
             title: '所属账号',
             dataIndex: 'accountId',
@@ -124,7 +135,15 @@ function tableConfig(onChange: () => void, useType: string, creativeHandle?: (id
             width: 140,
             align: 'right',
             ellipsis: true,
-            render: (a: string, b: { bidMode: string, optimizationGoal: string }) => {
+            render: (a: string, b: { bidMode: string, optimizationGoal: string, smartDeliveryPlatform?: string, smartDeliverySceneSpec?: any }) => {
+                if (b?.smartDeliveryPlatform && b?.smartDeliverySceneSpec) {
+                    const goalDto = SMART_DELIVERY_GOAL_ENUM[b.smartDeliverySceneSpec?.smartDeliveryGoal as keyof typeof SMART_DELIVERY_GOAL_ENUM]
+                    return `${goalDto?.smartDeliveryGoalSpec?.map(item => {
+                        const field_name = item.field_name
+                        const data = b.smartDeliverySceneSpec?.smartDeliveryGoalSpec?.[goalDto?.smartDeliveryGoalSpecName]?.[item.field_name]
+                        return `${item.title}: ${field_name?.includes('Roi') ? data : data / 100}${item?.unitTips || ''}`
+                    })}`
+                }
                 return `${BID_MODE_ENUM[b?.bidMode as keyof typeof BID_MODE_ENUM]} ${a}元/${b?.bidMode === 'BID_MODE_CPM' ? '千次曝光' : b?.bidMode === 'BID_MODE_CPC' ? '点击' : OPTIMIZATIONGOAL_ENUM[b?.optimizationGoal as keyof typeof OPTIMIZATIONGOAL_ENUM]}`
             }
         },

+ 32 - 31
src/pages/launchSystemV3/adqv3/config.ts

@@ -4,37 +4,38 @@ const txAdConfig = [
         label: '广告详情',
         data: [
             { title: '启停', dataIndex: 'configuredStatus', label: '广告详情', default: 1, width: 40 },
-            { title: '所属账号', dataIndex: 'accountId', label: '广告详情', default: 2, width: 75 },
-            { title: '腾讯备注', dataIndex: 'memo', label: '广告详情', default: 3, width: 80 },
-            { title: '本地备注', dataIndex: 'remark', label: '广告详情', default: 4, width: 80 },
-            { title: '广告ID', dataIndex: 'adgroupId', label: '广告详情', default: 5, width: 90 },
-            { title: '投手', dataIndex: 'putUserName', label: '广告详情', default: 6, width: 70 },
-            { title: '广告名称', dataIndex: 'adgroupName', label: '广告详情', default: 7, width: 280 },
-            { title: '投放日期', dataIndex: 'beginDate', label: '广告详情', default: 8, width: 150 },
-            { title: '投放时间', dataIndex: 'timeSeries', label: '广告详情', default: 9, width: 55 },
-            { title: '首日开始投放时间', dataIndex: 'firstDayBeginTime', label: '广告详情', default: 10, width: 70 },
-            { title: '出价', dataIndex: 'bidAmount', label: '广告详情', default: 11, width: 140 },
-            { title: '深度优化行为出价', dataIndex: 'deepConversionBehaviorBid', label: '广告详情', default: 12, width: 120 },
-            { title: '出价类型', dataIndex: 'smartBidType', label: '广告详情', default: 13, width: 80 },
-            { title: '出价策略', dataIndex: 'bidStrategy', label: '广告详情', default: 14, width: 80 },
-            { title: '一键起量', dataIndex: 'autoAcquisitionEnabled', label: '广告详情', default: 15, width: 70 },
-            { title: '一键起量状态', dataIndex: 'autoAcquisitionStatus', label: '广告详情', default: 16, width: 120 },
-            { title: '一键起量预算', dataIndex: 'autoAcquisitionBudget', label: '广告详情', default: 17, width: 70 },
-            { title: '广告组日预算(元)', dataIndex: 'dailyBudget', label: '广告详情', default: 18, width: 70 },
-            { title: '营销目的', dataIndex: 'marketingGoal', label: '广告详情', default: 19, width: 80 },
-            { title: '推广产品类型', dataIndex: 'marketingTargetType', label: '广告详情', default: 20, width: 90 },
-            { title: '营销载体类型', dataIndex: 'marketingCarrierType', label: '广告详情', default: 21, width: 90 },
-            { title: '是否开启自动版位功能', dataIndex: 'automaticSiteEnabled', label: '广告详情', default: 22, width: 80 },
-            { title: '版位选择', dataIndex: 'siteSet', label: '广告详情', default: 23, width: 100 },
-            { title: '定向条件描述', dataIndex: 'targetingTranslation', label: '广告详情', default: 24, width: 80 },
-            { title: '成本保障状态', dataIndex: 'costGuaranteeStatus', label: '广告详情', default: 25, width: 80 },
-            { title: '成本保障赔付金额', dataIndex: 'costGuaranteeMoney', label: '广告详情', default: 26, width: 80 },
-            { title: '创建时间', dataIndex: 'createdTime', label: '广告详情', default: 27, width: 140 },
-            { title: '是否已删除', dataIndex: 'isDeleted', label: '广告详情', default: 28, width: 60 },
-            { title: '广告状态', dataIndex: 'systemStatus', label: '广告详情', default: 29, width: 80 },
-            { title: '定向智能状态', dataIndex: 'smartTargetingStatus', label: '广告详情', default: 30, width: 80 },
-            { title: '创意预览', dataIndex: 'dynamicCreativeList', label: '广告详情', default: 31, width: 150 },
-            { title: '操作', dataIndex: 'cz', label: '广告详情', default: 32, width: 65 },
+            { title: '是否智投', dataIndex: 'smartDeliveryPlatform', label: '广告详情', default: 2, width: 60 },
+            { title: '所属账号', dataIndex: 'accountId', label: '广告详情', default: 3, width: 75 },
+            { title: '腾讯备注', dataIndex: 'memo', label: '广告详情', default: 4, width: 80 },
+            { title: '本地备注', dataIndex: 'remark', label: '广告详情', default: 5, width: 80 },
+            { title: '广告ID', dataIndex: 'adgroupId', label: '广告详情', default: 6, width: 90 },
+            { title: '投手', dataIndex: 'putUserName', label: '广告详情', default: 7, width: 70 },
+            { title: '广告名称', dataIndex: 'adgroupName', label: '广告详情', default: 8, width: 280 },
+            { title: '投放日期', dataIndex: 'beginDate', label: '广告详情', default: 9, width: 150 },
+            { title: '投放时间', dataIndex: 'timeSeries', label: '广告详情', default: 10, width: 55 },
+            { title: '首日开始投放时间', dataIndex: 'firstDayBeginTime', label: '广告详情', default: 11, width: 70 },
+            { title: '出价', dataIndex: 'bidAmount', label: '广告详情', default: 12, width: 140 },
+            { title: '深度优化行为出价', dataIndex: 'deepConversionBehaviorBid', label: '广告详情', default: 13, width: 120 },
+            { title: '出价类型', dataIndex: 'smartBidType', label: '广告详情', default: 14, width: 80 },
+            { title: '出价策略', dataIndex: 'bidStrategy', label: '广告详情', default: 15, width: 80 },
+            { title: '一键起量', dataIndex: 'autoAcquisitionEnabled', label: '广告详情', default: 16, width: 70 },
+            { title: '一键起量状态', dataIndex: 'autoAcquisitionStatus', label: '广告详情', default: 17, width: 120 },
+            { title: '一键起量预算', dataIndex: 'autoAcquisitionBudget', label: '广告详情', default: 18, width: 70 },
+            { title: '广告组日预算(元)', dataIndex: 'dailyBudget', label: '广告详情', default: 19, width: 70 },
+            { title: '营销目的', dataIndex: 'marketingGoal', label: '广告详情', default: 20, width: 80 },
+            { title: '推广产品类型', dataIndex: 'marketingTargetType', label: '广告详情', default: 21, width: 90 },
+            { title: '营销载体类型', dataIndex: 'marketingCarrierType', label: '广告详情', default: 22, width: 90 },
+            { title: '是否开启自动版位功能', dataIndex: 'automaticSiteEnabled', label: '广告详情', default: 23, width: 80 },
+            { title: '版位选择', dataIndex: 'siteSet', label: '广告详情', default: 24, width: 100 },
+            { title: '定向条件描述', dataIndex: 'targetingTranslation', label: '广告详情', default: 25, width: 80 },
+            { title: '成本保障状态', dataIndex: 'costGuaranteeStatus', label: '广告详情', default: 26, width: 80 },
+            { title: '成本保障赔付金额', dataIndex: 'costGuaranteeMoney', label: '广告详情', default: 27, width: 80 },
+            { title: '创建时间', dataIndex: 'createdTime', label: '广告详情', default: 28, width: 140 },
+            { title: '是否已删除', dataIndex: 'isDeleted', label: '广告详情', default: 29, width: 60 },
+            { title: '广告状态', dataIndex: 'systemStatus', label: '广告详情', default: 30, width: 80 },
+            { title: '定向智能状态', dataIndex: 'smartTargetingStatus', label: '广告详情', default: 31, width: 80 },
+            { title: '创意预览', dataIndex: 'dynamicCreativeList', label: '广告详情', default: 32, width: 150 },
+            { title: '操作', dataIndex: 'cz', label: '广告详情', default: 33, width: 65 },
         ]
     }
 ]

+ 9 - 1
src/pages/launchSystemV3/adqv3/const.tsx

@@ -14,7 +14,15 @@ export enum ADGROUP_STATUS {
     ADGROUP_STATUS_CREATIVE_STATUS_PENDING = '创意未投放',
     ADGROUP_STATUS_CREATIVE_EMPTY = '创意准备中',
     ADGROUP_STATUS_JOINT_BUDGET_REACHED = '广告被暂停(联合预算达上限)',
-    ADGROUP_STATUS_TOTAL_BUDGET_REACHED = '广告达到总预算上限'
+    ADGROUP_STATUS_TOTAL_BUDGET_REACHED = '广告达到总预算上限',
+    SMART_ADGROUP_STATUS_SUSPEND = '已暂停(智投)',
+    SMART_ADGROUP_STATUS_USING = '项目启用中(智投)',
+    SMART_ADGROUP_STATUS_ADGROUP_STATUS_STOP = '投放结束(智投)',
+    SMART_ADGROUP_STATUS_ACCOUNT_BALANCE_NOT_ENOUGH = '账户余额不足(智投)',
+    SMART_ADGROUP_STATUS_JOINT_BUDGET_REACHED = '项目被暂停(智投)',
+    SMART_ADGROUP_STATUS_DAILY_BUDGET_REACHED = '项目日预算到达上限(智投)',
+    SMART_ADGROUP_STATUS_NOT_IN_DELIVERY_TIME = '未到投放时间(智投)',
+    SMART_ADGROUP_STATUS_ACTIVE = '投放中(智投)'
 }
 
 /** 投放模式 */

+ 99 - 56
src/pages/launchSystemV3/components/AdgroupTooltip/index.tsx

@@ -1,6 +1,6 @@
-import React from "react"
+import React, { useMemo } from "react"
 import style from '../../tencentAdPutIn/create/index.less'
-import { AD_STATUS_ENUM, BID_ALL_OCATION_MODE, BID_MODE_ENUM, BID_SCENE_NORMAL_ENUM, DEEP_CONVERSION_ENUM, GOAL_ROAS_ENUM, MARKETING_CARRIER_TYPE_ENUM, MARKETING_GOAL_ENUM, MARKETING_SUB_GOAL_ENUM, MARKETING_TARGET_TYPE_ENUM, MARKETING_TARGET_TYPE_GAME_ENUM, OPTIMIZATIONGOAL_ENUM, ROI_ALL_OCATION_MODE, SITE_SET_ENUM, SMART_BID_TYPE_ENUM } from "../../tencentAdPutIn/const"
+import { AD_STATUS_ENUM, BID_ALL_OCATION_MODE, BID_MODE_ENUM, BID_SCENE_NORMAL_ENUM, DEEP_CONVERSION_ENUM, GOAL_ROAS_ENUM, MARKETING_CARRIER_TYPE_ENUM, MARKETING_GOAL_ENUM, MARKETING_SUB_GOAL_ENUM, MARKETING_TARGET_TYPE_ENUM, MARKETING_TARGET_TYPE_GAME_ENUM, OPTIMIZATIONGOAL_ENUM, ROI_ALL_OCATION_MODE, SITE_SET_ENUM, SMART_BID_TYPE_ENUM, SMART_DELIVERY_GOAL_ENUM, SMART_DELIVERY_PLATFORM_ENUM } from "../../tencentAdPutIn/const"
 import { Typography } from "antd"
 import TimeSeriesLook from "@/pages/launchSystemNew/adq/ad/timeSeriesLook"
 import { ShowApplication } from "../../tencenTasset/application"
@@ -21,69 +21,112 @@ const AdgroupTooltip: React.FC<Props> = ({ data: adgroups, taskType }) => {
     /************************************/
     const {
         marketingGoal, marketingSubGoal, marketingAssetOuterSpec, marketingCarrierType, automaticSiteEnabled, explorationStrategy, siteSet, prioritySiteSet, searchExpandTargetingSwitch, bidMode, smartBidType, bidScene, bidAmount, optimizationGoal, ecomPkamSwitch,
-        deepConversionSpec, autoAcquisitionEnabled, autoAcquisitionBudget, dailyBudget, endDate, beginDate, timeSeries, firstDayBeginTime, configuredStatus, adgroupName, promoteApplicationId, rtaId, rtaTargetId, bidAmountMin, bidAllocationMode, bidAmountMax,
-
+        deepConversionSpec, autoAcquisitionEnabled, autoAcquisitionBudget, dailyBudget, endDate, beginDate, timeSeries, firstDayBeginTime, configuredStatus, adgroupName, promoteApplicationId, rtaId, rtaTargetId, bidAmountMin, bidAllocationMode, bidAmountMax, deliveryMethod,
+        smartDeliverySceneSpec, smartDeliveryPlatform
     } = adgroups
     /************************************/
 
+    // 智能投放出价
+    const smartModel = useMemo(() => {
+        if (deliveryMethod === 'SMART') {
+            const goalDto = SMART_DELIVERY_GOAL_ENUM[smartDeliverySceneSpec?.smartDeliveryGoal as keyof typeof SMART_DELIVERY_GOAL_ENUM]
+            if ([2, 3].includes(bidAllocationMode)) {
+                const data = smartDeliverySceneSpec?.smartDeliveryGoalSpec?.[goalDto?.smartDeliveryGoalSpecName]
+                return goalDto?.smartDeliveryGoalSpec?.map(item => <p key={item.field_name} style={{ fontWeight: 'bold', color: '#000' }}>{item.title}: {data?.[item.field_name + 'Min']}-{data?.[item.field_name + 'Max']}{item?.unitTips || ''}</p>)
+            } else {
+                return goalDto?.smartDeliveryGoalSpec?.map(item => <p key={item.field_name} style={{ fontWeight: 'bold', color: '#000' }}>{item.title}: {smartDeliverySceneSpec?.smartDeliveryGoalSpec?.[goalDto?.smartDeliveryGoalSpecName]?.[item.field_name]}{item?.unitTips || ''}</p>)
+            }
+        }
+        return null
+    }, [smartDeliverySceneSpec, deliveryMethod, bidAllocationMode])
+
     return <div className={style.detail_body} style={{ height: 'auto' }}>
         {(adgroups && Object.keys(adgroups).length > 0) && <>
-            {taskType === 'NOVEL' ? <>
-                <p>营销目的:{MARKETING_GOAL_ENUM[marketingGoal as keyof typeof MARKETING_GOAL_ENUM]}</p>
-                <p style={{ fontWeight: 'bold', color: '#000' }}>推广产品类型:{MARKETING_TARGET_TYPE_ENUM[marketingAssetOuterSpec?.marketingTargetType as keyof typeof MARKETING_TARGET_TYPE_ENUM]}</p>
+            <p style={{ fontWeight: 'bold', color: '#000' }}>投放方式:{deliveryMethod === 'SMART' ? '智能投放' : '常规投放'}</p>
+            {deliveryMethod === 'NORMAL' ? <>
+                {taskType === 'NOVEL' ? <>
+                    <p>营销目的:{MARKETING_GOAL_ENUM[marketingGoal as keyof typeof MARKETING_GOAL_ENUM]}</p>
+                    <p style={{ fontWeight: 'bold', color: '#000' }}>推广产品类型:{MARKETING_TARGET_TYPE_ENUM[marketingAssetOuterSpec?.marketingTargetType as keyof typeof MARKETING_TARGET_TYPE_ENUM]}</p>
+                </> : <>
+                    <p>营销目的:{MARKETING_SUB_GOAL_ENUM[marketingSubGoal as keyof typeof MARKETING_SUB_GOAL_ENUM]}</p>
+                    <p style={{ fontWeight: 'bold', color: '#000' }}>推广产品类型:{MARKETING_TARGET_TYPE_GAME_ENUM[marketingAssetOuterSpec?.marketingTargetType as keyof typeof MARKETING_TARGET_TYPE_GAME_ENUM]}</p>
+                </>}
+                <p>营销载体类型:{MARKETING_CARRIER_TYPE_ENUM[marketingCarrierType as keyof typeof MARKETING_CARRIER_TYPE_ENUM]}</p>
+                {['MARKETING_CARRIER_TYPE_APP_ANDROID', 'MARKETING_CARRIER_TYPE_APP_IOS'].includes(marketingCarrierType) && <ShowApplication id={promoteApplicationId} />}
+                <p>版位选择:{automaticSiteEnabled ? '自动版位' : '选择特定版位'}</p>
+                {!automaticSiteEnabled && <Typography.Paragraph className={style.tpP} style={{ marginBottom: 0 }} ellipsis={{ tooltip: true, rows: 2 }}>广告版位:{siteSet.map((item: string | number) => SITE_SET_ENUM[item as keyof typeof SITE_SET_ENUM]).toString()}</Typography.Paragraph>}
+                {automaticSiteEnabled && <>
+                    <p>探索策略:{explorationStrategy === 'STEADY_EXPLORATION' ? '稳步探索' : '自动探索'}</p>
+                    {prioritySiteSet?.length > 0 && <Typography.Paragraph className={style.tpP} style={{ marginBottom: 0 }} ellipsis={{ tooltip: true, rows: 2 }}>优先探索版位:{prioritySiteSet.map((item: string | number) => SITE_SET_ENUM[item as keyof typeof SITE_SET_ENUM]).toString()}</Typography.Paragraph>}
+                </>}
+                <p>搜索场景扩量:{searchExpandTargetingSwitch === 'SEARCH_EXPAND_TARGETING_SWITCH_OPEN' ? '开启' : '关闭'}</p>
+                {rtaId && <p>RTA ID:{rtaId}</p>}
+                {rtaTargetId && <p>策略 ID:{rtaTargetId}</p>}
+                <p>计费方式:{BID_MODE_ENUM[bidMode as keyof typeof BID_MODE_ENUM]}</p>
+                {taskType === 'GAME' ? <>
+                    <p>出价场景:{BID_SCENE_NORMAL_ENUM[bidScene as keyof typeof BID_SCENE_NORMAL_ENUM]}</p>
+                </> : <p>出价类型:{SMART_BID_TYPE_ENUM[smartBidType as keyof typeof SMART_BID_TYPE_ENUM]}</p>}
+                <p style={{ fontWeight: 'bold', color: '#000' }}>出价分配方式:{BID_ALL_OCATION_MODE.find(item => item.value === bidAllocationMode)?.label}</p>
+                {[2, 3].includes(bidAllocationMode)
+                    ?
+                    <p style={{ fontWeight: 'bold', color: '#000' }}>出价:{bidAmountMin}-{bidAmountMax} 元/{optimizationGoal ? OPTIMIZATIONGOAL_ENUM[optimizationGoal as keyof typeof OPTIMIZATIONGOAL_ENUM] : ['BID_MODE_OCPM', 'BID_MODE_OCPC'].includes(bidMode) ? '千次曝光' : '点击'}</p>
+                    :
+                    <p style={{ fontWeight: 'bold', color: '#000' }}>出价:{bidAmount} 元/{optimizationGoal ? OPTIMIZATIONGOAL_ENUM[optimizationGoal as keyof typeof OPTIMIZATIONGOAL_ENUM] : ['BID_MODE_OCPM', 'BID_MODE_OCPC'].includes(bidMode) ? '千次曝光' : '点击'}</p>
+                }
+                {optimizationGoal && <p style={{ fontWeight: 'bold', color: '#000' }}>优化目标:{OPTIMIZATIONGOAL_ENUM[optimizationGoal as keyof typeof OPTIMIZATIONGOAL_ENUM]}</p>}
+                {deepConversionSpec && <>
+                    <p style={{ fontWeight: 'bold', color: '#000' }}>深度转化优化:开启</p>
+                    <p style={{ fontWeight: 'bold', color: '#000' }}>深度优化类型:{DEEP_CONVERSION_ENUM[deepConversionSpec?.deepConversionType as keyof typeof DEEP_CONVERSION_ENUM]}</p>
+                    {deepConversionSpec.deepConversionType === 'DEEP_CONVERSION_BEHAVIOR' ? <>
+                        <p style={{ fontWeight: 'bold', color: '#000' }}>深度优化目标:{OPTIMIZATIONGOAL_ENUM[deepConversionSpec.deepConversionBehaviorSpec.goal as keyof typeof OPTIMIZATIONGOAL_ENUM]}</p>
+                        <p style={{ fontWeight: 'bold', color: '#000' }}>深度目标出价:{deepConversionSpec.deepConversionBehaviorSpec.bidAmount}元/{OPTIMIZATIONGOAL_ENUM[deepConversionSpec.deepConversionBehaviorSpec.goal as keyof typeof OPTIMIZATIONGOAL_ENUM] || '优化目标'}</p>
+                    </> : <>
+                        <p style={{ fontWeight: 'bold', color: '#000' }}>深度优化目标:{GOAL_ROAS_ENUM[deepConversionSpec.deepConversionWorthSpec.goal as keyof typeof GOAL_ROAS_ENUM]}</p>
+                        <p style={{ fontWeight: 'bold', color: '#000' }}>ROI分配方式:{ROI_ALL_OCATION_MODE.find(item => item.value === deepConversionSpec?.deepConversionWorthSpec?.roiAllocationMode)?.label}</p>
+                        {[2, 3].includes(deepConversionSpec?.deepConversionWorthSpec?.roiAllocationMode)
+                            ?
+                            <p style={{ fontWeight: 'bold', color: '#000' }}>期望ROI:{deepConversionSpec.deepConversionWorthSpec.expectedRoiMin}-{deepConversionSpec.deepConversionWorthSpec.expectedRoiMax}</p>
+                            :
+                            <p style={{ fontWeight: 'bold', color: '#000' }}>期望ROI:{deepConversionSpec.deepConversionWorthSpec.expectedRoi}</p>
+                        }
+                    </>}
+                </>}
+                <p>一方人群跑量加强:{ecomPkamSwitch === 'ECOM_PKAM_SWITCH_OPEN' ? '开启' : '关闭'}</p>
+                <p>一键起量:{autoAcquisitionEnabled ? '开启' : '关闭'}</p>
+                {autoAcquisitionEnabled && <p>起量预算:{autoAcquisitionBudget}元/天</p>}
+                <p>广告日预算:{dailyBudget ? dailyBudget + '元/天' : '不限'}</p>
+                <p style={{ fontWeight: 'bold', color: '#000' }}>投放日期:{beginDate} 至 {endDate || '长期投放'}</p>
+                <p>投放时段:{timeSeries.includes('0') ? <TimeSeriesLook timeSeries={timeSeries} /> : '全天'}</p>
+                <p>首日开始时间:{firstDayBeginTime ? firstDayBeginTime : '关闭'}</p>
+                <p>广告状态:{AD_STATUS_ENUM[configuredStatus as keyof typeof AD_STATUS_ENUM]}</p>
+                <p>广告名称:{adgroupName}</p>
             </> : <>
-                <p>营销目的:{MARKETING_SUB_GOAL_ENUM[marketingSubGoal as keyof typeof MARKETING_SUB_GOAL_ENUM]}</p>
-                <p style={{ fontWeight: 'bold', color: '#000' }}>推广产品类型:{MARKETING_TARGET_TYPE_GAME_ENUM[marketingAssetOuterSpec?.marketingTargetType as keyof typeof MARKETING_TARGET_TYPE_GAME_ENUM]}</p>
-            </>}
-            <p>营销载体类型:{MARKETING_CARRIER_TYPE_ENUM[marketingCarrierType as keyof typeof MARKETING_CARRIER_TYPE_ENUM]}</p>
-            {['MARKETING_CARRIER_TYPE_APP_ANDROID', 'MARKETING_CARRIER_TYPE_APP_IOS'].includes(marketingCarrierType) && <ShowApplication id={promoteApplicationId} />}
-            <p>版位选择:{automaticSiteEnabled ? '自动版位' : '选择特定版位'}</p>
-            {!automaticSiteEnabled && <Typography.Paragraph className={style.tpP} style={{ marginBottom: 0 }} ellipsis={{ tooltip: true, rows: 2 }}>广告版位:{siteSet.map((item: string | number) => SITE_SET_ENUM[item as keyof typeof SITE_SET_ENUM]).toString()}</Typography.Paragraph>}
-            {automaticSiteEnabled && <>
-                <p>探索策略:{explorationStrategy === 'STEADY_EXPLORATION' ? '稳步探索' : '自动探索'}</p>
-                {prioritySiteSet?.length > 0 && <Typography.Paragraph className={style.tpP} style={{ marginBottom: 0 }} ellipsis={{ tooltip: true, rows: 2 }}>优先探索版位:{prioritySiteSet.map((item: string | number) => SITE_SET_ENUM[item as keyof typeof SITE_SET_ENUM]).toString()}</Typography.Paragraph>}
-            </>}
-            <p>搜索场景扩量:{searchExpandTargetingSwitch === 'SEARCH_EXPAND_TARGETING_SWITCH_OPEN' ? '开启' : '关闭'}</p>
-            {rtaId && <p>RTA ID:{rtaId}</p>}
-            {rtaTargetId && <p>策略 ID:{rtaTargetId}</p>}
-            <p>计费方式:{BID_MODE_ENUM[bidMode as keyof typeof BID_MODE_ENUM]}</p>
-            {taskType === 'GAME' ? <>
-                <p>出价场景:{BID_SCENE_NORMAL_ENUM[bidScene as keyof typeof BID_SCENE_NORMAL_ENUM]}</p>
-            </> : <p>出价类型:{SMART_BID_TYPE_ENUM[smartBidType as keyof typeof SMART_BID_TYPE_ENUM]}</p>}
-            <p style={{ fontWeight: 'bold', color: '#000' }}>出价分配方式:{BID_ALL_OCATION_MODE.find(item => item.value === bidAllocationMode)?.label}</p>
-            {[2, 3].includes(bidAllocationMode)
-                ?
-                <p style={{ fontWeight: 'bold', color: '#000' }}>出价:{bidAmountMin}-{bidAmountMax} 元/{optimizationGoal ? OPTIMIZATIONGOAL_ENUM[optimizationGoal as keyof typeof OPTIMIZATIONGOAL_ENUM] : ['BID_MODE_OCPM', 'BID_MODE_OCPC'].includes(bidMode) ? '千次曝光' : '点击'}</p>
-                :
-                <p style={{ fontWeight: 'bold', color: '#000' }}>出价:{bidAmount} 元/{optimizationGoal ? OPTIMIZATIONGOAL_ENUM[optimizationGoal as keyof typeof OPTIMIZATIONGOAL_ENUM] : ['BID_MODE_OCPM', 'BID_MODE_OCPC'].includes(bidMode) ? '千次曝光' : '点击'}</p>
-            }
-            {optimizationGoal && <p style={{ fontWeight: 'bold', color: '#000' }}>优化目标:{OPTIMIZATIONGOAL_ENUM[optimizationGoal as keyof typeof OPTIMIZATIONGOAL_ENUM]}</p>}
-            {deepConversionSpec && <>
-                <p style={{ fontWeight: 'bold', color: '#000' }}>深度转化优化:开启</p>
-                <p style={{ fontWeight: 'bold', color: '#000' }}>深度优化类型:{DEEP_CONVERSION_ENUM[deepConversionSpec?.deepConversionType as keyof typeof DEEP_CONVERSION_ENUM]}</p>
-                {deepConversionSpec.deepConversionType === 'DEEP_CONVERSION_BEHAVIOR' ? <>
-                    <p style={{ fontWeight: 'bold', color: '#000' }}>深度优化目标:{OPTIMIZATIONGOAL_ENUM[deepConversionSpec.deepConversionBehaviorSpec.goal as keyof typeof OPTIMIZATIONGOAL_ENUM]}</p>
-                    <p style={{ fontWeight: 'bold', color: '#000' }}>深度目标出价:{deepConversionSpec.deepConversionBehaviorSpec.bidAmount}元/{OPTIMIZATIONGOAL_ENUM[deepConversionSpec.deepConversionBehaviorSpec.goal as keyof typeof OPTIMIZATIONGOAL_ENUM] || '优化目标'}</p>
+                {/* 智能投放 */}
+                <p style={{ fontWeight: 'bold', color: '#000' }}>投放场景:{SMART_DELIVERY_PLATFORM_ENUM[smartDeliveryPlatform as keyof typeof SMART_DELIVERY_PLATFORM_ENUM]}</p>
+                {taskType === 'NOVEL' ? <>
+                    <p>营销目的:{MARKETING_GOAL_ENUM[marketingGoal as keyof typeof MARKETING_GOAL_ENUM]}</p>
+                    <p style={{ fontWeight: 'bold', color: '#000' }}>推广产品类型:{MARKETING_TARGET_TYPE_ENUM[marketingAssetOuterSpec?.marketingTargetType as keyof typeof MARKETING_TARGET_TYPE_ENUM]}</p>
                 </> : <>
-                    <p style={{ fontWeight: 'bold', color: '#000' }}>深度优化目标:{GOAL_ROAS_ENUM[deepConversionSpec.deepConversionWorthSpec.goal as keyof typeof GOAL_ROAS_ENUM]}</p>
-                    <p style={{ fontWeight: 'bold', color: '#000' }}>ROI分配方式:{ROI_ALL_OCATION_MODE.find(item => item.value === deepConversionSpec?.deepConversionWorthSpec?.roiAllocationMode)?.label}</p>
-                    {[2, 3].includes(deepConversionSpec?.deepConversionWorthSpec?.roiAllocationMode)
-                        ?
-                        <p style={{ fontWeight: 'bold', color: '#000' }}>期望ROI:{deepConversionSpec.deepConversionWorthSpec.expectedRoiMin}-{deepConversionSpec.deepConversionWorthSpec.expectedRoiMax}</p>
-                        :
-                        <p style={{ fontWeight: 'bold', color: '#000' }}>期望ROI:{deepConversionSpec.deepConversionWorthSpec.expectedRoi}</p>
-                    }
+                    <p>营销目的:{MARKETING_SUB_GOAL_ENUM[marketingSubGoal as keyof typeof MARKETING_SUB_GOAL_ENUM]}</p>
+                    <p style={{ fontWeight: 'bold', color: '#000' }}>推广产品类型:{MARKETING_TARGET_TYPE_GAME_ENUM[marketingAssetOuterSpec?.marketingTargetType as keyof typeof MARKETING_TARGET_TYPE_GAME_ENUM]}</p>
+                </>}
+                <p>营销载体类型:{MARKETING_CARRIER_TYPE_ENUM[marketingCarrierType as keyof typeof MARKETING_CARRIER_TYPE_ENUM]}</p>
+                {['MARKETING_CARRIER_TYPE_APP_ANDROID', 'MARKETING_CARRIER_TYPE_APP_IOS'].includes(marketingCarrierType) && <ShowApplication id={promoteApplicationId} />}
+                <p>版位选择:{automaticSiteEnabled ? '智能版位' : '选择特定版位'}</p>
+                {automaticSiteEnabled && <>
+                    <p>探索策略:{explorationStrategy === 'STEADY_EXPLORATION' ? '稳步探索' : '自动探索'}</p>
                 </>}
+                <p>搜索场景扩量:{searchExpandTargetingSwitch === 'SEARCH_EXPAND_TARGETING_SWITCH_OPEN' ? '开启' : '关闭'}</p>
+                <p>计费方式:{BID_MODE_ENUM[bidMode as keyof typeof BID_MODE_ENUM]}</p>
+                {smartDeliverySceneSpec?.smartDeliveryGoal && <p style={{ fontWeight: 'bold', color: '#000' }}>投放目标:{SMART_DELIVERY_GOAL_ENUM[smartDeliverySceneSpec?.smartDeliveryGoal as keyof typeof SMART_DELIVERY_GOAL_ENUM]?.title}</p>}
+                <p style={{ fontWeight: 'bold', color: '#000' }}>出价分配方式:{BID_ALL_OCATION_MODE.find(item => item.value === bidAllocationMode)?.label}</p>
+                {smartModel}
+                <p>广告日预算:{dailyBudget ? dailyBudget + '元/天' : '不限'}</p>
+                <p style={{ fontWeight: 'bold', color: '#000' }}>投放日期:{beginDate} 至 {endDate || '长期投放'}</p>
+                <p>投放时段:{timeSeries.includes('0') ? <TimeSeriesLook timeSeries={timeSeries} /> : '全天'}</p>
+                <p>首日开始时间:{firstDayBeginTime ? firstDayBeginTime : '关闭'}</p>
+                <p>广告名称:{adgroupName}</p>
             </>}
-            <p>一方人群跑量加强:{ecomPkamSwitch === 'ECOM_PKAM_SWITCH_OPEN' ? '开启' : '关闭'}</p>
-            <p>一键起量:{autoAcquisitionEnabled ? '开启' : '关闭'}</p>
-            {autoAcquisitionEnabled && <p>起量预算:{autoAcquisitionBudget}元/天</p>}
-            <p>广告日预算:{dailyBudget ? dailyBudget + '元/天' : '不限'}</p>
-            <p style={{ fontWeight: 'bold', color: '#000' }}>投放日期:{beginDate} 至 {endDate || '长期投放'}</p>
-            <p>投放时段:{timeSeries.includes('0') ? <TimeSeriesLook timeSeries={timeSeries} /> : '全天'}</p>
-            <p>首日开始时间:{firstDayBeginTime ? firstDayBeginTime : '关闭'}</p>
-            <p>广告状态:{AD_STATUS_ENUM[configuredStatus as keyof typeof AD_STATUS_ENUM]}</p>
-            <p>广告名称:{adgroupName}</p>
         </>}
     </div>
 }

+ 41 - 17
src/pages/launchSystemV3/components/ConversionSelect/index.tsx

@@ -6,6 +6,7 @@ import style from '../GoodsModal/index.less'
 import columns from './tableConfig'
 import { getConversionInfoApi } from "@/services/adqV3/global"
 import { useUpdateEffect } from "ahooks"
+import { SMART_DELIVERY_GOAL_ENUM } from "../../tencentAdPutIn/const"
 
 /**
  * 转化归因
@@ -29,6 +30,7 @@ const ConversionSelect: React.FC<Props> = (props) => {
     const [loading, setLoading] = useState<boolean>(false)
     const [accountId, setAccountId] = useState<number>(data[selectAdz - 1].accountId)
     const [conversionName, setConversionName] = useState<string>()
+    const [adOptimizationGoal, setAdOptimizationGoal] = useState<string>()
 
     const getConversionInfo = useAjax((params) => getConversionInfoApi(params))
     /************************/
@@ -47,12 +49,29 @@ const ConversionSelect: React.FC<Props> = (props) => {
 
     // 获取公众号列表
     const getList = (accountId: number) => {
-        let { optimizationGoal, deepConversionSpec, siteSet, marketingSubGoal, marketingGoal } = adgroups
+        const { optimizationGoal, deepConversionSpec, siteSet, marketingSubGoal, marketingAssetOuterSpec, marketingCarrierType, marketingGoal, deliveryMethod, smartDeliverySceneSpec } = adgroups
         let params: { [x: string]: any } = {}
-        if (putInType === 'NOVEL') {
-            params = { accountId, pageNum: 1, pageSize: 200, conversionName, createSourceType: 'SELF_CREATED', optimizationGoal, deepWorthOptimizationGoal: deepConversionSpec?.deepConversionWorthSpec?.goal, siteSet, taskType: putInType }
+        if (deliveryMethod === 'SMART') {
+            const optimizationGoalCombos = SMART_DELIVERY_GOAL_ENUM?.[smartDeliverySceneSpec?.smartDeliveryGoal as keyof typeof SMART_DELIVERY_GOAL_ENUM]
+            setAdOptimizationGoal(optimizationGoalCombos?.optimizationGoal)
+            params = {
+                accountId, pageNum: 1, pageSize: 200, conversionName,
+                createSourceType: 'SELF_CREATED',
+                optimizationGoal: optimizationGoalCombos?.optimizationGoal,
+                deepWorthOptimizationGoal: optimizationGoalCombos?.deepWorthOptimizationGoal,
+                marketingSubGoal,
+                marketingTargetType: marketingAssetOuterSpec?.marketingTargetType,
+                marketingCarrierType,
+                marketingGoal,
+                promotedObjectType: 'PROMOTED_OBJECT_TYPE_ECOMMERCE',
+                taskType: putInType
+            }
         } else {
-            params = { accountId, pageNum: 1, pageSize: 200, marketingGoal, marketingSubGoal, conversionName, createSourceType: 'SELF_CREATED', optimizationGoal, deepWorthOptimizationGoal: deepConversionSpec?.deepConversionWorthSpec?.goal, siteSet, taskType: putInType }
+            if (putInType === 'NOVEL') {
+                params = { accountId, pageNum: 1, pageSize: 200, conversionName, createSourceType: 'SELF_CREATED', optimizationGoal, deepWorthOptimizationGoal: deepConversionSpec?.deepConversionWorthSpec?.goal, siteSet, taskType: putInType }
+            } else {
+                params = { accountId, pageNum: 1, pageSize: 200, marketingGoal, marketingSubGoal, conversionName, createSourceType: 'SELF_CREATED', optimizationGoal, deepWorthOptimizationGoal: deepConversionSpec?.deepConversionWorthSpec?.goal, siteSet, taskType: putInType }
+            }
         }
         getConversionInfo.run(params).then(res => {
             setTableData(res?.records || [])
@@ -170,24 +189,29 @@ const ConversionSelect: React.FC<Props> = (props) => {
                         selectedRowKeys: data[selectAdz - 1]?.newConversionList?.map((item: any) => item?.conversionId),
                         onChange: onChangeTable,
                         getCheckboxProps: (record: any) => {
-                            const { deepConversionSpec } = adgroups
+                            const { deepConversionSpec, deliveryMethod } = adgroups
+                            if (deliveryMethod === 'SMART') {
+                                return {
+                                    disabled: adOptimizationGoal !== record.optimizationGoal
+                                }
+                            }
                             return {
                                 disabled: !deepConversionSpec ? (record?.deepWorthOptimizationGoal || record?.deepBehaviorOptimizationGoal) ? true : false : false
                             }
                         },
                     }}
-                    // onRow={(record) => ({
-                    //     onClick: () => {
-                    //         let newDatas = JSON.parse(JSON.stringify(data))
-                    //         let oldData = newDatas[selectAdz - 1]?.newConversionList || []
-                    //         const selected = oldData?.some((item: any) => item?.conversionId === record.conversionId);
-                    //         const newSelectedRows = selected
-                    //             ? oldData?.filter((item: any) => item?.conversionId !== record.conversionId)
-                    //             : [...oldData, record];
-                    //         newDatas[selectAdz - 1]['newConversionList'] = newSelectedRows;
-                    //         setData([...newDatas])
-                    //     },
-                    // })}
+                // onRow={(record) => ({
+                //     onClick: () => {
+                //         let newDatas = JSON.parse(JSON.stringify(data))
+                //         let oldData = newDatas[selectAdz - 1]?.newConversionList || []
+                //         const selected = oldData?.some((item: any) => item?.conversionId === record.conversionId);
+                //         const newSelectedRows = selected
+                //             ? oldData?.filter((item: any) => item?.conversionId !== record.conversionId)
+                //             : [...oldData, record];
+                //         newDatas[selectAdz - 1]['newConversionList'] = newSelectedRows;
+                //         setData([...newDatas])
+                //     },
+                // })}
                 />
             </div>
         </div>

+ 2 - 1
src/pages/launchSystemV3/components/PageModal/tableConfig.tsx

@@ -23,7 +23,8 @@ let columns = (type?: 1 | 2 | 3): TableProps<any>['columns'] => {
                 dataIndex: 'pageId',
                 key: 'pageId',
                 align: 'center',
-                width: 85
+                width: 95,
+                ellipsis: true
             },
             {
                 title: '落地页名称',

+ 1 - 1
src/pages/launchSystemV3/components/TargetingTooltip/index.tsx

@@ -2,7 +2,7 @@ import React, { useEffect, useState } from "react"
 import './index.less'
 import { DEVICE_PRICE_ENUM, EDUCATION_ENUM, EXCLUDED_DAY_ENUM, EXCLUDED_DIMENSION_ENUM, GAME_CONSUMPTION_LEVEL_ENUM, LOCATION_TYPES_ENUM, MARITAL_STATUS_ENUM, NETWORK_ENUM, OPTIMIZATIONGOAL_ENUM, USER_OS_ENUM, WECHAT_AD_NEHAVIOR_ENUM, WECHAT_AD_NEHAVIOR_GAME_ENUM } from "../../tencentAdPutIn/const"
 
-let targetingData = [
+export let targetingData = [
     { key: 'geoLocation', name: '地域' },
     { key: 'age', name: '年龄' },
     { key: 'gender', name: '性别' },

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

@@ -12,6 +12,12 @@
 export const defaultMarketingGoal = 'MARKETING_GOAL_PRODUCT_SALES'
 export const defaultGameMarketingGoal = 'MARKETING_GOAL_USER_GROWTH'
 
+// 智投 投放场景
+export enum SMART_DELIVERY_PLATFORM_ENUM {
+	SMART_DELIVERY_PLATFORM_EDITION_FICTION = '小说智投',
+	// SMART_DELIVERY_PLATFORM_EDITION_ECOLOGY_PLAYLET = '爆剧跑量',
+	// SMART_DELIVERY_PLATFORM_EDITION_ECOLOGY_LEADS = '线索跑量'
+}
 
 /** 营销目的 */
 export enum MARKETING_GOAL_ENUM {
@@ -610,7 +616,7 @@ export enum PAGE_TYPE_ENUM {
 	PAGE_TYPE_WECHAT_CHANNELS_PROFILE = "视频号",
 	PAGE_TYPE_SEARCH_BRAND_AREA = "搜一搜超级品专",
 	PAGE_TYPE_WECHAT_OFFICIAL_ACCOUNT_DETAIL = "公众号",
-	PAGE_TYPE_NOT_USED = "品牌形象",
+	PAGE_TYPE_NOT_USED = "自定义",
 	PAGE_TYPE_H5 = "自定义落地页",
 	PAGE_TYPE_XJ_WEB_H5 = "蹊径网页落地页",
 	PAGE_TYPE_WECHAT_MINI_PROGRAM = "微信小程序",
@@ -867,4 +873,80 @@ export enum STATUS_ENUM {
 	FROZEN = '冻结',
 	THAWING = '解冻中',
 	LOCKING = '锁定'
+}
+
+/** 投放目标值 */
+export const SMART_DELIVERY_GOAL_ENUM = {
+	FICTION_FOLLOW_PURCHASE_ROI: {
+		title: '关注和首日付费ROI',
+		smartDeliveryGoalSpecName: 'fictionFollowPurchaseRoiSpec',
+		deepWorthOptimizationGoal: 'GOAL_1DAY_PURCHASE_ROAS',
+		optimizationGoal: 'OPTIMIZATIONGOAL_FOLLOW',
+		smartDeliveryGoalSpec: [
+			{
+				"field_name": "followCost",
+				"title": "关注成本",
+				"unitTips": "元/关注"
+			},
+			{
+				"field_name": "firstDayPurchaseRoi",
+				"title": "首日付费ROI",
+			}
+		]
+	},
+	FICTION_REGISTER_PURCHASE_ROI: {
+		title: '注册和首日付费ROI',
+		smartDeliveryGoalSpecName: 'fictionRegisterPurchaseRoiSpec',
+		deepWorthOptimizationGoal: 'GOAL_1DAY_PURCHASE_ROAS',
+		optimizationGoal: 'OPTIMIZATIONGOAL_APP_REGISTER',
+		smartDeliveryGoalSpec: [
+			{
+				"field_name": "registerCost",
+				"title": "注册成本",
+				"unitTips": "元/关注"
+			},
+			{
+				"field_name": "firstDayPurchaseRoi",
+				"title": "首日付费ROI",
+			}
+		]
+	},
+	FICTION_REGISTER_MONETIZATION_ROI: {
+		title: '注册和首日变现ROI',
+		smartDeliveryGoalSpecName: 'fictionRegisterMonetizationRoiSpec',
+		deepWorthOptimizationGoal: 'GOAL_1DAY_MONETIZATION_ROAS',
+		optimizationGoal: 'OPTIMIZATIONGOAL_APP_REGISTER',
+		smartDeliveryGoalSpec: [
+			{
+				"field_name": "registerCost",
+				"title": "注册成本",
+				"unitTips": "元/关注"
+			},
+			{
+				"field_name": "firstDayMonetizationRoi",
+				"title": "首日变现ROI"
+			}
+		]
+	},
+	_24H_FIRSTPAY: {
+		title: '首日首次付费',
+		smartDeliveryGoalSpecName: 'bidAmountSpec',
+		deepWorthOptimizationGoal: undefined,
+		optimizationGoal: 'OPTIMIZATIONGOAL_24H_FIRSTPAY',
+		smartDeliveryGoalSpec: [
+			{
+				"field_name": "bidAmount",
+				"title": "首日首次付费成本",
+				"unitTips": "元/首日首次付费"
+			}
+		]
+	},
+}
+
+// 投放目标字段对应
+export const SMART_DELIVERY_GOAL_TYPE = {
+	FICTION_FOLLOW_PURCHASE_ROI: 'SMART_DELIVERY_GOAL_FICTION_FOLLOW_PURCHASE_ROI',
+	FICTION_REGISTER_PURCHASE_ROI: 'SMART_DELIVERY_GOAL_FICTION_REGISTER_PURCHASE_ROI',
+	FICTION_REGISTER_MONETIZATION_ROI: 'SMART_DELIVERY_GOAL_FICTION_REGISTER_MONETIZATION_ROI',
+	_24H_FIRSTPAY: 'SMART_DELIVERY_GOAL_24H_FIRSTPAY'
 }

+ 3 - 2
src/pages/launchSystemV3/tencentAdPutIn/create/Ad/adgroupsAdSetting.tsx

@@ -24,6 +24,7 @@ const AdgroupsAdSetting: React.FC<{ value?: any }> = ({ value }) => {
     const marketingGoal = Form.useWatch('marketingGoal', form)
     const marketingTargetType = Form.useWatch('marketingTargetType', form)
     const dateType = Form.useWatch('dateType', form)
+    const deliveryMethod = Form.useWatch('deliveryMethod', form);
     /****************************************/
 
     useEffect(() => {
@@ -119,7 +120,7 @@ const AdgroupsAdSetting: React.FC<{ value?: any }> = ({ value }) => {
                 </div>
             </Card>
         </Form.Item>
-        <Form.Item
+        {deliveryMethod === 'NORMAL' && <Form.Item
             label={<Space>
                 <strong>自动衍生创意</strong>
                 <Tooltip title={<div>
@@ -134,7 +135,7 @@ const AdgroupsAdSetting: React.FC<{ value?: any }> = ({ value }) => {
             name="autoDerivedCreativeEnabled"
         >
             <New1Radio data={[{ label: '系统衍生', value: true }, { label: '关闭衍生', value: false }]} />
-        </Form.Item>
+        </Form.Item>}
         <Form.Item label={<strong>广告状态</strong>} name="configuredStatus" rules={[{ required: true, message: '请选择广告状态' }]}>
             <New1Radio data={Object.keys(AD_STATUS_ENUM).map(key => ({ label: AD_STATUS_ENUM[key as keyof typeof AD_STATUS_ENUM], value: key }))} />
         </Form.Item>

+ 136 - 88
src/pages/launchSystemV3/tencentAdPutIn/create/Ad/adgroupsMarketingContent.tsx

@@ -6,7 +6,7 @@ import { DispatchAd } from "./newCreateAd"
 import { GOAL_ROAS_ENUM, MARKETING_CARRIER_TYPE_ENUM, MARKETING_TARGET_TYPE_ENUM, MARKETING_TARGET_TYPE_GAME_ENUM, OPTIMIZATIONGOAL_ENUM, defaultSiteSet, marketingGoalGameList, marketingGoalList, marketingSubGoalGameList } from "../../const"
 import New1Radio from "@/pages/launchSystemV3/components/New1Radio"
 import { getOptimizationGoalPermissionsV3Api } from "@/services/adqV3/global"
-import { adRules } from "../../rules"
+import { adRules, sdpRules } from "../../rules"
 import { QuestionCircleFilled } from "@ant-design/icons"
 import { SelectMiniProgramWechat } from "@/pages/launchSystemV3/tencenTasset/miniProgramWechat"
 import { SelectCorpWechat } from "@/pages/launchSystemV3/tencenTasset/corpWechat/manage"
@@ -23,7 +23,7 @@ import { SelectApplication } from "@/pages/launchSystemV3/tencenTasset/applicati
 const AdgroupsMarketingContent: React.FC<{ accountIdList: number[], value?: any }> = ({ accountIdList, value }) => {
 
     /****************************************/
-    const { form, OGPParams, setOGPparams, putInType } = useContext(DispatchAd)!;
+    const { form, OGPParams, setOGPparams, putInType, setSmartDeliveryGoalRules } = useContext(DispatchAd)!;
 
     const marketingGoal = Form.useWatch('marketingGoal', form);
     const marketingSubGoal = Form.useWatch<string>('marketingSubGoal', form);
@@ -36,9 +36,12 @@ const AdgroupsMarketingContent: React.FC<{ accountIdList: number[], value?: any
     const wxGameAppId = Form.useWatch('wxGameAppId', form);
     const depthConversionEnabled = Form.useWatch('depthConversionEnabled', form);
     const deepConversionType = Form.useWatch(['deepConversionSpec', 'deepConversionType'], form);
+    const deliveryMethod = Form.useWatch('deliveryMethod', form);
+    const smartDeliveryPlatform = Form.useWatch('smartDeliveryPlatform', form);
     // 推广产品
     const [marketingTargetTypeList, setMarketingTargetTypeList] = useState<PULLIN.DataType[]>([])
     const [marketingCarrierTypeList, setMarketingCarrierTypeList] = useState<PULLIN.DataType[]>([])
+    const [smartDeliveryGoalList, setSmartDeliveryGoalList] = useState<PULLIN.DataType[]>([])
     const [rules, setRules] = useState<any>({})
     const [behaviorList, setBehaviorList] = useState<string[]>([])
     const [worthList, setWorthList] = useState<string[]>([])
@@ -48,6 +51,35 @@ const AdgroupsMarketingContent: React.FC<{ accountIdList: number[], value?: any
     const queryOptimizationGoalPermissions = useRequest((params) => getOptimizationGoalPermissionsV3Api(params), { manual: true, debounceInterval: 100 })
     /****************************************/
 
+    // 处理投放目标
+    useEffect(() => {
+        if (marketingTargetType && marketingCarrierType && deliveryMethod === "SMART") {
+            const goalTypeRules: string[] = rules?.[marketingTargetType]?.MARKETING_SUB_GOAL_UNKNOWN?.[marketingCarrierType]?.GOAL_TYPE
+            const smartDeliveryGoalOptions = sdpRules.find(item => item.smart_delivery_platform === smartDeliveryPlatform)?.smart_delivery_goal_options
+            if (smartDeliveryGoalOptions && Array.isArray(smartDeliveryGoalOptions)) {
+                const newSmartDeliveryGoalList: PULLIN.DataType[] = []
+                const newSmartDeliveryGoalRules = smartDeliveryGoalOptions.filter(item => {
+                    if (goalTypeRules?.includes(item.value)) {
+                        newSmartDeliveryGoalList.push({ label: item.optimization_goal_combos[0].title, value: item.value })
+                        return true
+                    }
+                    return false
+                })
+                setSmartDeliveryGoalRules(newSmartDeliveryGoalRules)
+                if (newSmartDeliveryGoalList?.length) {
+                    const newSmartDeliveryGoal = newSmartDeliveryGoalList[0]
+                    form.setFieldsValue({
+                        smartDeliverySceneSpec: {
+                            smartDeliveryGoal: newSmartDeliveryGoal.value,
+                            smartDeliveryGoalSpec: {}
+                        }
+                    })
+                }
+                setSmartDeliveryGoalList(newSmartDeliveryGoalList)
+            }
+        }
+    }, [marketingCarrierType, marketingTargetType, rules, deliveryMethod, smartDeliveryPlatform])
+
     /** 获取深度优化 出价和版位改变时查询 */
     const getOptimizationGoalPermissions = () => {
         let marketingCarrierType = OGPParams?.marketingCarrierType
@@ -74,10 +106,10 @@ const AdgroupsMarketingContent: React.FC<{ accountIdList: number[], value?: any
     }
 
     useEffect(() => {
-        if (OGPParams.marketingCarrierType && OGPParams.marketingTargetType) {
+        if (OGPParams.marketingCarrierType && OGPParams.marketingTargetType && deliveryMethod === 'NORMAL') {
             getOptimizationGoalPermissions()
         }
-    }, [OGPParams, putInType, wxGameAppId, accountIdList])
+    }, [OGPParams, putInType, wxGameAppId, accountIdList, deliveryMethod])
 
     // 处理深度转化优化
     useEffect(() => {
@@ -111,8 +143,12 @@ const AdgroupsMarketingContent: React.FC<{ accountIdList: number[], value?: any
         let newMarketingTargetTypeList: PULLIN.DataType[] = []
         if (marketingGoal) {
             // 根据const里数据对比选出可展示数据
-            if (putInType === 'NOVEL') {
-                newRule = adRules[marketingGoal]
+            if (putInType === 'NOVEL' && (deliveryMethod === 'NORMAL' || (deliveryMethod === 'SMART' && smartDeliveryPlatform))) {
+                if (deliveryMethod === 'SMART' && smartDeliveryPlatform) {
+                    newRule = adRules[smartDeliveryPlatform][marketingGoal]
+                } else {
+                    newRule = adRules[marketingGoal]
+                }
                 newMarketingTargetTypeList = Object.keys(MARKETING_TARGET_TYPE_ENUM).filter(key => newRule?.[key]).map(key => ({ label: MARKETING_TARGET_TYPE_ENUM[key as keyof typeof MARKETING_TARGET_TYPE_ENUM], value: key }))
             } else if (putInType === 'GAME') {
                 newRule = adRules[marketingGoal][marketingSubGoal]
@@ -121,7 +157,7 @@ const AdgroupsMarketingContent: React.FC<{ accountIdList: number[], value?: any
         }
         setMarketingTargetTypeList(newMarketingTargetTypeList)
         setRules(newRule)
-    }, [marketingGoal, marketingSubGoal, putInType])
+    }, [marketingGoal, marketingSubGoal, putInType, deliveryMethod, smartDeliveryPlatform])
 
 
     // 推广产品设置默认值
@@ -136,7 +172,7 @@ const AdgroupsMarketingContent: React.FC<{ accountIdList: number[], value?: any
         let newMarketingTargetTypeListList: PULLIN.DataType[] = []
         // 推广产品是公众号不展示 营销载体类型
         if (marketingTargetType) {
-            let marketingTargetTypeRules: string[] = rules?.[marketingTargetType]?.MARKETING_SUB_GOAL_UNKNOWN
+            const marketingTargetTypeRules: string[] = rules?.[marketingTargetType]?.MARKETING_SUB_GOAL_UNKNOWN
             newMarketingTargetTypeListList = Object.keys(MARKETING_CARRIER_TYPE_ENUM).filter(key => marketingTargetTypeRules?.[key as keyof typeof marketingTargetTypeRules]).map(key => ({ label: MARKETING_CARRIER_TYPE_ENUM[key as keyof typeof MARKETING_CARRIER_TYPE_ENUM], value: key }))
         }
         setMarketingCarrierTypeList(newMarketingTargetTypeListList)
@@ -144,7 +180,7 @@ const AdgroupsMarketingContent: React.FC<{ accountIdList: number[], value?: any
 
     // 设置营销载体默认值
     useEffect(() => {
-        if (!(value && Object.keys(value).length > 0) && !marketingCarrierType || (marketingCarrierType && !marketingCarrierTypeList.some(item => item.value === marketingCarrierType))) {
+        if (!(value && Object.keys(value).length > 0) && !marketingCarrierType || (marketingCarrierType && marketingCarrierTypeList?.length && !marketingCarrierTypeList.some(item => item.value === marketingCarrierType))) {
             let newMarketingCarrierType = marketingCarrierTypeList?.[0]?.value
             form.setFieldsValue({ marketingCarrierType: newMarketingCarrierType })
             setOGPparams({ ...OGPParams, marketingTargetType, marketingCarrierType: newMarketingCarrierType })
@@ -189,15 +225,21 @@ const AdgroupsMarketingContent: React.FC<{ accountIdList: number[], value?: any
         className="cardResetCss"
     >
         <Form.Item name="marketingGoal" label={<strong>营销目的</strong>} rules={[{ required: true, message: '请选择营销目的!' }]} hidden={putInType === 'GAME'}>
-            <MarketingGoal data={putInType === 'GAME' ? marketingGoalGameList : marketingGoalList} onChange={(e) => {
-                if (e === 'MARKETING_GOAL_LEAD_RETENTION' && ['MARKETING_TARGET_TYPE_APP_ANDROID', 'MARKETING_TARGET_TYPE_APP_IOS'].includes(marketingTargetType)) {
-                    form.setFieldsValue({
-                        marketingTargetType: 'MARKETING_TARGET_TYPE_FICTION',
-                    })
+            <MarketingGoal
+                data={putInType === 'GAME' ? marketingGoalGameList :
+                    deliveryMethod === 'NORMAL' ? marketingGoalList :
+                        marketingGoalList.filter(item => smartDeliveryPlatform ? Object.keys(adRules[smartDeliveryPlatform]).includes(item.value) : false)
                 }
-                setOGPparams({ ...OGPParams, marketingGoal: e as string });
-                setIsUpdate()
-            }} />
+                onChange={(e) => {
+                    if (e === 'MARKETING_GOAL_LEAD_RETENTION' && ['MARKETING_TARGET_TYPE_APP_ANDROID', 'MARKETING_TARGET_TYPE_APP_IOS'].includes(marketingTargetType)) {
+                        form.setFieldsValue({
+                            marketingTargetType: 'MARKETING_TARGET_TYPE_FICTION',
+                        })
+                    }
+                    setOGPparams({ ...OGPParams, marketingGoal: e as string });
+                    setIsUpdate()
+                }}
+            />
         </Form.Item>
         {putInType === 'GAME' && <Form.Item name="marketingSubGoal" label={<strong>营销目的</strong>} rules={[{ required: true, message: '请选择营销目的!' }]}>
             <MarketingGoal data={marketingSubGoalGameList} onChange={(e) => { setOGPparams({ ...OGPParams, marketingSubGoal: e as string }); setIsUpdate() }} />
@@ -214,8 +256,6 @@ const AdgroupsMarketingContent: React.FC<{ accountIdList: number[], value?: any
             }} />
         </Form.Item>}
 
-
-
         {marketingCarrierTypeList?.length > 0 && <Form.Item name="marketingCarrierType" label={<strong>营销载体类型</strong>} rules={[{ required: true, message: '请选择营销载体类型!' }]}>
             <New1Radio data={marketingCarrierTypeList} onChange={(e) => { setOGPparams({ ...OGPParams, marketingCarrierType: e }); setIsUpdate() }} />
         </Form.Item>}
@@ -251,85 +291,93 @@ const AdgroupsMarketingContent: React.FC<{ accountIdList: number[], value?: any
                 name='isConversion'
                 help="注意账号需要开通权限"
             >
-                <New1Radio data={[{ label: '开启', value: true }, { label: '关闭', value: false }]} />
+                <New1Radio data={[{ label: '开启', value: true }, { label: '关闭', value: false, disabled: deliveryMethod === 'SMART' }]} />
             </Form.Item>}
-            <Form.Item
-                label={<strong>优化目标</strong>}
-                name='optimizationGoal'
-                rules={[{ required: true, message: '请选择优化目标' }]}
-                help={(marketingTargetType === 'MARKETING_TARGET_TYPE_WECHAT_MINI_GAME' && !wxGameAppId) ? '请先选择微信小游戏' : undefined}
-                validateStatus={(marketingTargetType === 'MARKETING_TARGET_TYPE_WECHAT_MINI_GAME' && !wxGameAppId) ? 'error' : undefined}
-            >
-                <Select
-                    style={{ width: 480 }}
-                    showSearch
-                    filterOption={(input, option) =>
-                        (option!.children as unknown as string)?.toLowerCase()?.includes(input?.toLowerCase())
-                    }
-                    disabled={(marketingTargetType === 'MARKETING_TARGET_TYPE_WECHAT_MINI_GAME' && !wxGameAppId)}
-                    allowClear
-                    placeholder='请选择'
-                    loading={queryOptimizationGoalPermissions.loading}
+            {/* 常规投放 优化目标 智能投放不支持 */}
+            {deliveryMethod === 'NORMAL' ? <>
+                <Form.Item
+                    label={<strong>优化目标</strong>}
+                    name='optimizationGoal'
+                    rules={[{ required: true, message: '请选择优化目标' }]}
+                    help={(marketingTargetType === 'MARKETING_TARGET_TYPE_WECHAT_MINI_GAME' && !wxGameAppId) ? '请先选择微信小游戏' : undefined}
+                    validateStatus={(marketingTargetType === 'MARKETING_TARGET_TYPE_WECHAT_MINI_GAME' && !wxGameAppId) ? 'error' : undefined}
                 >
-                    {queryOptimizationGoalPermissions?.data?.data?.optimizationGoalPermissionList.filter((key: string) => key !== 'UNKNOWN').map((key: string) => {
-                        return <Select.Option value={key} key={key}>{OPTIMIZATIONGOAL_ENUM[key as keyof typeof OPTIMIZATIONGOAL_ENUM]}</Select.Option>
-                    })}
-                </Select>
-            </Form.Item>
-            {/* 深度优化 */}
-            {((behaviorList?.length > 0 || worthList?.length > 0) && (marketingTargetType === 'MARKETING_TARGET_TYPE_WECHAT_MINI_GAME' ? !!wxGameAppId : true) && (putInType === 'GAME' ? bidScene !== 'BID_SCENE_NORMAL_MAX' : smartBidType !== 'SMART_BID_TYPE_SYSTEMATIC')) && <>
-                <Form.Item label={<strong>深度转化优化</strong>} name='depthConversionEnabled' valuePropName="checked">
-                    <Switch
+                    <Select
+                        style={{ width: 480 }}
+                        showSearch
+                        filterOption={(input, option) =>
+                            (option!.children as unknown as string)?.toLowerCase()?.includes(input?.toLowerCase())
+                        }
                         disabled={(marketingTargetType === 'MARKETING_TARGET_TYPE_WECHAT_MINI_GAME' && !wxGameAppId)}
-                        checkedChildren="开启"
-                        unCheckedChildren="关闭"
-                        onChange={(e) => {
-                            if (e) {
-                                if (behaviorList?.length > 0) {
-                                    form.setFieldsValue({
-                                        deepConversionSpec: {
-                                            deepConversionType: 'DEEP_CONVERSION_BEHAVIOR',
-                                        }
-                                    })
-                                } else if (worthList?.length > 0) {
-                                    form.setFieldsValue({
-                                        deepConversionSpec: {
-                                            deepConversionType: 'DEEP_CONVERSION_WORTH',
-                                            deepConversionWorthSpec: { roiAllocationMode: 1 }
-                                        }
-                                    })
-                                } else {
-                                    form.setFieldsValue({
-                                        deepConversionSpec: {
-                                            deepConversionType: undefined,
-                                        }
-                                    })
-                                }
-                            }
-                        }}
-                    />
+                        allowClear
+                        placeholder='请选择'
+                        loading={queryOptimizationGoalPermissions.loading}
+                    >
+                        {queryOptimizationGoalPermissions?.data?.data?.optimizationGoalPermissionList.filter((key: string) => key !== 'UNKNOWN').map((key: string) => {
+                            return <Select.Option value={key} key={key}>{OPTIMIZATIONGOAL_ENUM[key as keyof typeof OPTIMIZATIONGOAL_ENUM]}</Select.Option>
+                        })}
+                    </Select>
                 </Form.Item>
-                {depthConversionEnabled && <>
-                    <Form.Item label={<strong>深度优化类型</strong>} name={['deepConversionSpec', 'deepConversionType']} rules={[{ required: true, message: '请选择深度优化类型' }]}>
-                        <New1Radio
-                            data={deepConversionData}
+                {/* 深度优化 */}
+                {((behaviorList?.length > 0 || worthList?.length > 0) && (marketingTargetType === 'MARKETING_TARGET_TYPE_WECHAT_MINI_GAME' ? !!wxGameAppId : true) && (putInType === 'GAME' ? bidScene !== 'BID_SCENE_NORMAL_MAX' : smartBidType !== 'SMART_BID_TYPE_SYSTEMATIC')) && <>
+                    <Form.Item label={<strong>深度转化优化</strong>} name='depthConversionEnabled' valuePropName="checked">
+                        <Switch
+                            disabled={(marketingTargetType === 'MARKETING_TARGET_TYPE_WECHAT_MINI_GAME' && !wxGameAppId)}
+                            checkedChildren="开启"
+                            unCheckedChildren="关闭"
                             onChange={(e) => {
-                                form.setFieldsValue({
-                                    deepConversionSpec: {
-                                        deepConversionType: e,
-                                        ...(e === 'DEEP_CONVERSION_WORTH' ? { deepConversionWorthSpec: { roiAllocationMode: 1 } } : {})
+                                if (e) {
+                                    if (behaviorList?.length > 0) {
+                                        form.setFieldsValue({
+                                            deepConversionSpec: {
+                                                deepConversionType: 'DEEP_CONVERSION_BEHAVIOR',
+                                            }
+                                        })
+                                    } else if (worthList?.length > 0) {
+                                        form.setFieldsValue({
+                                            deepConversionSpec: {
+                                                deepConversionType: 'DEEP_CONVERSION_WORTH',
+                                                deepConversionWorthSpec: { roiAllocationMode: 1 }
+                                            }
+                                        })
+                                    } else {
+                                        form.setFieldsValue({
+                                            deepConversionSpec: {
+                                                deepConversionType: undefined,
+                                            }
+                                        })
                                     }
-                                })
+                                }
                             }}
                         />
                     </Form.Item>
-                    <Form.Item label={<strong>深度优化目标</strong>} name={['deepConversionSpec', deepConversionType === 'DEEP_CONVERSION_BEHAVIOR' ? 'deepConversionBehaviorSpec' : 'deepConversionWorthSpec', 'goal']} rules={[{ required: true, message: '请选择深度优化目标' }]}>
-                        <Select style={{ width: 480 }} placeholder='请选择'>
-                            {deepConversionType === 'DEEP_CONVERSION_BEHAVIOR' ? Object.keys(OPTIMIZATIONGOAL_ENUM).filter(key => behaviorList?.includes(key)).map(key => <Select.Option value={key} key={key}>{OPTIMIZATIONGOAL_ENUM[key as keyof typeof OPTIMIZATIONGOAL_ENUM]}</Select.Option>) : deepConversionType === 'DEEP_CONVERSION_WORTH' ?
-                                Object.keys(GOAL_ROAS_ENUM).filter(key => worthList?.includes(key)).map(key => <Select.Option value={key} key={key}>{GOAL_ROAS_ENUM[key as keyof typeof GOAL_ROAS_ENUM]}</Select.Option>) : null}
-                        </Select>
-                    </Form.Item>
+                    {depthConversionEnabled && <>
+                        <Form.Item label={<strong>深度优化类型</strong>} name={['deepConversionSpec', 'deepConversionType']} rules={[{ required: true, message: '请选择深度优化类型' }]}>
+                            <New1Radio
+                                data={deepConversionData}
+                                onChange={(e) => {
+                                    form.setFieldsValue({
+                                        deepConversionSpec: {
+                                            deepConversionType: e,
+                                            ...(e === 'DEEP_CONVERSION_WORTH' ? { deepConversionWorthSpec: { roiAllocationMode: 1 } } : {})
+                                        }
+                                    })
+                                }}
+                            />
+                        </Form.Item>
+                        <Form.Item label={<strong>深度优化目标</strong>} name={['deepConversionSpec', deepConversionType === 'DEEP_CONVERSION_BEHAVIOR' ? 'deepConversionBehaviorSpec' : 'deepConversionWorthSpec', 'goal']} rules={[{ required: true, message: '请选择深度优化目标' }]}>
+                            <Select style={{ width: 480 }} placeholder='请选择'>
+                                {deepConversionType === 'DEEP_CONVERSION_BEHAVIOR' ? Object.keys(OPTIMIZATIONGOAL_ENUM).filter(key => behaviorList?.includes(key)).map(key => <Select.Option value={key} key={key}>{OPTIMIZATIONGOAL_ENUM[key as keyof typeof OPTIMIZATIONGOAL_ENUM]}</Select.Option>) : deepConversionType === 'DEEP_CONVERSION_WORTH' ?
+                                    Object.keys(GOAL_ROAS_ENUM).filter(key => worthList?.includes(key)).map(key => <Select.Option value={key} key={key}>{GOAL_ROAS_ENUM[key as keyof typeof GOAL_ROAS_ENUM]}</Select.Option>) : null}
+                            </Select>
+                        </Form.Item>
+                    </>}
                 </>}
+            </> : <>
+                {/* 智能投放 投放目标 */}
+                {(smartDeliveryGoalList?.length > 0 && deliveryMethod === 'SMART') && <Form.Item name={['smartDeliverySceneSpec', 'smartDeliveryGoal']} label={<strong>投放目标</strong>} rules={[{ required: true, message: '请选择投放目标!' }]}>
+                    <New1Radio data={smartDeliveryGoalList} />
+                </Form.Item>}
             </>}
         </>}
     </Card>

+ 267 - 144
src/pages/launchSystemV3/tencentAdPutIn/create/Ad/adgroupsPrice.tsx

@@ -1,9 +1,11 @@
 import { Card, Form, Input, InputNumber, Space, Switch, Tooltip } from "antd"
-import React, { useContext } from "react"
+import React, { useContext, useEffect, useState } from "react"
 import { DispatchAd } from "./newCreateAd";
 import New1Radio from "@/pages/launchSystemV3/components/New1Radio";
 import { BID_ALL_OCATION_MODE, BID_MODE_ENUM, BID_SCENE_NORMAL_ENUM, OPTIMIZATIONGOAL_ENUM, ROI_ALL_OCATION_MODE, SMART_BID_TYPE_ENUM } from "../../const";
 import { QuestionCircleFilled } from "@ant-design/icons";
+import { toCamelCase } from "@/utils/utils";
+import style from '../index.less'
 
 
 /**
@@ -13,7 +15,10 @@ import { QuestionCircleFilled } from "@ant-design/icons";
 const AdgroupsPrice: React.FC = () => {
 
     /****************************************/
-    const { form, setOGPparams, OGPParams, putInType } = useContext(DispatchAd)!;
+    const { form, setOGPparams, OGPParams, putInType, smartDeliveryGoalRules } = useContext(DispatchAd)!;
+
+    const [smartDeliveryGoalSpecRules, setSmartDeliveryGoalSpecRules] = useState<PULLIN.SmartDeliveryGoalSpecProps[]>([])
+    const [smartDeliveryGoalSpecName, setSmartDeliveryGoalSpecName] = useState<string>('spec')
 
     const siteSet = Form.useWatch('siteSet', form)
     const bidMode = Form.useWatch('bidMode', form)
@@ -25,9 +30,20 @@ const AdgroupsPrice: React.FC = () => {
     const autoAcquisitionEnabled = Form.useWatch('autoAcquisitionEnabled', form)
     const automaticSiteEnabled = Form.useWatch('automaticSiteEnabled', form)
     const deepConversionType = Form.useWatch(['deepConversionSpec', 'deepConversionType'], form);
+    const deliveryMethod = Form.useWatch('deliveryMethod', form);
+    const smartDeliverySceneSpec = Form.useWatch('smartDeliverySceneSpec', form);
     const goal = Form.useWatch(['deepConversionSpec', deepConversionType === 'DEEP_CONVERSION_BEHAVIOR' ? 'deepConversionBehaviorSpec' : 'deepConversionWorthSpec', 'goal'], form);
     /****************************************/
 
+    useEffect(() => {
+        if (deliveryMethod === 'SMART' && smartDeliveryGoalRules?.length && smartDeliverySceneSpec?.smartDeliveryGoal) {
+            const rule = smartDeliveryGoalRules.find(item => item.value === smartDeliverySceneSpec.smartDeliveryGoal)
+            const smartDeliveryGoalSpecRules = rule?.parameter_definitions?.smart_delivery_goal_spec
+            setSmartDeliveryGoalSpecRules(smartDeliveryGoalSpecRules || [])
+            const smartDeliveryGoalSpecName = toCamelCase(rule?.smart_delivery_goal_spec_name || "")
+            setSmartDeliveryGoalSpecName(smartDeliveryGoalSpecName)
+        }
+    }, [smartDeliveryGoalRules, smartDeliverySceneSpec, deliveryMethod])
 
     return <Card
         title={<strong style={{ fontSize: 18 }}>出价与预算</strong>}
@@ -45,6 +61,7 @@ const AdgroupsPrice: React.FC = () => {
         >
             <New1Radio
                 data={Object.keys(BID_MODE_ENUM).filter(key => {
+                    if (deliveryMethod === 'SMART') return key === 'BID_MODE_OCPM';
                     if (siteSet?.some((name: string) => ['SITE_SET_CHANNELS', 'SITE_SET_MOMENTS'].includes(name)) || automaticSiteEnabled) {
                         return key === 'BID_MODE_OCPM' || key === 'BID_MODE_CPM'
                     } else {
@@ -80,171 +97,277 @@ const AdgroupsPrice: React.FC = () => {
                 }}
             />
         </Form.Item>
-        {(bidMode === 'BID_MODE_OCPM' || bidMode === 'BID_MODE_OCPC') && <>
-            {putInType === 'GAME' ? <Form.Item label={<strong>出价场景</strong>} name='bidScene' rules={[{ required: true, message: '请选择出价场景' }]}>
-                <New1Radio data={Object.keys(BID_SCENE_NORMAL_ENUM).map(key => ({ label: BID_SCENE_NORMAL_ENUM[key as keyof typeof BID_SCENE_NORMAL_ENUM], value: key }))} />
-            </Form.Item> : <Form.Item label={<strong>出价类型</strong>} name='smartBidType' rules={[{ required: true, message: '请选择出价类型' }]}>
-                <New1Radio data={Object.keys(SMART_BID_TYPE_ENUM).map(key => ({ label: SMART_BID_TYPE_ENUM[key as keyof typeof SMART_BID_TYPE_ENUM], value: key }))} />
-            </Form.Item>}
-        </>}
 
-        {(putInType === 'GAME' ? bidScene !== 'BID_SCENE_NORMAL_MAX' : smartBidType !== 'SMART_BID_TYPE_SYSTEMATIC') && <>
-            <Form.Item label={<strong>出价分配方式</strong>} name='bidAllocationMode' rules={[{ required: true, message: '请选择出价分配方式' }]}>
-                <New1Radio data={BID_ALL_OCATION_MODE} />
-            </Form.Item>
+        {deliveryMethod === 'NORMAL' ? <>
+            {/* 常规3.0 */}
+            {(bidMode === 'BID_MODE_OCPM' || bidMode === 'BID_MODE_OCPC') && <>
+                {putInType === 'GAME' ? <Form.Item label={<strong>出价场景</strong>} name='bidScene' rules={[{ required: true, message: '请选择出价场景' }]}>
+                    <New1Radio data={Object.keys(BID_SCENE_NORMAL_ENUM).map(key => ({ label: BID_SCENE_NORMAL_ENUM[key as keyof typeof BID_SCENE_NORMAL_ENUM], value: key }))} />
+                </Form.Item> : <Form.Item label={<strong>出价类型</strong>} name='smartBidType' rules={[{ required: true, message: '请选择出价类型' }]}>
+                    <New1Radio data={Object.keys(SMART_BID_TYPE_ENUM).map(key => ({ label: SMART_BID_TYPE_ENUM[key as keyof typeof SMART_BID_TYPE_ENUM], value: key }))} />
+                </Form.Item>}
+            </>}
 
-            {bidAllocationMode === 1 ? <Form.Item label={<strong>出价</strong>} name='bidAmount' rules={[{ required: true, message: '请输入价格' }]}>
-                <Input
-                    placeholder={`请输入价格`}
-                    style={{ width: 480 }}
-                    suffix={`元/${optimizationGoal ? OPTIMIZATIONGOAL_ENUM[optimizationGoal as keyof typeof OPTIMIZATIONGOAL_ENUM] : ['BID_MODE_OCPM', 'BID_MODE_OCPC'].includes(bidMode) ? '千次曝光' : '点击'}`}
-                />
-            </Form.Item> : <Form.Item label={<strong>{bidAllocationMode === 2 ? '随机出价' : '阶梯出价'}</strong>} required>
-                <Space>
-                    <Form.Item name='bidAmountMin' rules={[{ required: true, message: '请输入价格最小值' }]} noStyle>
-                        <Input
-                            placeholder={`请输入价格最小值`}
-                            style={{ width: 200 }}
-                        />
-                    </Form.Item>
-                    <span>-</span>
-                    <Form.Item name='bidAmountMax' rules={[{ required: true, message: '请输入价格最大值' }]} noStyle>
-                        <Input
-                            placeholder={`请输入价格最大值`}
-                            style={{ width: 200 }}
-                        />
-                    </Form.Item>
-                    <span>元/{optimizationGoal ? OPTIMIZATIONGOAL_ENUM[optimizationGoal as keyof typeof OPTIMIZATIONGOAL_ENUM] : ['BID_MODE_OCPM', 'BID_MODE_OCPC'].includes(bidMode) ? '千次曝光' : '点击'}</span>
-                </Space>
-            </Form.Item>}
+            {(putInType === 'GAME' ? bidScene !== 'BID_SCENE_NORMAL_MAX' : smartBidType !== 'SMART_BID_TYPE_SYSTEMATIC') && <>
+                <Form.Item label={<strong>出价分配方式</strong>} name='bidAllocationMode' rules={[{ required: true, message: '请选择出价分配方式' }]}>
+                    <New1Radio data={BID_ALL_OCATION_MODE} />
+                </Form.Item>
 
+                {bidAllocationMode === 1 ? <Form.Item label={<strong>出价</strong>} name='bidAmount' rules={[{ required: true, message: '请输入价格' }]}>
+                    <Input
+                        placeholder={`请输入价格`}
+                        style={{ width: 480 }}
+                        suffix={`元/${optimizationGoal ? OPTIMIZATIONGOAL_ENUM[optimizationGoal as keyof typeof OPTIMIZATIONGOAL_ENUM] : ['BID_MODE_OCPM', 'BID_MODE_OCPC'].includes(bidMode) ? '千次曝光' : '点击'}`}
+                    />
+                </Form.Item> : <Form.Item label={<strong>{bidAllocationMode === 2 ? '随机出价' : '阶梯出价'}</strong>} required>
+                    <Space>
+                        <Form.Item name='bidAmountMin' rules={[{ required: true, message: '请输入价格最小值' }]} noStyle>
+                            <Input
+                                placeholder={`请输入价格最小值`}
+                                style={{ width: 200 }}
+                            />
+                        </Form.Item>
+                        <span>-</span>
+                        <Form.Item name='bidAmountMax' rules={[{ required: true, message: '请输入价格最大值' }]} noStyle>
+                            <Input
+                                placeholder={`请输入价格最大值`}
+                                style={{ width: 200 }}
+                            />
+                        </Form.Item>
+                        <span>元/{optimizationGoal ? OPTIMIZATIONGOAL_ENUM[optimizationGoal as keyof typeof OPTIMIZATIONGOAL_ENUM] : ['BID_MODE_OCPM', 'BID_MODE_OCPC'].includes(bidMode) ? '千次曝光' : '点击'}</span>
+                    </Space>
+                </Form.Item>}
 
-            {deepConversionType === 'DEEP_CONVERSION_BEHAVIOR' ? <>
-                <Form.Item label={<strong>深度目标出价</strong>} name={['deepConversionSpec', 'deepConversionBehaviorSpec', 'bidAmount']} rules={[{ required: true, message: '请输入深度目标出价' }]}>
-                    <Input style={{ width: 480 }} suffix={`元/${OPTIMIZATIONGOAL_ENUM[goal as keyof typeof OPTIMIZATIONGOAL_ENUM] || '优化目标'}`} placeholder={`请输入深度目标出价,范围0.1~10000`} />
-                </Form.Item>
-            </> :
-                deepConversionType === 'DEEP_CONVERSION_WORTH' ? <>
-                    <Form.Item label={<strong>ROI分配方式</strong>} name={['deepConversionSpec', 'deepConversionWorthSpec', 'roiAllocationMode']} rules={[{ required: true, message: '请选择ROI分配方式' }]}>
-                        <New1Radio data={ROI_ALL_OCATION_MODE} />
+
+                {deepConversionType === 'DEEP_CONVERSION_BEHAVIOR' ? <>
+                    <Form.Item label={<strong>深度目标出价</strong>} name={['deepConversionSpec', 'deepConversionBehaviorSpec', 'bidAmount']} rules={[{ required: true, message: '请输入深度目标出价' }]}>
+                        <Input style={{ width: 480 }} suffix={`元/${OPTIMIZATIONGOAL_ENUM[goal as keyof typeof OPTIMIZATIONGOAL_ENUM] || '优化目标'}`} placeholder={`请输入深度目标出价,范围0.1~10000`} />
                     </Form.Item>
-                    {roiAllocationMode === 1 ? <Form.Item
-                        label={<strong>期望ROI</strong>}
-                        name={['deepConversionSpec', 'deepConversionWorthSpec', 'expectedRoi']}
-                        rules={[
-                            { required: true, message: '请输入期望ROI' },
-                            { type: 'number', ...(goal === 'GOAL_1DAY_MONETIZATION_ROAS' ? { min: 0.001, max: 50, message: '范围0.001~50' } : { min: 0.001, max: 1000, message: '范围0.001~1000' }) },
-                            {
-                                validator: (_: any, value: string) => {
-                                    if (!value || /^\d+(\.\d{0,3})?$/.test(value)) {
-                                        return Promise.resolve();
+                </> :
+                    deepConversionType === 'DEEP_CONVERSION_WORTH' ? <>
+                        <Form.Item label={<strong>ROI分配方式</strong>} name={['deepConversionSpec', 'deepConversionWorthSpec', 'roiAllocationMode']} rules={[{ required: true, message: '请选择ROI分配方式' }]}>
+                            <New1Radio data={ROI_ALL_OCATION_MODE} />
+                        </Form.Item>
+                        {roiAllocationMode === 1 ? <Form.Item
+                            label={<strong>期望ROI</strong>}
+                            name={['deepConversionSpec', 'deepConversionWorthSpec', 'expectedRoi']}
+                            rules={[
+                                { required: true, message: '请输入期望ROI' },
+                                { type: 'number', ...(goal === 'GOAL_1DAY_MONETIZATION_ROAS' ? { min: 0.001, max: 50, message: '范围0.001~50' } : { min: 0.001, max: 1000, message: '范围0.001~1000' }) },
+                                {
+                                    validator: (_: any, value: string) => {
+                                        if (!value || /^\d+(\.\d{0,3})?$/.test(value)) {
+                                            return Promise.resolve();
+                                        }
+                                        return Promise.reject(new Error('请输入最多三位小数'));
                                     }
-                                    return Promise.reject(new Error('请输入最多三位小数'));
                                 }
-                            }
-                        ]}
-                    >
-                        <InputNumber style={{ width: 480 }} placeholder={`期望ROI目标范围${goal === 'GOAL_1DAY_MONETIZATION_ROAS' ? '0.001~50' : '0.001~1000'},输入0.05,表示ROI目标为5%`} />
-                    </Form.Item> : <Form.Item label={<strong>{roiAllocationMode === 2 ? '随机ROI' : '阶梯ROI'}</strong>} required>
-                        <Space>
-                            <Form.Item
-                                name={['deepConversionSpec', 'deepConversionWorthSpec', 'expectedRoiMin']}
-                                rules={[
-                                    { required: true, message: '请输入期望ROI最小值' },
-                                    { type: 'number', ...(goal === 'GOAL_1DAY_MONETIZATION_ROAS' ? { min: 0.001, max: 50, message: '范围0.001~50' } : { min: 0.001, max: 1000, message: '范围0.001~1000' }) },
-                                    {
-                                        validator: (_: any, value: string) => {
-                                            if (!value || /^\d+(\.\d{0,3})?$/.test(value)) {
-                                                return Promise.resolve();
+                            ]}
+                        >
+                            <InputNumber style={{ width: 480 }} placeholder={`期望ROI目标范围${goal === 'GOAL_1DAY_MONETIZATION_ROAS' ? '0.001~50' : '0.001~1000'},输入0.05,表示ROI目标为5%`} />
+                        </Form.Item> : <Form.Item label={<strong>{roiAllocationMode === 2 ? '随机ROI' : '阶梯ROI'}</strong>} required>
+                            <Space>
+                                <Form.Item
+                                    name={['deepConversionSpec', 'deepConversionWorthSpec', 'expectedRoiMin']}
+                                    rules={[
+                                        { required: true, message: '请输入期望ROI最小值' },
+                                        { type: 'number', ...(goal === 'GOAL_1DAY_MONETIZATION_ROAS' ? { min: 0.001, max: 50, message: '范围0.001~50' } : { min: 0.001, max: 1000, message: '范围0.001~1000' }) },
+                                        {
+                                            validator: (_: any, value: string) => {
+                                                if (!value || /^\d+(\.\d{0,3})?$/.test(value)) {
+                                                    return Promise.resolve();
+                                                }
+                                                return Promise.reject(new Error('请输入最多三位小数'));
                                             }
-                                            return Promise.reject(new Error('请输入最多三位小数'));
                                         }
-                                    }
-                                ]}
-                                noStyle
-                            >
-                                <InputNumber
-                                    placeholder={`请输入期望ROI最小值`}
-                                    style={{ width: 228 }}
-                                />
-                            </Form.Item>
-                            <span>-</span>
-                            <Form.Item
-                                name={['deepConversionSpec', 'deepConversionWorthSpec', 'expectedRoiMax']}
-                                rules={[
-                                    { required: true, message: '请输入期望ROI最大值' },
-                                    { type: 'number', ...(goal === 'GOAL_1DAY_MONETIZATION_ROAS' ? { min: 0.001, max: 50, message: '范围0.001~50' } : { min: 0.001, max: 1000, message: '范围0.001~1000' }) },
-                                    {
-                                        validator: (_: any, value: string) => {
-                                            if (!value || /^\d+(\.\d{0,3})?$/.test(value)) {
-                                                return Promise.resolve();
+                                    ]}
+                                    noStyle
+                                >
+                                    <InputNumber
+                                        placeholder={`请输入期望ROI最小值`}
+                                        style={{ width: 228 }}
+                                    />
+                                </Form.Item>
+                                <span>-</span>
+                                <Form.Item
+                                    name={['deepConversionSpec', 'deepConversionWorthSpec', 'expectedRoiMax']}
+                                    rules={[
+                                        { required: true, message: '请输入期望ROI最大值' },
+                                        { type: 'number', ...(goal === 'GOAL_1DAY_MONETIZATION_ROAS' ? { min: 0.001, max: 50, message: '范围0.001~50' } : { min: 0.001, max: 1000, message: '范围0.001~1000' }) },
+                                        {
+                                            validator: (_: any, value: string) => {
+                                                if (!value || /^\d+(\.\d{0,3})?$/.test(value)) {
+                                                    return Promise.resolve();
+                                                }
+                                                return Promise.reject(new Error('请输入最多三位小数'));
                                             }
-                                            return Promise.reject(new Error('请输入最多三位小数'));
                                         }
-                                    }
-                                ]}
-                                noStyle
-                            >
-                                <InputNumber
-                                    placeholder={`请输入期望ROI最大值`}
-                                    style={{ width: 228 }}
-                                />
-                            </Form.Item>
-                        </Space>
-                    </Form.Item>}
-                </> : null}
-            {optimizationGoal === 'OPTIMIZATIONGOAL_24H_FIRSTPAY' && <Form.Item
-                style={{ marginBottom: 10 }}
-                label={<Space>
-                    <strong>一方数据跑量加强</strong>
-                    <Tooltip title={<div>
-                        <p>基于您规范回传的一方数据,系统将其作为补充样本针对性优化OCPX模型,并助力提升广告投放拿量能力</p>
-                    </div>}>
-                        <QuestionCircleFilled />
-                    </Tooltip>
-                </Space>}
-                name='ecomPkamSwitch'
-                valuePropName="checked"
-                help="注意账号需要开通权限"
-            >
-                <Switch checkedChildren="开启" unCheckedChildren="关闭" />
-            </Form.Item>}
-            {((bidMode === 'BID_MODE_OCPM' || bidMode === 'BID_MODE_OCPC') && (putInType === 'GAME' ? bidScene !== 'BID_SCENE_NORMAL_MAX' : smartBidType !== 'SMART_BID_TYPE_SYSTEMATIC')) && <>
-                <Form.Item
+                                    ]}
+                                    noStyle
+                                >
+                                    <InputNumber
+                                        placeholder={`请输入期望ROI最大值`}
+                                        style={{ width: 228 }}
+                                    />
+                                </Form.Item>
+                            </Space>
+                        </Form.Item>}
+                    </> : null}
+                {optimizationGoal === 'OPTIMIZATIONGOAL_24H_FIRSTPAY' && <Form.Item
                     style={{ marginBottom: 10 }}
                     label={<Space>
-                        <strong>一键起量</strong>
+                        <strong>一方数据跑量加强</strong>
                         <Tooltip title={<div>
-                            <p>1. 一键起量原理:给该广告提供一笔起量预算,系统会在 6 小时内快速花完预算,帮助广告激进探索,获取更多曝光,期间转化成本可能高于预期;</p>
-                            <p>
-                                <span>2. 一键起量注意事项:</span><br />
-                                探索中任何原因导致广告暂停播放,都会导致起量中止,且恢复播放后也不会再继续探索; 一键起量期间产生的消耗不赔付,但转化计入赔付门槛判断;你可以在该广告的一键起量状态中止或结束时,重新设置起量预算,开始一次新的起量周期
-                            </p>
-                            <p>
-                                <span>点击查看</span><a href="https://e.qq.com/ads/helpcenter/detail?cid=3532&pid=2004" target="__blank">赔付规则</a><br />
-                                <span>点击了解</span><a href="https://e.qq.com/ads/helpcenter/detail?cid=3532&pid=2005" target="__blank">一键起量</a>
-                            </p>
+                            <p>基于您规范回传的一方数据,系统将其作为补充样本针对性优化OCPX模型,并助力提升广告投放拿量能力</p>
                         </div>}>
                             <QuestionCircleFilled />
                         </Tooltip>
                     </Space>}
-                    name='autoAcquisitionEnabled'
+                    name='ecomPkamSwitch'
                     valuePropName="checked"
+                    help="注意账号需要开通权限"
                 >
                     <Switch checkedChildren="开启" unCheckedChildren="关闭" />
-                </Form.Item>
-                {/* 一键起量开启时才出现 */}
-                {autoAcquisitionEnabled && <Form.Item
-                    name='autoAcquisitionBudget'
-                    rules={[{ required: true, message: '请输入起量预算' }]}
-                    help={<div>
-                        <span>1. 一键起量期间产生的消耗不赔付,但转化计入赔付门槛判断</span><br />
-                        <span>2. 一键起量可能导致转化成本高于预期,且起量结束后不一定能持续消耗</span>
-                    </div>}
-                >
-                    <Input placeholder='请输入起量预算,建议设置为出价的10倍,范围 200~100000 元,不能低于出价' style={{ width: 560 }} suffix="元" />
                 </Form.Item>}
+                {((bidMode === 'BID_MODE_OCPM' || bidMode === 'BID_MODE_OCPC') && (putInType === 'GAME' ? bidScene !== 'BID_SCENE_NORMAL_MAX' : smartBidType !== 'SMART_BID_TYPE_SYSTEMATIC')) && <>
+                    <Form.Item
+                        style={{ marginBottom: 10 }}
+                        label={<Space>
+                            <strong>一键起量</strong>
+                            <Tooltip title={<div>
+                                <p>1. 一键起量原理:给该广告提供一笔起量预算,系统会在 6 小时内快速花完预算,帮助广告激进探索,获取更多曝光,期间转化成本可能高于预期;</p>
+                                <p>
+                                    <span>2. 一键起量注意事项:</span><br />
+                                    探索中任何原因导致广告暂停播放,都会导致起量中止,且恢复播放后也不会再继续探索; 一键起量期间产生的消耗不赔付,但转化计入赔付门槛判断;你可以在该广告的一键起量状态中止或结束时,重新设置起量预算,开始一次新的起量周期
+                                </p>
+                                <p>
+                                    <span>点击查看</span><a href="https://e.qq.com/ads/helpcenter/detail?cid=3532&pid=2004" target="__blank">赔付规则</a><br />
+                                    <span>点击了解</span><a href="https://e.qq.com/ads/helpcenter/detail?cid=3532&pid=2005" target="__blank">一键起量</a>
+                                </p>
+                            </div>}>
+                                <QuestionCircleFilled />
+                            </Tooltip>
+                        </Space>}
+                        name='autoAcquisitionEnabled'
+                        valuePropName="checked"
+                    >
+                        <Switch checkedChildren="开启" unCheckedChildren="关闭" />
+                    </Form.Item>
+                    {/* 一键起量开启时才出现 */}
+                    {autoAcquisitionEnabled && <Form.Item
+                        name='autoAcquisitionBudget'
+                        rules={[{ required: true, message: '请输入起量预算' }]}
+                        help={<div>
+                            <span>1. 一键起量期间产生的消耗不赔付,但转化计入赔付门槛判断</span><br />
+                            <span>2. 一键起量可能导致转化成本高于预期,且起量结束后不一定能持续消耗</span>
+                        </div>}
+                    >
+                        <Input placeholder='请输入起量预算,建议设置为出价的10倍,范围 200~100000 元,不能低于出价' style={{ width: 560 }} suffix="元" />
+                    </Form.Item>}
+                </>}
             </>}
+        </> : <>
+            {/* 智投 */}
+            <Form.Item label={<strong>出价分配方式</strong>} name='bidAllocationMode' rules={[{ required: true, message: '请选择出价分配方式' }]}>
+                <New1Radio data={BID_ALL_OCATION_MODE} />
+            </Form.Item>
+            <Form.Item label={<strong>投放目标出价</strong>} required>
+                <Card bordered className="cardResetCss newCss" bodyStyle={{ padding: 0, backgroundColor: '#fafafa' }}>
+                    {smartDeliveryGoalSpecRules.map((item, index) => {
+                        return <div className={style.newSpace} key={index}>
+                            <div className={style.newSpace_top}>
+                                <div className={style.newSpace_title}>{item.title}</div>
+                                {bidAllocationMode === 1 ? <Form.Item
+                                    style={{ marginBottom: 0 }}
+                                    name={['smartDeliverySceneSpec', 'smartDeliveryGoalSpec', smartDeliveryGoalSpecName, toCamelCase(item.field_name)]}
+                                    rules={[
+                                        { required: item.required, message: `请输入${item.title}` },
+                                        {
+                                            validator: (_: any, value: string) => {
+                                                if (value === undefined || value === null || value === '') return Promise.resolve();
+                                                const num = parseFloat(value);
+                                                if (isNaN(num)) return Promise.reject(new Error('请输入有效的数字'));
+                                                if (num < item.min || num > item.max) return Promise.reject(new Error(`范围${item.min}~${item.max}`));
+                                                return Promise.resolve();
+                                            }
+                                        },
+                                        {
+                                            validator: (_: any, value: string) => {
+                                                const regex = new RegExp(`^\\d+(\\.\\d{0,${item.decimal_length}})?$`);
+                                                if (!value || regex.test(value)) {
+                                                    return Promise.resolve();
+                                                }
+                                                return Promise.reject(new Error(`请输入最多${item.decimal_length}位小数`));
+                                            }
+                                        }
+                                    ]}
+                                >
+                                    <Input style={{ width: 480 }} placeholder={item.placeholder} suffix={item.unitTips} />
+                                </Form.Item> : <Space>
+                                    <Form.Item
+                                        style={{ marginBottom: 0 }}
+                                        name={['smartDeliverySceneSpec', 'smartDeliveryGoalSpec', smartDeliveryGoalSpecName, toCamelCase(item.field_name + '_min')]}
+                                        rules={[
+                                            { required: item.required, message: `请输入${item.title}最小值` },
+                                            {
+                                                validator: (_: any, value: string) => {
+                                                    if (value === undefined || value === null || value === '') return Promise.resolve();
+                                                    const num = parseFloat(value);
+                                                    if (isNaN(num)) return Promise.reject(new Error('最小值请输入有效的数字'));
+                                                    if (num < item.min || num > item.max) return Promise.reject(new Error(`最小值范围${item.min}~${item.max}`));
+                                                    return Promise.resolve();
+                                                }
+                                            },
+                                            {
+                                                validator: (_: any, value: string) => {
+                                                    const regex = new RegExp(`^\\d+(\\.\\d{0,${item.decimal_length}})?$`);
+                                                    if (!value || regex.test(value)) {
+                                                        return Promise.resolve();
+                                                    }
+                                                    return Promise.reject(new Error(`最小值请输入最多${item.decimal_length}位小数`));
+                                                }
+                                            }
+                                        ]}
+                                        noStyle
+                                    >
+                                        <Input style={{ width: 240 }} placeholder={item.placeholder + '最小值'} />
+                                    </Form.Item>
+                                    <span>-</span>
+                                    <Form.Item
+                                        style={{ marginBottom: 0 }}
+                                        name={['smartDeliverySceneSpec', 'smartDeliveryGoalSpec', smartDeliveryGoalSpecName, toCamelCase(item.field_name + '_max')]}
+                                        rules={[
+                                            { required: item.required, message: `请输入${item.title}最大值` },
+                                            {
+                                                validator: (_: any, value: string) => {
+                                                    if (value === undefined || value === null || value === '') return Promise.resolve();
+                                                    const num = parseFloat(value);
+                                                    if (isNaN(num)) return Promise.reject(new Error('最大值请输入有效的数字'));
+                                                    if (num < item.min || num > item.max) return Promise.reject(new Error(`最大值范围${item.min}~${item.max}`));
+                                                    return Promise.resolve();
+                                                }
+                                            },
+                                            {
+                                                validator: (_: any, value: string) => {
+                                                    const regex = new RegExp(`^\\d+(\\.\\d{0,${item.decimal_length}})?$`);
+                                                    if (!value || regex.test(value)) {
+                                                        return Promise.resolve();
+                                                    }
+                                                    return Promise.reject(new Error(`最大值请输入最多${item.decimal_length}位小数`));
+                                                }
+                                            }
+                                        ]}
+                                        noStyle
+                                    >
+                                        <Input style={{ width: 240 }} placeholder={item.placeholder + '最大值'} />
+                                    </Form.Item>
+                                    <span>{item.unitTips}</span>
+                                </Space>}
+                            </div>
+                        </div>
+                    })}
+                </Card>
+            </Form.Item>
         </>}
 
         <Form.Item label={<strong>广告日预算</strong>} name='dailyBudget' rules={[{ required: (smartBidType === 'SMART_BID_TYPE_SYSTEMATIC' || bidScene === 'BID_SCENE_NORMAL_MAX'), message: '请输入广告日预算' }]}>

+ 63 - 0
src/pages/launchSystemV3/tencentAdPutIn/create/Ad/adgroupsPutInType.tsx

@@ -0,0 +1,63 @@
+import { Card, Form } from "antd";
+import React, { useContext } from "react";
+import { DispatchAd } from "./newCreateAd";
+import DeliveryMethod from "./deliveryMethod";
+import NewRadio from "@/pages/launchSystemV3/components/NewRadio";
+import { SMART_DELIVERY_PLATFORM_ENUM } from "../../const";
+
+
+const AdgroupsPutInType: React.FC = () => {
+
+    /****************************************/
+    const { form, putInType, setOGPparams, OGPParams } = useContext(DispatchAd)!;
+    const deliveryMethod = Form.useWatch('deliveryMethod', form);
+    /****************************************/
+
+    return <Card
+        title={<strong style={{ fontSize: 18 }}>投放方式</strong>}
+        className="cardResetCss"
+    >
+        <Form.Item
+            name="deliveryMethod"
+            label={<strong>投放方式</strong>}
+            rules={[{ required: true, message: '请选择投放方式!' }]}
+            help="智能投放属于白名单功能,请确认账户已拥有权限后开启"
+        >
+            <DeliveryMethod
+                data={[{ label: '常规投放', value: 'NORMAL', desc: '常规的3.0广告新建' }, { label: '智能投放', value: 'SMART', desc: '行业化的智能投放工具', disabled: putInType === 'GAME' }]}
+                onChange={(v) => {
+                    if (v === 'NORMAL') {
+                        // 重置
+                        form.resetFields()
+                        form.setFieldsValue({
+                            marketingTargetType: 'MARKETING_TARGET_TYPE_FICTION',
+                            marketingCarrierType: 'MARKETING_CARRIER_TYPE_WECHAT_OFFICIAL_ACCOUNT'
+                        })
+                        setOGPparams({ ...OGPParams, marketingGoal: 'MARKETING_GOAL_PRODUCT_SALES' });
+                    } else {
+                        form.setFieldsValue({
+                            smartDeliveryPlatform: 'SMART_DELIVERY_PLATFORM_EDITION_FICTION',
+                            marketingGoal: "MARKETING_GOAL_PRODUCT_SALES",
+                            marketingCarrierType: 'MARKETING_CARRIER_TYPE_WECHAT_OFFICIAL_ACCOUNT',
+                            siteSet: null,
+                            isConversion: true,          // 开启转化归因新链路 固定不可改
+                            automaticSiteEnabled: true,  // 开启智能版位 固定不可改
+                            explorationStrategy: 'AUTOMATIC_EXPLORATION',  // 探索策略 自动探索
+                            searchExpandTargetingSwitch: 'SEARCH_EXPAND_TARGETING_SWITCH_OPEN', //定向拓展 
+                            bidMode: 'BID_MODE_OCPM',   // 计费方式
+                            // searchExpansionWitch: 'SEARCH_EXPANSION_SWITCH_OPEN',   // 搜索扩量开关,ADX 程序化广告不可填写提交 看看后期添加
+                            // bidAmount: 150,   //看看后期添加
+                            // marketingSubGoal: 'MARKETING_SUB_GOAL_UNKNOWN', // 看后期添加  二级营销目的
+                        })
+                    }
+                }}
+            />
+        </Form.Item>
+
+        {deliveryMethod === 'SMART' && <Form.Item style={{ marginBottom: 0 }} name="smartDeliveryPlatform" label={<strong>投放场景</strong>} rules={[{ required: true, message: '请选择投放场景!' }]}>
+            <NewRadio data={(Object.keys(SMART_DELIVERY_PLATFORM_ENUM) as Array<keyof typeof SMART_DELIVERY_PLATFORM_ENUM>).map((key) => ({ label: SMART_DELIVERY_PLATFORM_ENUM[key], value: key }))} />
+        </Form.Item>}
+    </Card>
+}
+
+export default React.memo(AdgroupsPutInType);

+ 25 - 20
src/pages/launchSystemV3/tencentAdPutIn/create/Ad/adgroupsSitSet.tsx

@@ -8,6 +8,7 @@ import { QuestionCircleFilled } from "@ant-design/icons";
 import style from '../index.less'
 import { getSceneTagsList } from "@/services/launchAdq/global";
 import { useAjax } from "@/Hook/useAjax";
+import { ReactComponent as MiaosiSvg } from '@/assets/x-miaosi-mini-brand.svg'
 
 /**
  * 广告版位
@@ -29,6 +30,7 @@ const AdgroupsSitSet: React.FC = () => {
     const officialAccountMediaCategory = Form.useWatch(['wechatScene', 'officialAccountMediaCategory'], form);
     const miniProgramAndMiniGame = Form.useWatch(['wechatScene', 'miniProgramAndMiniGame'], form);
     const payScene = Form.useWatch(['wechatScene', 'payScene'], form);
+    const deliveryMethod = Form.useWatch('deliveryMethod', form);
 
     const [OFFICIAL_ACCOUNT_MEDIA_CATEGORY, SET_OFFICIAL_ACCOUNT_MEDIA_CATEGORY] = useState<{ description: string, id: number }[]>([])
     const [MINI_PROGRAM_AND_MINI_GAME, SET_MINI_PROGRAM_AND_MINI_GAME] = useState<{ description: string, id: number }[]>([])
@@ -42,26 +44,31 @@ const AdgroupsSitSet: React.FC = () => {
 
     // 场景定向
     useEffect(() => {
-        sceneTagsList.run({ typeList: ['WECHAT_POSITION', 'OFFICIAL_ACCOUNT_MEDIA_CATEGORY', 'MINI_PROGRAM_AND_MINI_GAME', 'PAY_SCENE', 'MOBILE_UNION_CATEGORY', 'WECHAT_CHANNELS_SCENE'] }).then(res => {
-            let NEW_OFFICIAL_ACCOUNT_MEDIA_CATEGORY = res?.OFFICIAL_ACCOUNT_MEDIA_CATEGORY
-            let NEW_MINI_PROGRAM_AND_MINI_GAME = res?.MINI_PROGRAM_AND_MINI_GAME
-            let NEW_PAY_SCENE = res?.PAY_SCENE
-            SET_OFFICIAL_ACCOUNT_MEDIA_CATEGORY(NEW_OFFICIAL_ACCOUNT_MEDIA_CATEGORY || [])
-            SET_MINI_PROGRAM_AND_MINI_GAME(NEW_MINI_PROGRAM_AND_MINI_GAME || [])
-            SET_PAY_SCENE(NEW_PAY_SCENE || [])
-            setNoLimitOAMC(NEW_OFFICIAL_ACCOUNT_MEDIA_CATEGORY?.filter((i: { description: string; }) => i.description === '不限')?.[0].id)
-            setNoLimitMPAMG(NEW_MINI_PROGRAM_AND_MINI_GAME?.filter((i: { description: string; }) => i.description === '不限')?.[0].id)
-            setNoLimitPS(NEW_PAY_SCENE?.filter((i: { description: string; }) => i.description === '不限')?.[0].id)
-        })
-    }, [])
+        if (deliveryMethod === 'NORMAL') {
+            sceneTagsList.run({ typeList: ['WECHAT_POSITION', 'OFFICIAL_ACCOUNT_MEDIA_CATEGORY', 'MINI_PROGRAM_AND_MINI_GAME', 'PAY_SCENE', 'MOBILE_UNION_CATEGORY', 'WECHAT_CHANNELS_SCENE'] }).then(res => {
+                let NEW_OFFICIAL_ACCOUNT_MEDIA_CATEGORY = res?.OFFICIAL_ACCOUNT_MEDIA_CATEGORY
+                let NEW_MINI_PROGRAM_AND_MINI_GAME = res?.MINI_PROGRAM_AND_MINI_GAME
+                let NEW_PAY_SCENE = res?.PAY_SCENE
+                SET_OFFICIAL_ACCOUNT_MEDIA_CATEGORY(NEW_OFFICIAL_ACCOUNT_MEDIA_CATEGORY || [])
+                SET_MINI_PROGRAM_AND_MINI_GAME(NEW_MINI_PROGRAM_AND_MINI_GAME || [])
+                SET_PAY_SCENE(NEW_PAY_SCENE || [])
+                setNoLimitOAMC(NEW_OFFICIAL_ACCOUNT_MEDIA_CATEGORY?.filter((i: { description: string; }) => i.description === '不限')?.[0].id)
+                setNoLimitMPAMG(NEW_MINI_PROGRAM_AND_MINI_GAME?.filter((i: { description: string; }) => i.description === '不限')?.[0].id)
+                setNoLimitPS(NEW_PAY_SCENE?.filter((i: { description: string; }) => i.description === '不限')?.[0].id)
+            })
+        }
+    }, [deliveryMethod])
 
     return <Card
-        title={<strong style={{ fontSize: 18 }}>广告版位</strong>}
+        title={deliveryMethod === 'NORMAL' ?
+            <strong style={{ fontSize: 18 }}>广告版位</strong> :
+            <strong style={{ fontSize: 18 }}>智能版位 <span style={{ color: 'rgba(51,55,61,0.58)', fontSize: 12 }}><span role="img" aria-label="fund-view" className="anticon anticon-fund-view"><MiaosiSvg /></span>系统将智能进行版位择优投放</span></strong>
+        }
         className="cardResetCss"
     >
         <Form.Item name="automaticSiteEnabled" style={{ marginBottom: automaticSiteEnabled ? 24 : 10 }} label={<strong>版位选择</strong>} rules={[{ required: true, message: '版位选择!' }]}>
             <New1Radio
-                data={[{ label: '自动版位', value: true }, { label: '选择特定版位', value: false }]}
+                data={[{ label: '智能版位', value: true }, { label: '选择特定版位', value: false, disabled: deliveryMethod === 'SMART' }]}
                 onChange={(e) => {
                     form.setFieldsValue({ siteSet: defaultSiteSet, explorationStrategy: 'AUTOMATIC_EXPLORATION' })
                     setOGPparams({ ...OGPParams, automaticSiteEnabled: e, siteSet: defaultSiteSet })
@@ -88,7 +95,7 @@ const AdgroupsSitSet: React.FC = () => {
             <Form.Item name="explorationStrategy" label={<strong>探索策略</strong>} rules={[{ required: true, message: '探索策略!' }]}>
                 <Radio.Group>
                     <Radio value={'AUTOMATIC_EXPLORATION'}>自动探索</Radio>
-                    <Radio value={'STEADY_EXPLORATION'}>稳步探索</Radio>
+                    <Radio value={'STEADY_EXPLORATION'} disabled={deliveryMethod === 'SMART'}>稳步探索</Radio>
                 </Radio.Group>
             </Form.Item>
             {explorationStrategy === 'STEADY_EXPLORATION' && <Form.Item
@@ -121,7 +128,7 @@ const AdgroupsSitSet: React.FC = () => {
                         <div className={style.newSpace_title}>定向拓展</div>
                         <Form.Item name="searchExpandTargetingSwitch" style={{ marginBottom: 0 }}>
                             <Radio.Group buttonStyle="solid">
-                                <Radio.Button value="SEARCH_EXPAND_TARGETING_SWITCH_CLOSE">关闭</Radio.Button>
+                                <Radio.Button value="SEARCH_EXPAND_TARGETING_SWITCH_CLOSE" disabled={deliveryMethod === 'SMART'}>关闭</Radio.Button>
                                 <Radio.Button value="SEARCH_EXPAND_TARGETING_SWITCH_OPEN">开启</Radio.Button>
                             </Radio.Group>
                         </Form.Item>
@@ -130,9 +137,8 @@ const AdgroupsSitSet: React.FC = () => {
             </Card>
         </Form.Item>
 
-        <Form.Item style={{ marginBottom: 0 }}>
+        {deliveryMethod === 'NORMAL' && <Form.Item style={{ marginBottom: 0 }}>
             <Card bordered className="cardResetCss newCss" bodyStyle={{ padding: 0 }}>
-
                 {(siteSet?.includes('SITE_SET_WECHAT') || automaticSiteEnabled) && <div className={style.newSpace}>
                     <div className={style.newSpace_top}>
                         <div className={style.newSpace_title}>微信公众号与小程序定投</div>
@@ -288,9 +294,8 @@ const AdgroupsSitSet: React.FC = () => {
                         </Form.Item>
                     </div>}
                 </div>}
-
             </Card>
-        </Form.Item>
+        </Form.Item>}
     </Card>
 }
 

+ 38 - 0
src/pages/launchSystemV3/tencentAdPutIn/create/Ad/deliveryMethod.tsx

@@ -0,0 +1,38 @@
+import React from "react"
+import style from './index.less'
+import { CheckCircleFilled } from "@ant-design/icons"
+
+
+/**
+ * 投放方式
+ * @param param0 
+ * @returns 
+ */
+const DeliveryMethod: React.FC<PULLIN.FormItemDataNewProps<string>> = ({ data, value, onChange }) => {
+
+
+    return <div className={style.marketingGoal}>
+        <div className={style.marketingGoal_row}>
+            {
+                data.map(item => <div
+                    key={item.value}
+                    onClick={() => {
+                        if (!item.disabled) {
+                            onChange?.(item.value)
+                        }
+                    }}
+                    className={`${style.marketingGoal_col} ${value === item.value ? style.marketingGoal_active : ''} ${item.disabled ? style.marketingGoal_disable : ''}`}
+                    style={{ height:  60, width: 200, alignItems: 'flex-start', padding: '0 10px' }}
+                >
+                    {value === item.value ? <>
+                        <div><CheckCircleFilled /></div>
+                    </> : null}
+                    <span>{item.label}</span>
+                    <p style={{}}>{item.desc}</p>
+                </div>)
+            }
+        </div>
+    </div>
+}
+
+export default React.memo(DeliveryMethod)

+ 32 - 0
src/pages/launchSystemV3/tencentAdPutIn/create/Ad/index.less

@@ -37,6 +37,13 @@
             color: rgb(49, 50, 51);
         }
 
+        >p {
+            font-size: 12px;
+            font-weight: 400;
+            color: rgb(153, 153, 153);
+            margin: 0;
+        }
+
         >div {
             color: #1890ff;
             position: absolute;
@@ -64,6 +71,10 @@
             font-weight: 600;
         }
 
+        >p {
+            color: #1890ff;
+        }
+
         >img {
             transform: scale(1.2);
         }
@@ -73,4 +84,25 @@
             border-color: rgba(41, 107, 239, 0.8);
         }
     }
+
+    .marketingGoal_disable {
+        cursor: not-allowed;
+        background: #f2f4fa;
+
+        >span {
+            color: rgb(153, 153, 153);
+        }
+
+        >p {
+            color: rgb(153, 153, 153);
+        }
+
+        >img {
+            transform: scale(1);
+        }
+
+        &:hover {
+            background: #f2f4fa;
+        }
+    }
 }

+ 114 - 64
src/pages/launchSystemV3/tencentAdPutIn/create/Ad/index.tsx

@@ -1,10 +1,10 @@
-import React, { useContext, useState } from "react"
+import React, { useContext, useMemo, useState } from "react"
 import style from '../index.less'
 import NewCreateAd from "./newCreateAd"
 import { DispatchAddelivery } from "..";
 import { Button, Modal, Typography } from "antd";
 import { EditOutlined } from "@ant-design/icons";
-import { AD_STATUS_ENUM, BID_ALL_OCATION_MODE, BID_MODE_ENUM, BID_SCENE_NORMAL_ENUM, DEEP_CONVERSION_ENUM, GOAL_ROAS_ENUM, MARKETING_CARRIER_TYPE_ENUM, MARKETING_GOAL_ENUM, MARKETING_SUB_GOAL_ENUM, MARKETING_TARGET_TYPE_ENUM, MARKETING_TARGET_TYPE_GAME_ENUM, OPTIMIZATIONGOAL_ENUM, ROI_ALL_OCATION_MODE, SITE_SET_ENUM, SMART_BID_TYPE_ENUM } from "../../const";
+import { AD_STATUS_ENUM, BID_ALL_OCATION_MODE, BID_MODE_ENUM, BID_SCENE_NORMAL_ENUM, DEEP_CONVERSION_ENUM, GOAL_ROAS_ENUM, MARKETING_CARRIER_TYPE_ENUM, MARKETING_GOAL_ENUM, MARKETING_SUB_GOAL_ENUM, MARKETING_TARGET_TYPE_ENUM, MARKETING_TARGET_TYPE_GAME_ENUM, OPTIMIZATIONGOAL_ENUM, ROI_ALL_OCATION_MODE, SITE_SET_ENUM, SMART_BID_TYPE_ENUM, SMART_DELIVERY_GOAL_ENUM, SMART_DELIVERY_PLATFORM_ENUM } from "../../const";
 import TimeSeriesLook from "@/pages/launchSystemNew/adq/ad/timeSeriesLook";
 import { arraysHaveSameValues } from "@/utils/utils";
 import '../../index.less'
@@ -22,13 +22,27 @@ const Ad: React.FC = () => {
     const { addelivery, setAddelivery, accountCreateLogs, clearData, setAccountCreateLogs, putInType, setIsDqSubmit } = useContext(DispatchAddelivery)!;
     const { adgroups } = addelivery
     const {
-        marketingGoal, marketingSubGoal, marketingAssetOuterSpec, marketingCarrierType, automaticSiteEnabled, explorationStrategy, siteSet, prioritySiteSet, searchExpandTargetingSwitch, bidMode, smartBidType, bidScene, bidAmount, optimizationGoal, isConversion, depthConversionEnabled,
+        deliveryMethod, marketingGoal, marketingSubGoal, marketingAssetOuterSpec, marketingCarrierType, automaticSiteEnabled, explorationStrategy, siteSet, prioritySiteSet, searchExpandTargetingSwitch, bidMode, smartBidType, bidScene, bidAmount, optimizationGoal, isConversion, depthConversionEnabled,
         deepConversionSpec, ecomPkamSwitch, autoAcquisitionEnabled, autoAcquisitionBudget, dailyBudget, endDate, beginDate, timeSeries, firstDayBeginTime, configuredStatus, adgroupName, sceneSpec, autoDerivedCreativeEnabled, sysWechatAppId, wxGameAppId, promoteApplicationId, rtaId, rtaTargetId, bidAllocationMode,
-        bidAmountMin, bidAmountMax
+        bidAmountMin, bidAmountMax, smartDeliveryPlatform, smartDeliverySceneSpec
     } = adgroups
     const [newVisible, setNewVisible] = useState<boolean>(false)
     /*****************************/
 
+    // 智能投放出价
+    const smartModel = useMemo(() => {
+        if (deliveryMethod === 'SMART') {
+            const goalDto = SMART_DELIVERY_GOAL_ENUM[smartDeliverySceneSpec?.smartDeliveryGoal as keyof typeof SMART_DELIVERY_GOAL_ENUM]
+            if ([2, 3].includes(bidAllocationMode)) {
+                const data = smartDeliverySceneSpec?.smartDeliveryGoalSpec?.[goalDto?.smartDeliveryGoalSpecName]
+                return goalDto?.smartDeliveryGoalSpec?.map(item => <p key={item.field_name} style={{ fontWeight: 'bold', color: '#000' }}>{item.title}: {data?.[item.field_name + 'Min']}-{data?.[item.field_name + 'Max']}{item?.unitTips || ''}</p>)
+            } else {
+                return goalDto?.smartDeliveryGoalSpec?.map(item => <p key={item.field_name} style={{ fontWeight: 'bold', color: '#000' }}>{item.title}: {smartDeliverySceneSpec?.smartDeliveryGoalSpec?.[goalDto?.smartDeliveryGoalSpecName]?.[item.field_name]}{item?.unitTips || ''}</p>)
+            }
+        }
+        return null
+    }, [smartDeliverySceneSpec, deliveryMethod, bidAllocationMode])
+
     return <>
         <div className={`${style.settingsBody_content_row} ${style.row1}`}>
             <div className={style.title}>
@@ -38,70 +52,106 @@ const Ad: React.FC = () => {
                 <div className={style.detail_body}>
                     {(adgroups && Object.keys(adgroups).length > 0) ? <>
                         <p style={{ fontWeight: 'bold', color: configuredStatus === 'AD_STATUS_NORMAL' ? '#52c41a' : '#FF4D4F' }}>广告状态:{AD_STATUS_ENUM[configuredStatus as keyof typeof AD_STATUS_ENUM]}</p>
-                        {putInType === 'NOVEL' ? <>
-                            <p>营销目的:{MARKETING_GOAL_ENUM[marketingGoal as keyof typeof MARKETING_GOAL_ENUM]}</p>
-                            <p style={{ fontWeight: 'bold', color: '#000' }}>推广产品类型:{MARKETING_TARGET_TYPE_ENUM[marketingAssetOuterSpec?.marketingTargetType as keyof typeof MARKETING_TARGET_TYPE_ENUM]}</p>
-                        </> : <>
-                            <p>营销目的:{MARKETING_SUB_GOAL_ENUM[marketingSubGoal as keyof typeof MARKETING_SUB_GOAL_ENUM]}</p>
-                            <p style={{ fontWeight: 'bold', color: '#000' }}>推广产品类型:{MARKETING_TARGET_TYPE_GAME_ENUM[marketingAssetOuterSpec?.marketingTargetType as keyof typeof MARKETING_TARGET_TYPE_GAME_ENUM]}</p>
-                        </>}
-                        {marketingAssetOuterSpec?.marketingTargetType === 'MARKETING_TARGET_TYPE_MINI_PROGRAM_WECHAT' ?
-                            <ShowMiniProgramWechatDetail id={sysWechatAppId} /> :
-                            marketingAssetOuterSpec?.marketingTargetType === 'MARKETING_TARGET_TYPE_WECHAT_MINI_GAME' ?
-                                <ShowGameAppIdDetail appId={wxGameAppId} /> :
-                                null
-                        }
-                        <p>营销载体类型:{MARKETING_CARRIER_TYPE_ENUM[marketingCarrierType as keyof typeof MARKETING_CARRIER_TYPE_ENUM]}</p>
-                        {['MARKETING_CARRIER_TYPE_APP_ANDROID', 'MARKETING_CARRIER_TYPE_APP_IOS'].includes(marketingCarrierType) && <ShowApplication id={promoteApplicationId} />}
-                        <p>版位选择:{automaticSiteEnabled ? '自动版位' : '选择特定版位'}</p>
-                        {!automaticSiteEnabled && <Typography.Paragraph className={style.tpP} style={{ marginBottom: 0 }} ellipsis={{ tooltip: true, rows: 2 }}>广告版位:{siteSet.map((item: string | number) => SITE_SET_ENUM[item as keyof typeof SITE_SET_ENUM]).toString()}</Typography.Paragraph>}
-                        {automaticSiteEnabled && <>
-                            <p>探索策略:{explorationStrategy === 'STEADY_EXPLORATION' ? '稳步探索' : '自动探索'}</p>
-                            {prioritySiteSet?.length > 0 && <Typography.Paragraph className={style.tpP} style={{ marginBottom: 0 }} ellipsis={{ tooltip: true, rows: 2 }}>优先探索版位:{prioritySiteSet.map((item: string | number) => SITE_SET_ENUM[item as keyof typeof SITE_SET_ENUM]).toString()}</Typography.Paragraph>}
-                        </>}
-                        <p>搜索场景扩量:{searchExpandTargetingSwitch === 'SEARCH_EXPAND_TARGETING_SWITCH_OPEN' ? '开启' : '关闭'}</p>
-                        {rtaId && <p>RTA ID:{rtaId}</p>}
-                        {rtaTargetId && <p>策略 ID:{rtaTargetId}</p>}
-                        <p>计费方式:{BID_MODE_ENUM[bidMode as keyof typeof BID_MODE_ENUM]}</p>
-                        {putInType === 'GAME' ? <>
-                            <p>出价场景:{BID_SCENE_NORMAL_ENUM[bidScene as keyof typeof BID_SCENE_NORMAL_ENUM]}</p>
-                        </> : <p>出价类型:{SMART_BID_TYPE_ENUM[smartBidType as keyof typeof SMART_BID_TYPE_ENUM]}</p>}
-                        <p style={{ fontWeight: 'bold', color: '#000' }}>出价分配方式:{BID_ALL_OCATION_MODE.find(item => item.value === bidAllocationMode)?.label}</p>
-                        {[2, 3].includes(bidAllocationMode)
-                            ?
-                            <p style={{ fontWeight: 'bold', color: '#000' }}>出价:{bidAmountMin}-{bidAmountMax} 元/{optimizationGoal ? OPTIMIZATIONGOAL_ENUM[optimizationGoal as keyof typeof OPTIMIZATIONGOAL_ENUM] : ['BID_MODE_OCPM', 'BID_MODE_OCPC'].includes(bidMode) ? '千次曝光' : '点击'}</p>
-                            :
-                            <p style={{ fontWeight: 'bold', color: '#000' }}>出价:{bidAmount} 元/{optimizationGoal ? OPTIMIZATIONGOAL_ENUM[optimizationGoal as keyof typeof OPTIMIZATIONGOAL_ENUM] : ['BID_MODE_OCPM', 'BID_MODE_OCPC'].includes(bidMode) ? '千次曝光' : '点击'}</p>
-                        }
+                        <p style={{ fontWeight: 'bold', color: '#000' }}>投放方式:{deliveryMethod === 'SMART' ? '智能投放' : '常规投放'}</p>
+                        {deliveryMethod === 'NORMAL' ? <>
+                            {putInType === 'NOVEL' ? <>
+                                <p>营销目的:{MARKETING_GOAL_ENUM[marketingGoal as keyof typeof MARKETING_GOAL_ENUM]}</p>
+                                <p style={{ fontWeight: 'bold', color: '#000' }}>推广产品类型:{MARKETING_TARGET_TYPE_ENUM[marketingAssetOuterSpec?.marketingTargetType as keyof typeof MARKETING_TARGET_TYPE_ENUM]}</p>
+                            </> : <>
+                                <p>营销目的:{MARKETING_SUB_GOAL_ENUM[marketingSubGoal as keyof typeof MARKETING_SUB_GOAL_ENUM]}</p>
+                                <p style={{ fontWeight: 'bold', color: '#000' }}>推广产品类型:{MARKETING_TARGET_TYPE_GAME_ENUM[marketingAssetOuterSpec?.marketingTargetType as keyof typeof MARKETING_TARGET_TYPE_GAME_ENUM]}</p>
+                            </>}
+                            {marketingAssetOuterSpec?.marketingTargetType === 'MARKETING_TARGET_TYPE_MINI_PROGRAM_WECHAT' ?
+                                <ShowMiniProgramWechatDetail id={sysWechatAppId} /> :
+                                marketingAssetOuterSpec?.marketingTargetType === 'MARKETING_TARGET_TYPE_WECHAT_MINI_GAME' ?
+                                    <ShowGameAppIdDetail appId={wxGameAppId} /> :
+                                    null
+                            }
+                            <p>营销载体类型:{MARKETING_CARRIER_TYPE_ENUM[marketingCarrierType as keyof typeof MARKETING_CARRIER_TYPE_ENUM]}</p>
+                            {['MARKETING_CARRIER_TYPE_APP_ANDROID', 'MARKETING_CARRIER_TYPE_APP_IOS'].includes(marketingCarrierType) && <ShowApplication id={promoteApplicationId} />}
+                            <p>版位选择:{automaticSiteEnabled ? '智能版位' : '选择特定版位'}</p>
+                            {!automaticSiteEnabled && <Typography.Paragraph className={style.tpP} style={{ marginBottom: 0 }} ellipsis={{ tooltip: true, rows: 2 }}>广告版位:{siteSet.map((item: string | number) => SITE_SET_ENUM[item as keyof typeof SITE_SET_ENUM]).toString()}</Typography.Paragraph>}
+                            {automaticSiteEnabled && <>
+                                <p>探索策略:{explorationStrategy === 'STEADY_EXPLORATION' ? '稳步探索' : '自动探索'}</p>
+                                {prioritySiteSet?.length > 0 && <Typography.Paragraph className={style.tpP} style={{ marginBottom: 0 }} ellipsis={{ tooltip: true, rows: 2 }}>优先探索版位:{prioritySiteSet.map((item: string | number) => SITE_SET_ENUM[item as keyof typeof SITE_SET_ENUM]).toString()}</Typography.Paragraph>}
+                            </>}
+                            <p>搜索场景扩量:{searchExpandTargetingSwitch === 'SEARCH_EXPAND_TARGETING_SWITCH_OPEN' ? '开启' : '关闭'}</p>
+                            {rtaId && <p>RTA ID:{rtaId}</p>}
+                            {rtaTargetId && <p>策略 ID:{rtaTargetId}</p>}
+                            <p>计费方式:{BID_MODE_ENUM[bidMode as keyof typeof BID_MODE_ENUM]}</p>
+                            {putInType === 'GAME' ? <>
+                                <p>出价场景:{BID_SCENE_NORMAL_ENUM[bidScene as keyof typeof BID_SCENE_NORMAL_ENUM]}</p>
+                            </> : <p>出价类型:{SMART_BID_TYPE_ENUM[smartBidType as keyof typeof SMART_BID_TYPE_ENUM]}</p>}
+                            <p style={{ fontWeight: 'bold', color: '#000' }}>出价分配方式:{BID_ALL_OCATION_MODE.find(item => item.value === bidAllocationMode)?.label}</p>
+                            {[2, 3].includes(bidAllocationMode)
+                                ?
+                                <p style={{ fontWeight: 'bold', color: '#000' }}>出价:{bidAmountMin}-{bidAmountMax} 元/{optimizationGoal ? OPTIMIZATIONGOAL_ENUM[optimizationGoal as keyof typeof OPTIMIZATIONGOAL_ENUM] : ['BID_MODE_OCPM', 'BID_MODE_OCPC'].includes(bidMode) ? '千次曝光' : '点击'}</p>
+                                :
+                                <p style={{ fontWeight: 'bold', color: '#000' }}>出价:{bidAmount} 元/{optimizationGoal ? OPTIMIZATIONGOAL_ENUM[optimizationGoal as keyof typeof OPTIMIZATIONGOAL_ENUM] : ['BID_MODE_OCPM', 'BID_MODE_OCPC'].includes(bidMode) ? '千次曝光' : '点击'}</p>
+                            }
 
-                        {isConversion && <p style={{ fontWeight: 'bold', color: '#000' }}>转化:新链路转化</p>}
-                        {optimizationGoal && <p style={{ fontWeight: 'bold', color: '#000' }}>优化目标:{OPTIMIZATIONGOAL_ENUM[optimizationGoal as keyof typeof OPTIMIZATIONGOAL_ENUM]}</p>}
-                        {deepConversionSpec && <>
-                            <p style={{ fontWeight: 'bold', color: '#000' }}>深度转化优化:开启</p>
-                            <p style={{ fontWeight: 'bold', color: '#000' }}>深度优化类型:{DEEP_CONVERSION_ENUM[deepConversionSpec?.deepConversionType as keyof typeof DEEP_CONVERSION_ENUM]}</p>
-                            {deepConversionSpec.deepConversionType === 'DEEP_CONVERSION_BEHAVIOR' ? <>
-                                <p style={{ fontWeight: 'bold', color: '#000' }}>深度优化目标:{OPTIMIZATIONGOAL_ENUM[deepConversionSpec.deepConversionBehaviorSpec.goal as keyof typeof OPTIMIZATIONGOAL_ENUM]}</p>
-                                <p style={{ fontWeight: 'bold', color: '#000' }}>深度目标出价:{deepConversionSpec.deepConversionBehaviorSpec.bidAmount}元/{OPTIMIZATIONGOAL_ENUM[deepConversionSpec.deepConversionBehaviorSpec.goal as keyof typeof OPTIMIZATIONGOAL_ENUM] || '优化目标'}</p>
+                            {isConversion && <p style={{ fontWeight: 'bold', color: '#000' }}>转化:新链路转化</p>}
+                            {optimizationGoal && <p style={{ fontWeight: 'bold', color: '#000' }}>优化目标:{OPTIMIZATIONGOAL_ENUM[optimizationGoal as keyof typeof OPTIMIZATIONGOAL_ENUM]}</p>}
+                            {deepConversionSpec && <>
+                                <p style={{ fontWeight: 'bold', color: '#000' }}>深度转化优化:开启</p>
+                                <p style={{ fontWeight: 'bold', color: '#000' }}>深度优化类型:{DEEP_CONVERSION_ENUM[deepConversionSpec?.deepConversionType as keyof typeof DEEP_CONVERSION_ENUM]}</p>
+                                {deepConversionSpec.deepConversionType === 'DEEP_CONVERSION_BEHAVIOR' ? <>
+                                    <p style={{ fontWeight: 'bold', color: '#000' }}>深度优化目标:{OPTIMIZATIONGOAL_ENUM[deepConversionSpec.deepConversionBehaviorSpec.goal as keyof typeof OPTIMIZATIONGOAL_ENUM]}</p>
+                                    <p style={{ fontWeight: 'bold', color: '#000' }}>深度目标出价:{deepConversionSpec.deepConversionBehaviorSpec.bidAmount}元/{OPTIMIZATIONGOAL_ENUM[deepConversionSpec.deepConversionBehaviorSpec.goal as keyof typeof OPTIMIZATIONGOAL_ENUM] || '优化目标'}</p>
+                                </> : <>
+                                    <p style={{ fontWeight: 'bold', color: '#000' }}>深度优化目标:{GOAL_ROAS_ENUM[deepConversionSpec.deepConversionWorthSpec.goal as keyof typeof GOAL_ROAS_ENUM]}</p>
+                                    <p style={{ fontWeight: 'bold', color: '#000' }}>ROI分配方式:{ROI_ALL_OCATION_MODE.find(item => item.value === deepConversionSpec?.deepConversionWorthSpec?.roiAllocationMode)?.label}</p>
+                                    {[2, 3].includes(deepConversionSpec?.deepConversionWorthSpec?.roiAllocationMode)
+                                        ?
+                                        <p style={{ fontWeight: 'bold', color: '#000' }}>期望ROI:{deepConversionSpec.deepConversionWorthSpec.expectedRoiMin}-{deepConversionSpec.deepConversionWorthSpec.expectedRoiMax}</p>
+                                        :
+                                        <p style={{ fontWeight: 'bold', color: '#000' }}>期望ROI:{deepConversionSpec.deepConversionWorthSpec.expectedRoi}</p>
+                                    }
+                                </>}
+                            </>}
+                            <p>一方人群跑量加强:{ecomPkamSwitch === 'ECOM_PKAM_SWITCH_OPEN' ? '开启' : '关闭'}</p>
+                            <p>一键起量:{autoAcquisitionEnabled ? '开启' : '关闭'}</p>
+                            {autoAcquisitionEnabled && <p>起量预算:{autoAcquisitionBudget}元/天</p>}
+                            <p>广告日预算:{dailyBudget ? dailyBudget + '元/天' : '不限'}</p>
+                            <p style={{ fontWeight: 'bold', color: '#000' }}>投放日期:{beginDate} 至 {endDate || '长期投放'}</p>
+                            <p>投放时段:{timeSeries.includes('0') ? <TimeSeriesLook timeSeries={timeSeries} /> : '全天'}</p>
+                            <p>首日开始时间:{firstDayBeginTime ? firstDayBeginTime : '关闭'}</p>
+                            <p>自动衍生创意:{autoDerivedCreativeEnabled ? '系统衍生' : '关闭衍生'}</p>
+                            <p>广告名称:{adgroupName}</p>
+                        </> : <>
+                            {/* 智能投放 */}
+                            <p style={{ fontWeight: 'bold', color: '#000' }}>投放场景:{SMART_DELIVERY_PLATFORM_ENUM[smartDeliveryPlatform as keyof typeof SMART_DELIVERY_PLATFORM_ENUM]}</p>
+                            {putInType === 'NOVEL' ? <>
+                                <p>营销目的:{MARKETING_GOAL_ENUM[marketingGoal as keyof typeof MARKETING_GOAL_ENUM]}</p>
+                                <p style={{ fontWeight: 'bold', color: '#000' }}>推广产品类型:{MARKETING_TARGET_TYPE_ENUM[marketingAssetOuterSpec?.marketingTargetType as keyof typeof MARKETING_TARGET_TYPE_ENUM]}</p>
                             </> : <>
-                                <p style={{ fontWeight: 'bold', color: '#000' }}>深度优化目标:{GOAL_ROAS_ENUM[deepConversionSpec.deepConversionWorthSpec.goal as keyof typeof GOAL_ROAS_ENUM]}</p>
-                                <p style={{ fontWeight: 'bold', color: '#000' }}>ROI分配方式:{ROI_ALL_OCATION_MODE.find(item => item.value === deepConversionSpec?.deepConversionWorthSpec?.roiAllocationMode)?.label}</p>
-                                {[2, 3].includes(deepConversionSpec?.deepConversionWorthSpec?.roiAllocationMode)
-                                    ?
-                                    <p style={{ fontWeight: 'bold', color: '#000' }}>期望ROI:{deepConversionSpec.deepConversionWorthSpec.expectedRoiMin}-{deepConversionSpec.deepConversionWorthSpec.expectedRoiMax}</p>
-                                    :
-                                    <p style={{ fontWeight: 'bold', color: '#000' }}>期望ROI:{deepConversionSpec.deepConversionWorthSpec.expectedRoi}</p>
-                                }
+                                <p>营销目的:{MARKETING_SUB_GOAL_ENUM[marketingSubGoal as keyof typeof MARKETING_SUB_GOAL_ENUM]}</p>
+                                <p style={{ fontWeight: 'bold', color: '#000' }}>推广产品类型:{MARKETING_TARGET_TYPE_GAME_ENUM[marketingAssetOuterSpec?.marketingTargetType as keyof typeof MARKETING_TARGET_TYPE_GAME_ENUM]}</p>
+                            </>}
+                            {marketingAssetOuterSpec?.marketingTargetType === 'MARKETING_TARGET_TYPE_MINI_PROGRAM_WECHAT' ?
+                                <ShowMiniProgramWechatDetail id={sysWechatAppId} /> :
+                                marketingAssetOuterSpec?.marketingTargetType === 'MARKETING_TARGET_TYPE_WECHAT_MINI_GAME' ?
+                                    <ShowGameAppIdDetail appId={wxGameAppId} /> :
+                                    null
+                            }
+                            <p>营销载体类型:{MARKETING_CARRIER_TYPE_ENUM[marketingCarrierType as keyof typeof MARKETING_CARRIER_TYPE_ENUM]}</p>
+                            {['MARKETING_CARRIER_TYPE_APP_ANDROID', 'MARKETING_CARRIER_TYPE_APP_IOS'].includes(marketingCarrierType) && <ShowApplication id={promoteApplicationId} />}
+                            <p>版位选择:{automaticSiteEnabled ? '智能版位' : '选择特定版位'}</p>
+                            {automaticSiteEnabled && <>
+                                <p>探索策略:{explorationStrategy === 'STEADY_EXPLORATION' ? '稳步探索' : '自动探索'}</p>
                             </>}
+                            <p>搜索场景扩量:{searchExpandTargetingSwitch === 'SEARCH_EXPAND_TARGETING_SWITCH_OPEN' ? '开启' : '关闭'}</p>
+                            <p>计费方式:{BID_MODE_ENUM[bidMode as keyof typeof BID_MODE_ENUM]}</p>
+                            {smartDeliverySceneSpec?.smartDeliveryGoal && <p style={{ fontWeight: 'bold', color: '#000' }}>投放目标:{SMART_DELIVERY_GOAL_ENUM[smartDeliverySceneSpec?.smartDeliveryGoal as keyof typeof SMART_DELIVERY_GOAL_ENUM]?.title}</p>}
+                            <p style={{ fontWeight: 'bold', color: '#000' }}>出价分配方式:{BID_ALL_OCATION_MODE.find(item => item.value === bidAllocationMode)?.label}</p>
+                            {smartModel}
+                            {isConversion && <p style={{ fontWeight: 'bold', color: '#000' }}>转化:新链路转化</p>}
+                            <p>广告日预算:{dailyBudget ? dailyBudget + '元/天' : '不限'}</p>
+                            <p style={{ fontWeight: 'bold', color: '#000' }}>投放日期:{beginDate} 至 {endDate || '长期投放'}</p>
+                            <p>投放时段:{timeSeries.includes('0') ? <TimeSeriesLook timeSeries={timeSeries} /> : '全天'}</p>
+                            <p>首日开始时间:{firstDayBeginTime ? firstDayBeginTime : '关闭'}</p>
+                            <p>广告名称:{adgroupName}</p>
                         </>}
-                        <p>一方人群跑量加强:{ecomPkamSwitch === 'ECOM_PKAM_SWITCH_OPEN' ? '开启' : '关闭'}</p>
-                        <p>一键起量:{autoAcquisitionEnabled ? '开启' : '关闭'}</p>
-                        {autoAcquisitionEnabled && <p>起量预算:{autoAcquisitionBudget}元/天</p>}
-                        <p>广告日预算:{dailyBudget ? dailyBudget + '元/天' : '不限'}</p>
-                        <p style={{ fontWeight: 'bold', color: '#000' }}>投放日期:{beginDate} 至 {endDate || '长期投放'}</p>
-                        <p>投放时段:{timeSeries.includes('0') ? <TimeSeriesLook timeSeries={timeSeries} /> : '全天'}</p>
-                        <p>首日开始时间:{firstDayBeginTime ? firstDayBeginTime : '关闭'}</p>
-                        <p>自动衍生创意:{autoDerivedCreativeEnabled ? '系统衍生' : '关闭衍生'}</p>
-                        <p>广告名称:{adgroupName}</p>
                     </> : <div className={style.ad_config}>
                         {accountCreateLogs?.length > 0 ?
                             <div className={style.ad_config_item} onClick={() => setNewVisible(true)}>新建广告</div>

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

@@ -9,6 +9,7 @@ import AdgroupsAdSetting from "./adgroupsAdSetting"
 import moment from "moment"
 import { getTimeSeriesList } from "@/pages/launchSystemNew/adq/ad/const"
 import AdgroupsTarget from "./adgroupsTarget"
+import AdgroupsPutInType from "./adgroupsPutInType"
 
 export const DispatchAd = React.createContext<PULLIN.AdReactContent | null>(null);
 
@@ -33,6 +34,7 @@ const NewCreateAd: React.FC<Props> = ({ accountIdList, value, visible, onChange,
     const marketingCarrierType = Form.useWatch('marketingCarrierType', form);
     // 深度优化副作用参数
     const [OGPParams, setOGPparams] = useState<PULLIN.OGPParamsProps>({ bidMode: 'BID_MODE_OCPM', siteSet: defaultSiteSet, automaticSiteEnabled: false, marketingGoal: putInType === 'NOVEL' ? defaultMarketingGoal : defaultGameMarketingGoal, marketingSubGoal: putInType === 'GAME' ? 'MARKETING_SUB_GOAL_MINI_GAME_NEW_CUSTOMER_GROWTH' : undefined })
+    const [smartDeliveryGoalRules, setSmartDeliveryGoalRules] = useState<PULLIN.SmartDeliveryGoalOption[]>([])
     /***********************************/
 
     const handleOk = (values: any) => {
@@ -95,6 +97,15 @@ const NewCreateAd: React.FC<Props> = ({ accountIdList, value, visible, onChange,
                 delete adgroupsValues[key]
             }
         })
+
+        if (values?.deliveryMethod === 'SMART') {
+            // 搜索扩量开关
+            adgroupsValues.searchExpansionWitch = 'SEARCH_EXPANSION_SWITCH_OPEN'
+            adgroupsValues.bidAmount = 1.5
+            // 二级营销目的
+            adgroupsValues.marketingSubGoal = 'MARKETING_SUB_GOAL_UNKNOWN'
+        }
+        console.log('adgroupsValues', adgroupsValues)
         onChange?.(adgroupsValues)
     }
 
@@ -226,6 +237,7 @@ const NewCreateAd: React.FC<Props> = ({ accountIdList, value, visible, onChange,
             }}
             onFinish={handleOk}
             initialValues={{
+                deliveryMethod: 'NORMAL',
                 marketingGoal: putInType === 'NOVEL' ? defaultMarketingGoal : putInType === 'GAME' ? defaultGameMarketingGoal : undefined,
                 marketingSubGoal: putInType === 'GAME' ? 'MARKETING_SUB_GOAL_MINI_GAME_NEW_CUSTOMER_GROWTH' : undefined,
                 automaticSiteEnabled: false,
@@ -262,8 +274,10 @@ const NewCreateAd: React.FC<Props> = ({ accountIdList, value, visible, onChange,
                 smartTargetingMode: 'SMART_TARGETING_MANUAL'
             }}
         >
-            <DispatchAd.Provider value={{ form, OGPParams, setOGPparams, putInType }}>
+            <DispatchAd.Provider value={{ form, OGPParams, setOGPparams, putInType, smartDeliveryGoalRules, setSmartDeliveryGoalRules }}>
                 <Space direction="vertical" style={{ width: '100%' }}>
+                    {/* 投放方式 */}
+                    <AdgroupsPutInType />
                     {/* 营销内容 */}
                     <AdgroupsMarketingContent value={value} accountIdList={accountIdList} />
                     {/* 广告版位 */}

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

@@ -35,7 +35,7 @@ const CreativeTemplateContent: React.FC<{ automaticSiteEnabled: boolean, putInTy
                     brand = creativeComponents[key]
                     let page_type = brand.children.page_type
                     let typeList = ["PAGE_TYPE_WECHAT_OFFICIAL_ACCOUNT_DETAIL", "PAGE_TYPE_H5_PROFILE", "PAGE_TYPE_NOT_USED", "PAGE_TYPE_WECHAT_CHANNELS_PROFILE"]
-                    enumeration = (page_type.enumProperty.enumeration as { value: string, description: string }[]).filter((item: { value: string; }) => typeList.includes(item.value)).map(item => ({ label: item.value === 'PAGE_TYPE_NOT_USED' ? '品牌形象' : item.description, value: item.value }))
+                    enumeration = (page_type.enumProperty.enumeration as { value: string, description: string }[]).filter((item: { value: string; }) => typeList.includes(item.value)).map(item => ({ label: item.value === 'PAGE_TYPE_NOT_USED' ? '自定义' : item.description, value: item.value }))
                     break
                 case 'jump_info':
                     let jump_info = creativeComponents[key]

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

@@ -44,7 +44,7 @@ const NewDynamic: React.FC<Props> = ({ putInType, value: newValue, visible, onCl
     const [adcreativeTemplateList, setAdcreativeTemplateList] = useState<PULLIN.AdcreativeTemplateList[]>([])
     const [creativeComponents, setCreativeComponents] = useState<any>({})
     const [isUpdate, setIsUpdate] = useState<boolean>(false)
-    const { marketingGoal, marketingAssetOuterSpec, marketingCarrierType, siteSet, sceneSpec, automaticSiteEnabled, marketingSubGoal } = adgroups
+    const { marketingGoal, marketingAssetOuterSpec, marketingCarrierType, siteSet, sceneSpec, automaticSiteEnabled, marketingSubGoal, deliveryMethod } = adgroups
 
     const [newMaterialData, setNewMaterialData] = useState<any>({}) // 素材数据
     const [newTextData, setNewTextData] = useState<any>({})
@@ -676,7 +676,7 @@ const NewDynamic: React.FC<Props> = ({ putInType, value: newValue, visible, onCl
                                     setTimeout(() => { setIsUpdate(true) }, 50)
                                     setValue(undefined)
                                 }}>
-                                    {Object.keys(DELIVERY_MODE_ENUM).map(key => <Radio value={key} key={key}>{DELIVERY_MODE_ENUM[key as keyof typeof DELIVERY_MODE_ENUM]}</Radio>)}
+                                    {Object.keys(DELIVERY_MODE_ENUM).map(key => <Radio value={key} disabled={deliveryMethod === 'SMART' ? key === 'DELIVERY_MODE_CUSTOMIZE' : false} key={key}>{DELIVERY_MODE_ENUM[key as keyof typeof DELIVERY_MODE_ENUM]}</Radio>)}
                                 </Radio.Group>
                             </Form.Item>
                             {(deliveryMode === 'DELIVERY_MODE_CUSTOMIZE' || dynamicCreativeSwitch) && <>

+ 580 - 575
src/pages/launchSystemV3/tencentAdPutIn/create/Target/addTarget.tsx

@@ -21,9 +21,10 @@ interface Props {
     visible?: boolean
     onClose?: () => void
     onChange?: (targeting?: any) => void
+    targetRules?: PULLIN.TargetingRulesProps
 }
 
-const AddTarget: React.FC<Props> = ({ isBackVal, putInType, value, visible, onChange, onClose }) => {
+const AddTarget: React.FC<Props> = ({ isBackVal, putInType, value, visible, onChange, onClose, targetRules }) => {
 
     /******************************/
     const [form] = Form.useForm();
@@ -33,8 +34,6 @@ const AddTarget: React.FC<Props> = ({ isBackVal, putInType, value, visible, onCh
     const wechatAdBehaviorType = Form.useWatch('wechatAdBehaviorType', form);
     const userOsType = Form.useWatch('userOsType', form);
     const ageType = Form.useWatch('ageType', form);
-    const min = Form.useWatch(['age', 'min'], form);
-    const max = Form.useWatch(['age', 'max'], form);
     const age = Form.useWatch('age', form);
     const education = Form.useWatch('education', form);
     const networkType = Form.useWatch('networkType', form);
@@ -410,6 +409,11 @@ const AddTarget: React.FC<Props> = ({ isBackVal, putInType, value, visible, onCh
         return false;
     }
 
+    // 智能投放 判断是否展示可添加定向
+    const isShow = (field: string) => {
+        return (targetRules?.rules && targetRules?.rules?.length > 0) ? targetRules?.rules?.includes(field) : true
+    }
+
     return <Modal
         title={isBackVal ? <strong style={{ fontSize: 20 }}>
             {(value && Object.keys(value).length > 0) ? `修改定向` : `新增定向`}
@@ -419,604 +423,605 @@ const AddTarget: React.FC<Props> = ({ isBackVal, putInType, value, visible, onCh
         footer={null}
         width={920}
         className={`modalResetCss`}
-        bodyStyle={{ padding: '0 0 40px', position: 'relative', borderRadius: '0 0 8px 8px' }}
+        bodyStyle={{ padding: 0, position: 'relative', borderRadius: '0 0 8px 8px' }}
         maskClosable={false}
     >
-        {getTargetingGags.loading && <div style={{ position: 'absolute', width: '100%', top: 0, left: 0, zIndex: 20 }}>
-            <Spin spinning={getTargetingGags.loading}>
-                <div style={{ width: '100%', height: 600, backgroundColor: 'rgba(255,255,255,0.95)' }}></div>
-            </Spin>
-        </div>}
-        <Form
-            form={form}
-            name="newAdTarget"
-            labelAlign='left'
-            labelCol={{ span: 4 }}
-            colon={false}
-            style={{ backgroundColor: '#f1f4fc', maxHeight: 600, overflow: 'hidden', overflowY: 'auto', padding: '10px 10px 10px', borderRadius: '0 0 8px 8px' }}
-            scrollToFirstError
-            onFinishFailed={({ errorFields }) => {
-                message.error(errorFields?.[0]?.errors?.[0])
-            }}
-            onFinish={handleOk}
-            initialValues={{
-                taskType: 'NOVEL',
-                geoLocationType: '0',
-                maritalStatusType: '0',
-                deviceBrandModelType: '0',
-                userOsType: '0',
-                ageType: '0',
-                wechatAdBehaviorType: ['0'],
-                age: [{}],
-                gender: '0',
-                education: ['0'],
-                networkType: ['0'],
-                devicePrice: ['0'],
-                gameConsumptionLevel: ['0'],
-                excludedConvertedAudience: {
-                    excludedDimension: '0'
-                },
-                conversionBehaviorType: 'optimization',
-                geoLocation: {
-                    locationTypes: ['LIVE_IN']
-                },
-                targetingName: (isBackVal ? '定向' : '定向模板') + '_' + localStorage.getItem('userId') + '_' + moment().format('MM_DD_HH:mm:ss')
-            }}
-        >
-            {!putInType && <Card
-                title={<strong style={{ fontSize: 18 }}>定向类型</strong>}
-                className="cardResetCss newCss"
-                bodyStyle={{ padding: '4px 6px' }}
-                style={{ marginBottom: 8 }}
-            >
-                <div className={style.newSpace}>
-                    <Form.Item name="taskType" label={<strong>投放类型</strong>} style={{ marginBottom: 0 }} rules={[{ required: true, message: '请选择定向类型' }]}>
-                        <Radio.Group onChange={(e) => {
-                            form.setFieldsValue({
-                                excludedConvertedAudience: {
-                                    excludedDimension: '0'
-                                },
-                                userOsType: '0',
-                                wechatAdBehaviorType: ['0']
-                            })
-                        }}>
-                            <Radio value="NOVEL">小说</Radio>
-                            <Radio value="GAME">游戏</Radio>
-                        </Radio.Group>
-                    </Form.Item>
-                </div>
-            </Card>}
-            <Card
-                title={<strong style={{ fontSize: 18 }}>定向选择</strong>}
-                className="cardResetCss newCss"
-                bodyStyle={{ padding: '4px 6px' }}
-                style={{ marginBottom: 8 }}
-            >
-                <div className={style.newSpace}>
-                    <Form.Item name="geoLocationType" label={<strong>地理位置</strong>} style={{ marginBottom: 0 }}>
-                        <Radio.Group>
-                            <Radio value="0">不限</Radio>
-                            <Radio value="1">按区域</Radio>
-                        </Radio.Group>
-                    </Form.Item>
-                    {geoLocationType === '1' && <div className={style.newSpace_bottom}>
-                        {/* <Title level={5} style={{ fontSize: 14 }}>微信流量(除视频号/搜一搜)暂时仅支持 “常住地”或“旅行到访”。按法务合规要求,“常住地”暂不支持国内港澳台及国外地区,“旅行到访”仅支持部分国外地区。</Title> */}
-                        <Form.Item
-                            name={['geoLocation', 'regions']}
-                            rules={[
-                                { required: true, message: '请选择区域' },
-                                { type: 'array', max: 1000, message: '地理位置最多选择1000' },
-                            ]}
-                        >
-                            <TreeSelect
-                                placeholder="请选择"
-                                showSearch={true}
-                                maxTagCount={50}
-                                treeCheckable={true}
-                                showCheckedStrategy={TreeSelect.SHOW_PARENT}
-                                treeData={regionsList}
-                                loading={getTargetingGags.loading}
-                                style={{ width: '100%' }}
-                                allowClear
-                                filterTreeNode={(inputValue: string, treeNode: any) => {
-                                    if (treeNode.title.includes(inputValue)) {
-                                        return true
-                                    } else {
-                                        return false
+        <Spin spinning={getTargetingGags.loading}>
+            <div style={{ width: '100%', position: 'relative', padding: '0 0 40px' }}>
+                <Form
+                    form={form}
+                    name="newAdTarget"
+                    labelAlign='left'
+                    labelCol={{ span: 4 }}
+                    colon={false}
+                    style={{ backgroundColor: '#f1f4fc', maxHeight: 600, overflow: 'hidden', overflowY: 'auto', padding: '10px 10px 10px', borderRadius: '0 0 8px 8px' }}
+                    scrollToFirstError
+                    onFinishFailed={({ errorFields }) => {
+                        message.error(errorFields?.[0]?.errors?.[0])
+                    }}
+                    onFinish={handleOk}
+                    initialValues={{
+                        taskType: 'NOVEL',
+                        geoLocationType: '0',
+                        maritalStatusType: '0',
+                        deviceBrandModelType: '0',
+                        userOsType: '0',
+                        ageType: '0',
+                        wechatAdBehaviorType: ['0'],
+                        age: [{}],
+                        gender: '0',
+                        education: ['0'],
+                        networkType: ['0'],
+                        devicePrice: ['0'],
+                        gameConsumptionLevel: ['0'],
+                        excludedConvertedAudience: {
+                            excludedDimension: '0'
+                        },
+                        conversionBehaviorType: 'optimization',
+                        geoLocation: {
+                            locationTypes: ['LIVE_IN']
+                        },
+                        targetingName: (isBackVal ? '定向' : '定向模板') + '_' + localStorage.getItem('userId') + '_' + moment().format('MM_DD_HH:mm:ss')
+                    }}
+                >
+                    {!putInType && <Card
+                        title={<strong style={{ fontSize: 18 }}>定向类型</strong>}
+                        className="cardResetCss newCss"
+                        bodyStyle={{ padding: '4px 6px' }}
+                        style={{ marginBottom: 8 }}
+                    >
+                        <div className={style.newSpace}>
+                            <Form.Item name="taskType" label={<strong>投放类型</strong>} style={{ marginBottom: 0 }} rules={[{ required: true, message: '请选择定向类型' }]}>
+                                <Radio.Group onChange={(e) => {
+                                    form.setFieldsValue({
+                                        excludedConvertedAudience: {
+                                            excludedDimension: '0'
+                                        },
+                                        userOsType: '0',
+                                        wechatAdBehaviorType: ['0']
+                                    })
+                                }}>
+                                    <Radio value="NOVEL">小说</Radio>
+                                    <Radio value="GAME">游戏</Radio>
+                                </Radio.Group>
+                            </Form.Item>
+                        </div>
+                    </Card>}
+                    <Card
+                        title={<strong style={{ fontSize: 18 }}>定向选择</strong>}
+                        className="cardResetCss newCss"
+                        bodyStyle={{ padding: '4px 6px' }}
+                        style={{ marginBottom: 8 }}
+                    >
+                        {isShow('geoLocation') && <div className={style.newSpace}>
+                            <Form.Item name="geoLocationType" label={<strong>地理位置</strong>} style={{ marginBottom: 0 }}>
+                                <Radio.Group>
+                                    <Radio value="0">不限</Radio>
+                                    <Radio value="1">按区域</Radio>
+                                </Radio.Group>
+                            </Form.Item>
+                            {geoLocationType === '1' && <div className={style.newSpace_bottom}>
+                                {/* <Title level={5} style={{ fontSize: 14 }}>微信流量(除视频号/搜一搜)暂时仅支持 “常住地”或“旅行到访”。按法务合规要求,“常住地”暂不支持国内港澳台及国外地区,“旅行到访”仅支持部分国外地区。</Title> */}
+                                <Form.Item
+                                    name={['geoLocation', 'regions']}
+                                    rules={[
+                                        { required: true, message: '请选择区域' },
+                                        { type: 'array', max: 1000, message: '地理位置最多选择1000' },
+                                    ]}
+                                >
+                                    <TreeSelect
+                                        placeholder="请选择"
+                                        showSearch={true}
+                                        maxTagCount={50}
+                                        treeCheckable={true}
+                                        showCheckedStrategy={TreeSelect.SHOW_PARENT}
+                                        treeData={regionsList}
+                                        loading={getTargetingGags.loading}
+                                        style={{ width: '100%' }}
+                                        allowClear
+                                        filterTreeNode={(inputValue: string, treeNode: any) => {
+                                            if (treeNode.title.includes(inputValue)) {
+                                                return true
+                                            } else {
+                                                return false
+                                            }
+                                        }}
+                                    />
+                                </Form.Item>
+                                <Form.Item
+                                    name={['geoLocation', 'locationTypes']}
+                                    rules={[{ required: true, message: '请选择地点类型' }]}
+                                >
+                                    <Checkbox.Group
+                                        disabled
+                                        options={Object.keys(LOCATION_TYPES_ENUM)?.map(key => ({ label: LOCATION_TYPES_ENUM[key as keyof typeof LOCATION_TYPES_ENUM], value: key }))}
+                                    />
+                                </Form.Item>
+                            </div>}
+                        </div>}
+
+                        {isShow('age') && <div className={style.newSpace}>
+                            <Form.Item name="ageType" label={<strong>年龄</strong>} style={{ marginBottom: 0 }}>
+                                <Radio.Group>
+                                    <Radio value="0">不限</Radio>
+                                    <Radio value="14_18">14~18岁</Radio>
+                                    <Radio value="19_24">19~24岁</Radio>
+                                    <Radio value="25_29">25~29岁</Radio>
+                                    <Radio value="30_39">30~39岁</Radio>
+                                    <Radio value="40_49">40~49岁</Radio>
+                                    <Radio value="50_66">50岁及以上</Radio>
+                                    <Radio value="1">自定义</Radio>
+                                </Radio.Group>
+                            </Form.Item>
+                            {ageType === '1' && <Form.List
+                                name='age'
+                                rules={[
+                                    {
+                                        validator: (_, ranges) => {
+                                            if (hasOverlap(ranges)) {
+                                                return Promise.reject('年龄存在区间重叠,请修改');
+                                            }
+                                            return Promise.resolve();
+                                        }
                                     }
+                                ]}
+                            >
+                                {(fields, { add, remove }) => {
+                                    return <>
+                                        {fields.map(({ key, name, ...restField }, index) => {
+                                            const ag = age?.[index]
+                                            return <div className={`${style.newSpace_bottom} flexStart`} key={key} style={{ '--g': '5px', padding: '10px 16px' } as React.CSSProperties}>
+                                                <Form.Item
+                                                    {...restField}
+                                                    name={[name, 'min']}
+                                                    style={{ marginBottom: 0 }}
+                                                    rules={[
+                                                        { required: true, message: '请选择最小年龄!' },
+                                                        ({ getFieldValue }) => ({
+                                                            validator(_, min) {
+                                                                const max = getFieldValue(['age', name, 'max']);
+                                                                if (min && max && max - min < 4) {
+                                                                    return Promise.reject('年龄跨度需≥4岁');
+                                                                }
+                                                                return Promise.resolve();
+                                                            }
+                                                        })
+                                                    ]}
+                                                >
+                                                    <Select style={{ width: 185 }} placeholder="请选择">
+                                                        {Array(66 - 13).fill('').map((_, i) => i + 14).filter(i => i !== 15 && i !== 16 && i !== 17).map(i => {
+                                                            return <Select.Option disabled={i > ag?.max} value={i} key={i}>{i === 66 ? '66 岁及以上' : i + ' 岁'}</Select.Option>
+                                                        })}
+                                                    </Select>
+                                                </Form.Item>
+                                                <span>-</span>
+                                                <Form.Item
+                                                    {...restField}
+                                                    name={[name, 'max']}
+                                                    style={{ marginBottom: 0 }}
+                                                    rules={[
+                                                        { required: true, message: '请选择最大年龄!' },
+                                                        ({ getFieldValue }) => ({
+                                                            validator(_, max) {
+                                                                const min = getFieldValue(['age', name, 'min']);
+                                                                if (min && max && max - min < 4) {
+                                                                    return Promise.reject('年龄跨度需≥4岁');
+                                                                }
+                                                                return Promise.resolve();
+                                                            }
+                                                        })
+                                                    ]}
+                                                >
+                                                    <Select style={{ width: 185 }} placeholder="请选择">
+                                                        {Array(66 - 18).fill('').map((_, i) => {
+                                                            return <Select.Option disabled={i + 19 < ag?.min + 4} value={i + 19} key={i + 19}>{i + 19 === 66 ? '66 岁及以上' : i + 19 + ' 岁'}</Select.Option>
+                                                        })}
+                                                    </Select>
+                                                </Form.Item>
+                                                {age?.length > 1 && <Button danger onClick={() => remove(name)}><DeleteOutlined /></Button>}
+                                            </div>
+                                        })}
+                                        {age?.length < 5 && <Form.Item noStyle>
+                                            <Button type="dashed" onClick={() => add()} style={{ width: '100%' }} icon={<PlusOutlined />}>
+                                                新增年龄段
+                                            </Button>
+                                        </Form.Item>}
+                                    </>
                                 }}
-                            />
-                        </Form.Item>
-                        <Form.Item
-                            name={['geoLocation', 'locationTypes']}
-                            rules={[{ required: true, message: '请选择地点类型' }]}
-                        >
-                            <Checkbox.Group
-                                disabled
-                                options={Object.keys(LOCATION_TYPES_ENUM)?.map(key => ({ label: LOCATION_TYPES_ENUM[key as keyof typeof LOCATION_TYPES_ENUM], value: key }))}
-                            />
-                        </Form.Item>
-                    </div>}
-                </div>
+                            </Form.List>}
+                        </div>}
 
-                <div className={style.newSpace}>
-                    <Form.Item name="ageType" label={<strong>年龄</strong>} style={{ marginBottom: 0 }}>
-                        <Radio.Group>
-                            <Radio value="0">不限</Radio>
-                            <Radio value="14_18">14~18岁</Radio>
-                            <Radio value="19_24">19~24岁</Radio>
-                            <Radio value="25_29">25~29岁</Radio>
-                            <Radio value="30_39">30~39岁</Radio>
-                            <Radio value="40_49">40~49岁</Radio>
-                            <Radio value="50_66">50岁及以上</Radio>
-                            <Radio value="1">自定义</Radio>
-                        </Radio.Group>
-                    </Form.Item>
-                    {ageType === '1' && <Form.List
-                        name='age'
-                        rules={[
-                            {
-                                validator: (_, ranges) => {
-                                    if (hasOverlap(ranges)) {
-                                        return Promise.reject('年龄存在区间重叠,请修改');
+                        {isShow('gender') && <div className={style.newSpace}>
+                            <Form.Item name="gender" label={<strong>性别</strong>} style={{ marginBottom: 0 }}>
+                                <Radio.Group>
+                                    <Radio value="0">不限</Radio>
+                                    {Object.keys(GENDER_ENUM).map(key => {
+                                        return <Radio value={key} key={key}>{GENDER_ENUM[key as keyof typeof GENDER_ENUM]}</Radio>
+                                    })}
+                                </Radio.Group>
+                            </Form.Item>
+                        </div>}
+
+                        {isShow('education') && <div className={style.newSpace}>
+                            <Form.Item
+                                name="education"
+                                label={<Space>
+                                    <strong>学历</strong>
+                                    <Tooltip title="用户的最高学历">
+                                        <QuestionCircleFilled />
+                                    </Tooltip>
+                                </Space>}
+                                style={{ marginBottom: 0 }}
+                                getValueFromEvent={(e: string[]) => {
+                                    if (e.length > 1 && !education.includes('0') && e.includes('0')) {
+                                        return ['0'];
                                     }
-                                    return Promise.resolve();
-                                }
-                            }
-                        ]}
-                    >
-                        {(fields, { add, remove }) => {
-                            return <>
-                                {fields.map(({ key, name, ...restField }, index) => {
-                                    const ag = age?.[index]
-                                    return <div className={`${style.newSpace_bottom} flexStart`} key={key} style={{ '--g': '5px', padding: '10px 16px' } as React.CSSProperties}>
-                                        <Form.Item
-                                            {...restField}
-                                            name={[name, 'min']}
-                                            style={{ marginBottom: 0 }}
-                                            rules={[
-                                                { required: true, message: '请选择最小年龄!' },
-                                                ({ getFieldValue }) => ({
-                                                    validator(_, min) {
-                                                        const max = getFieldValue(['age', name, 'max']);
-                                                        if (min && max && max - min < 4) {
-                                                            return Promise.reject('年龄跨度需≥4岁');
-                                                        }
-                                                        return Promise.resolve();
-                                                    }
-                                                })
-                                            ]}
-                                        >
-                                            <Select style={{ width: 185 }} placeholder="请选择">
-                                                {Array(66 - 13).fill('').map((_, i) => i + 14).filter(i => i !== 15 && i !== 16 && i !== 17).map(i => {
-                                                    return <Select.Option disabled={i > ag?.max} value={i} key={i}>{i === 66 ? '66 岁及以上' : i + ' 岁'}</Select.Option>
-                                                })}
-                                            </Select>
-                                        </Form.Item>
-                                        <span>-</span>
-                                        <Form.Item
-                                            {...restField}
-                                            name={[name, 'max']}
-                                            style={{ marginBottom: 0 }}
-                                            rules={[
-                                                { required: true, message: '请选择最大年龄!' },
-                                                ({ getFieldValue }) => ({
-                                                    validator(_, max) {
-                                                        const min = getFieldValue(['age', name, 'min']);
-                                                        if (min && max && max - min < 4) {
-                                                            return Promise.reject('年龄跨度需≥4岁');
-                                                        }
-                                                        return Promise.resolve();
-                                                    }
-                                                })
-                                            ]}
-                                        >
-                                            <Select style={{ width: 185 }} placeholder="请选择">
-                                                {Array(66 - 17).fill('').map((_, i) => {
-                                                    return <Select.Option disabled={i + 18 < ag?.min + 4} value={i + 18} key={i + 18}>{i + 18 === 66 ? '66 岁及以上' : i + 18 + ' 岁'}</Select.Option>
-                                                })}
-                                            </Select>
-                                        </Form.Item>
-                                        {age?.length > 1 && <Button danger onClick={() => remove(name)}><DeleteOutlined /></Button>}
-                                    </div>
-                                })}
-                                {age?.length < 5 && <Form.Item noStyle>
-                                    <Button type="dashed" onClick={() => add()} style={{ width: '100%' }} icon={<PlusOutlined />}>
-                                        新增年龄段
-                                    </Button>
-                                </Form.Item>}
-                            </>
-                        }}
-                    </Form.List>}
-                </div>
+                                    return e.length > 0 ? (e.length > 1 && e.includes('0') ? e.filter(item => item !== '0') : e) : ['0'];
+                                }}
+                            >
+                                <Checkbox.Group
+                                    options={[
+                                        { label: '不限', value: '0' },
+                                        ...Object.keys(EDUCATION_ENUM)?.map(key => ({ label: EDUCATION_ENUM[key as keyof typeof EDUCATION_ENUM], value: key }))
+                                    ]}
+                                />
+                            </Form.Item>
+                        </div>}
 
-                <div className={style.newSpace}>
-                    <Form.Item name="gender" label={<strong>性别</strong>} style={{ marginBottom: 0 }}>
-                        <Radio.Group>
-                            <Radio value="0">不限</Radio>
-                            {Object.keys(GENDER_ENUM).map(key => {
-                                return <Radio value={key} key={key}>{GENDER_ENUM[key as keyof typeof GENDER_ENUM]}</Radio>
-                            })}
-                        </Radio.Group>
-                    </Form.Item>
-                </div>
+                        {isShow('networkType') && <div className={style.newSpace}>
+                            <Form.Item
+                                name="networkType"
+                                label={<strong>联网方式</strong>}
+                                style={{ marginBottom: 0 }}
+                                getValueFromEvent={(e: string[]) => {
+                                    if (e.length > 1 && !networkType.includes('0') && e.includes('0')) {
+                                        return ['0'];
+                                    }
+                                    return e.length > 0 ? (e.length > 1 && e.includes('0') ? e.filter(item => item !== '0') : e) : ['0'];
+                                }}
+                            >
+                                <Checkbox.Group
+                                    options={[
+                                        { label: '不限', value: '0' },
+                                        ...Object.keys(NETWORK_ENUM)?.map(key => ({ label: NETWORK_ENUM[key as keyof typeof NETWORK_ENUM], value: key }))
+                                    ]}
+                                />
+                            </Form.Item>
+                        </div>}
 
-                <div className={style.newSpace}>
-                    <Form.Item
-                        name="education"
-                        label={<Space>
-                            <strong>学历</strong>
-                            <Tooltip title="用户的最高学历">
-                                <QuestionCircleFilled />
-                            </Tooltip>
-                        </Space>}
-                        style={{ marginBottom: 0 }}
-                        getValueFromEvent={(e: string[]) => {
-                            if (e.length > 1 && !education.includes('0') && e.includes('0')) {
-                                return ['0'];
-                            }
-                            return e.length > 0 ? (e.length > 1 && e.includes('0') ? e.filter(item => item !== '0') : e) : ['0'];
-                        }}
-                    >
-                        <Checkbox.Group
-                            options={[
-                                { label: '不限', value: '0' },
-                                ...Object.keys(EDUCATION_ENUM)?.map(key => ({ label: EDUCATION_ENUM[key as keyof typeof EDUCATION_ENUM], value: key }))
-                            ]}
-                        />
-                    </Form.Item>
-                </div>
+                        {(isShow('excludedCustomAudience')) && <div className={style.newSpace}>
+                            <Form.Item
+                                label={<Space>
+                                    <strong>自定义人群</strong>
+                                    <Tooltip title={<span>
+                                        自定义人群是指客户通过腾讯广告知数(原DMP)创建和管理自己定义类人群,包括您自行上传的号码包人群等。仅当出价方式选择CPC、 CPM或oCPM(且优化目标为“点击”)时,你可以“二方人群”进行投放。
+                                        <a href="https://e.qq.com/ads/helpcenter/detail/?cid=3161&pid=8995" target="__blank">了解更多</a>
+                                    </span>}>
+                                        <QuestionCircleFilled />
+                                    </Tooltip>
+                                </Space>}
+                                style={{ marginBottom: 0 }}
+                            >
+                                <Space>
+                                    <Checkbox.Group
+                                        defaultValue={['0']}
+                                        options={[
+                                            { label: '不限', value: '0' }
+                                        ]}
+                                    />
+                                    <span style={{ color: '#FAAD14' }}>自定义人群必须关联指定账户,当前关联账户为不限</span>
+                                </Space>
+                            </Form.Item>
+                        </div>}
 
-                <div className={style.newSpace}>
-                    <Form.Item
-                        name="networkType"
-                        label={<strong>联网方式</strong>}
-                        style={{ marginBottom: 0 }}
-                        getValueFromEvent={(e: string[]) => {
-                            if (e.length > 1 && !networkType.includes('0') && e.includes('0')) {
-                                return ['0'];
-                            }
-                            return e.length > 0 ? (e.length > 1 && e.includes('0') ? e.filter(item => item !== '0') : e) : ['0'];
-                        }}
-                    >
-                        <Checkbox.Group
-                            options={[
-                                { label: '不限', value: '0' },
-                                ...Object.keys(NETWORK_ENUM)?.map(key => ({ label: NETWORK_ENUM[key as keyof typeof NETWORK_ENUM], value: key }))
-                            ]}
-                        />
-                    </Form.Item>
-                </div>
+                        <div className={style.newSpace}>
+                            {isShow('maritalStatus') && <Form.Item name="maritalStatusType" label={<strong>婚恋育儿状态</strong>} style={{ marginBottom: maritalStatusType === '1' ? 4 : 12 }}>
+                                <Radio.Group>
+                                    <Radio value="0">不限</Radio>
+                                    <Radio value="1">自定义</Radio>
+                                </Radio.Group>
+                            </Form.Item>}
+                            {maritalStatusType === '1' && <div className={`${style.newSpace_bottom}`} style={{ marginBottom: 6 }}>
+                                <Form.Item name={'maritalStatus'} rules={[{ required: true, message: '请选择婚恋育儿状态' }]}>
+                                    <Checkbox.Group options={Object.keys(MARITAL_STATUS_ENUM).map(key => ({ label: MARITAL_STATUS_ENUM[key as keyof typeof MARITAL_STATUS_ENUM], value: key }))} />
+                                </Form.Item>
+                            </div>}
+                            {isShow('excludedConvertedAudience') && <>
+                                <Form.Item
+                                    name={['excludedConvertedAudience', 'excludedDimension']}
+                                    label={<Space>
+                                        <strong>排除已转化用户</strong>
+                                        <Tooltip title={<>
+                                            <Paragraph>
+                                                设置排除已转化定向,广告不会曝光给所选范围内已转化的用户;
+                                                系统将自动以当前广告选择的优化目标作为此定向的转化行为(不支持“点击”、“次留率”优化目标);
+                                                该定向仅可选择oCPC、oCPM、oCPA出价方式,若勾选自定义转化行为则不限制出价方式 。
+                                            </Paragraph>
+                                            <a href="https://e.qq.com/ads/helpcenter/detail/?cid=3531&pid=2612" target="__blank">了解更多</a>
+                                        </>}>
+                                            <QuestionCircleFilled />
+                                        </Tooltip>
+                                    </Space>}
+                                    style={{ marginBottom: excludedDimension === '0' ? 12 : 4 }}
+                                >
+                                    <Radio.Group>
+                                        <Radio value="0">不限</Radio>
+                                        {Object.keys(EXCLUDED_DIMENSION_ENUM).filter(key => taskType === 'GAME' ? ['EXCLUDED_DIMENSION_UID', 'EXCLUDED_DIMENSION_BUSINESS_MANAGER', 'EXCLUDED_DIMENSION_COMPANY_ACCOUNT', 'EXCLUDED_DIMENSION_APP'].includes(key) : true).map(key => {
+                                            return <Radio value={key} key={key}>{EXCLUDED_DIMENSION_ENUM[key as keyof typeof EXCLUDED_DIMENSION_ENUM]}</Radio>
+                                        })}
+                                    </Radio.Group>
+                                </Form.Item>
+                                {excludedDimension !== '0' && <div className={`${style.newSpace_bottom}`} style={{ marginBottom: 6 }}>
+                                    <Title level={5} style={{ fontSize: 14 }}>系统自动依照当前广告选择的优化目标作为此定向的转化行为</Title>
+                                    <Form.Item label="转化行为" name={'conversionBehaviorType'} rules={[{ required: true, message: '请选择自定义转化行为' }]} style={{ marginBottom: 10 }}>
+                                        <Radio.Group>
+                                            <Radio value="optimization">优化目标</Radio>
+                                            <Radio value="customize">自定义</Radio>
+                                        </Radio.Group>
+                                    </Form.Item>
+                                    {conversionBehaviorType === 'customize' && <Form.Item name={['excludedConvertedAudience', 'conversionBehaviorList']} rules={[{ required: true, message: '请选择自定义转化行为' }]} style={{ marginBottom: 10 }}>
+                                        <Select
+                                            showSearch
+                                            filterOption={(input, option) =>
+                                                (option!.children as unknown as string).toLowerCase().includes(input.toLowerCase())
+                                            }
+                                            allowClear
+                                            placeholder='请选择自定义转化行为'
+                                            mode="multiple"
+                                            style={{ width: 480 }}
+                                        >
+                                            {Object.keys(OPTIMIZATIONGOAL_ENUM).filter(key => key !== 'OPTIMIZATIONGOAL_NONE').map(key => {
+                                                return <Select.Option value={key} key={key} disabled={conversionBehaviorList?.length >= 2 && !conversionBehaviorList.includes(key)}>{OPTIMIZATIONGOAL_ENUM[key as keyof typeof OPTIMIZATIONGOAL_ENUM]}</Select.Option>
+                                            })}
+                                        </Select>
+                                    </Form.Item>}
+                                    <Form.Item label="转化时间区间" name={['excludedConvertedAudience', 'excludedDay']}>
+                                        <Radio.Group>
+                                            {Object.keys(EXCLUDED_DAY_ENUM).map(key => <Radio value={key} key={key}>{EXCLUDED_DAY_ENUM[key as keyof typeof EXCLUDED_DAY_ENUM]}</Radio>)}
+                                        </Radio.Group>
+                                    </Form.Item>
+                                </div>}
+                            </>}
 
-                <div className={style.newSpace}>
-                    <Form.Item
-                        label={<Space>
-                            <strong>自定义人群</strong>
-                            <Tooltip title={<span>
-                                自定义人群是指客户通过腾讯广告知数(原DMP)创建和管理自己定义类人群,包括您自行上传的号码包人群等。仅当出价方式选择CPC、 CPM或oCPM(且优化目标为“点击”)时,你可以“二方人群”进行投放。
-                                <a href="https://e.qq.com/ads/helpcenter/detail/?cid=3161&pid=8995" target="__blank">了解更多</a>
-                            </span>}>
-                                <QuestionCircleFilled />
-                            </Tooltip>
-                        </Space>}
-                        style={{ marginBottom: 0 }}
-                    >
-                        <Space>
-                            <Checkbox.Group
-                                defaultValue={['0']}
-                                options={[
-                                    { label: '不限', value: '0' }
-                                ]}
-                            />
-                            <span style={{ color: '#FAAD14' }}>自定义人群必须关联指定账户,当前关联账户为不限</span>
-                        </Space>
-                    </Form.Item>
-                </div>
+                            {isShow('deviceBrandModel') && <Form.Item name="deviceBrandModelType" label={<strong>设备品牌型号</strong>} style={{ marginBottom: deviceBrandModelType === '0' ? 0 : 4 }}>
+                                <Radio.Group>
+                                    <Radio value="0">不限</Radio>
+                                    <Radio value="1">自定义</Radio>
+                                </Radio.Group>
+                            </Form.Item>}
+                            {deviceBrandModelType === '1' && <div className={`${style.newSpace_bottom}`} style={{ marginBottom: 6 }}>
+                                <Form.Item
+                                    name={'deviceBrandModelList'}
+                                    rules={[
+                                        { required: true, message: '请选择设备品牌' },
+                                        { type: 'array', max: 400, message: '设备品牌最多选择400个设备型号' }
+                                    ]}
+                                    style={{ marginBottom: 10 }}
+                                >
+                                    <TreeSelect
+                                        placeholder="请选择"
+                                        showSearch={true}
+                                        maxTagCount={20}
+                                        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='isExcludedDeviceBrandModel' valuePropName="checked">
+                                    <Checkbox>排除所选设备的用户</Checkbox>
+                                </Form.Item>
+                            </div>}
+                        </div>
 
-                <div className={style.newSpace}>
-                    <Form.Item name="maritalStatusType" label={<strong>婚恋育儿状态</strong>} style={{ marginBottom: maritalStatusType === '1' ? 4 : 12 }}>
-                        <Radio.Group>
-                            <Radio value="0">不限</Radio>
-                            <Radio value="1">自定义</Radio>
-                        </Radio.Group>
-                    </Form.Item>
-                    {maritalStatusType === '1' && <div className={`${style.newSpace_bottom}`} style={{ marginBottom: 6 }}>
-                        <Form.Item name={'maritalStatus'} rules={[{ required: true, message: '请选择婚恋育儿状态' }]}>
-                            <Checkbox.Group options={Object.keys(MARITAL_STATUS_ENUM).map(key => ({ label: MARITAL_STATUS_ENUM[key as keyof typeof MARITAL_STATUS_ENUM], value: key }))} />
-                        </Form.Item>
-                    </div>}
-                    <Form.Item
-                        name={['excludedConvertedAudience', 'excludedDimension']}
-                        label={<Space>
-                            <strong>排除已转化用户</strong>
-                            <Tooltip title={<>
-                                <Paragraph>
-                                    设置排除已转化定向,广告不会曝光给所选范围内已转化的用户;
-                                    系统将自动以当前广告选择的优化目标作为此定向的转化行为(不支持“点击”、“次留率”优化目标);
-                                    该定向仅可选择oCPC、oCPM、oCPA出价方式,若勾选自定义转化行为则不限制出价方式 。
-                                </Paragraph>
-                                <a href="https://e.qq.com/ads/helpcenter/detail/?cid=3531&pid=2612" target="__blank">了解更多</a>
-                            </>}>
-                                <QuestionCircleFilled />
-                            </Tooltip>
-                        </Space>}
-                        style={{ marginBottom: excludedDimension === '0' ? 12 : 4 }}
-                    >
-                        <Radio.Group>
-                            <Radio value="0">不限</Radio>
-                            {Object.keys(EXCLUDED_DIMENSION_ENUM).filter(key => taskType === 'GAME' ? ['EXCLUDED_DIMENSION_UID', 'EXCLUDED_DIMENSION_BUSINESS_MANAGER', 'EXCLUDED_DIMENSION_COMPANY_ACCOUNT', 'EXCLUDED_DIMENSION_APP'].includes(key) : true).map(key => {
-                                return <Radio value={key} key={key}>{EXCLUDED_DIMENSION_ENUM[key as keyof typeof EXCLUDED_DIMENSION_ENUM]}</Radio>
-                            })}
-                        </Radio.Group>
-                    </Form.Item>
-                    {excludedDimension !== '0' && <div className={`${style.newSpace_bottom}`} style={{ marginBottom: 6 }}>
-                        <Title level={5} style={{ fontSize: 14 }}>系统自动依照当前广告选择的优化目标作为此定向的转化行为</Title>
-                        <Form.Item label="转化行为" name={'conversionBehaviorType'} rules={[{ required: true, message: '请选择自定义转化行为' }]} style={{ marginBottom: 10 }}>
-                            <Radio.Group>
-                                <Radio value="optimization">优化目标</Radio>
-                                <Radio value="customize">自定义</Radio>
-                            </Radio.Group>
-                        </Form.Item>
-                        {conversionBehaviorType === 'customize' && <Form.Item name={['excludedConvertedAudience', 'conversionBehaviorList']} rules={[{ required: true, message: '请选择自定义转化行为' }]} style={{ marginBottom: 10 }}>
-                            <Select
-                                showSearch
-                                filterOption={(input, option) =>
-                                    (option!.children as unknown as string).toLowerCase().includes(input.toLowerCase())
-                                }
-                                allowClear
-                                placeholder='请选择自定义转化行为'
-                                mode="multiple"
-                                style={{ width: 480 }}
+                        {taskType === 'GAME' && <div className={style.newSpace}>
+                            <Form.Item
+                                name="gameConsumptionLevel"
+                                label={<strong>游戏消费能力</strong>}
+                                style={{ marginBottom: 0 }}
+                                getValueFromEvent={(e: string[]) => {
+                                    if (e.length > 1 && !gameConsumptionLevel.includes('0') && e.includes('0')) {
+                                        return ['0'];
+                                    }
+                                    return e.length > 0 ? (e.length > 1 && e.includes('0') ? e.filter(item => item !== '0') : e) : ['0'];
+                                }}
                             >
-                                {Object.keys(OPTIMIZATIONGOAL_ENUM).filter(key => key !== 'OPTIMIZATIONGOAL_NONE').map(key => {
-                                    return <Select.Option value={key} key={key} disabled={conversionBehaviorList?.length >= 2 && !conversionBehaviorList.includes(key)}>{OPTIMIZATIONGOAL_ENUM[key as keyof typeof OPTIMIZATIONGOAL_ENUM]}</Select.Option>
-                                })}
-                            </Select>
-                        </Form.Item>}
-                        <Form.Item label="转化时间区间" name={['excludedConvertedAudience', 'excludedDay']}>
-                            <Radio.Group>
-                                {Object.keys(EXCLUDED_DAY_ENUM).map(key => <Radio value={key} key={key}>{EXCLUDED_DAY_ENUM[key as keyof typeof EXCLUDED_DAY_ENUM]}</Radio>)}
-                            </Radio.Group>
-                        </Form.Item>
-                    </div>}
+                                <Checkbox.Group
+                                    options={[
+                                        { label: '不限', value: '0' },
+                                        ...Object.keys(GAME_CONSUMPTION_LEVEL_ENUM)?.map(key => ({ label: GAME_CONSUMPTION_LEVEL_ENUM[key as keyof typeof GAME_CONSUMPTION_LEVEL_ENUM], value: key }))
+                                    ]}
+                                />
+                            </Form.Item>
+                        </div>}
 
-                    <Form.Item name="deviceBrandModelType" label={<strong>设备品牌型号</strong>} style={{ marginBottom: deviceBrandModelType === '0' ? 0 : 4 }}>
-                        <Radio.Group>
-                            <Radio value="0">不限</Radio>
-                            <Radio value="1">自定义</Radio>
-                        </Radio.Group>
-                    </Form.Item>
-                    {deviceBrandModelType === '1' && <div className={`${style.newSpace_bottom}`} style={{ marginBottom: 6 }}>
-                        <Form.Item
-                            name={'deviceBrandModelList'}
-                            rules={[
-                                { required: true, message: '请选择设备品牌' },
-                                { type: 'array', max: 400, message: '设备品牌最多选择400个设备型号' }
-                            ]}
-                            style={{ marginBottom: 10 }}
-                        >
-                            <TreeSelect
-                                placeholder="请选择"
-                                showSearch={true}
-                                maxTagCount={20}
-                                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
+
+                        {isShow('userOs') && <div className={style.newSpace}>
+                            <Form.Item name="userOsType" label={<strong>操作系统版本</strong>} style={{ marginBottom: 0 }}>
+                                <Radio.Group>
+                                    <Radio value="0">不限</Radio>
+                                    <Radio value="1">自定义</Radio>
+                                </Radio.Group>
+                            </Form.Item>
+                            {userOsType === '1' && <div className={`${style.newSpace_bottom}`}>
+                                <Form.Item
+                                    name={'os'}
+                                    style={{ marginBottom: 10 }}
+                                    rules={[
+                                        { required: true, message: '请选择操作系统版本' },
+                                        { type: 'array', max: 100, message: '操作系统版本最多选择100个设备型号' }
+                                    ]}
+                                >
+                                    <TreeSelect
+                                        placeholder="请选择"
+                                        showSearch={true}
+                                        maxTagCount={10}
+                                        treeCheckable={true}
+                                        showCheckedStrategy={TreeSelect.SHOW_PARENT}
+                                        treeData={osList}
+                                        style={{ width: '100%' }}
+                                        allowClear
+                                        filterTreeNode={(inputValue: string, treeNode: any) => {
+                                            if (treeNode.title.includes(inputValue)) {
+                                                return true
+                                            } else {
+                                                return false
+                                            }
+                                        }}
+                                    />
+                                </Form.Item>
+                                <Form.Item name='isExcludedOs' valuePropName="checked">
+                                    <Checkbox>排除所选操作系统版本的用户</Checkbox>
+                                </Form.Item>
+                            </div>}
+                        </div>}
+
+                        {isShow('devicePrice') && <div className={style.newSpace}>
+                            <Form.Item
+                                name="devicePrice"
+                                label={<strong>设备价格</strong>}
+                                style={{ marginBottom: 0 }}
+                                getValueFromEvent={(e: string[]) => {
+                                    if (e.length > 1 && !devicePrice.includes('0') && e.includes('0')) {
+                                        return ['0'];
                                     }
+                                    return e.length > 0 ? (e.length > 1 && e.includes('0') ? e.filter(item => item !== '0') : e) : ['0'];
                                 }}
-                            />
-                        </Form.Item>
-                        <Form.Item name='isExcludedDeviceBrandModel' valuePropName="checked">
-                            <Checkbox>排除所选设备的用户</Checkbox>
-                        </Form.Item>
-                    </div>}
-                </div>
+                            >
+                                <Checkbox.Group
+                                    options={[
+                                        { label: '不限', value: '0' },
+                                        ...Object.keys(DEVICE_PRICE_ENUM)?.map(key => ({ label: DEVICE_PRICE_ENUM[key as keyof typeof DEVICE_PRICE_ENUM], value: key }))
+                                    ]}
+                                />
+                            </Form.Item>
+                        </div>}
 
-                {taskType === 'GAME' && <div className={style.newSpace}>
-                    <Form.Item
-                        name="gameConsumptionLevel"
-                        label={<strong>游戏消费能力</strong>}
-                        style={{ marginBottom: 0 }}
-                        getValueFromEvent={(e: string[]) => {
-                            if (e.length > 1 && !gameConsumptionLevel.includes('0') && e.includes('0')) {
-                                return ['0'];
-                            }
-                            return e.length > 0 ? (e.length > 1 && e.includes('0') ? e.filter(item => item !== '0') : e) : ['0'];
-                        }}
+                        {isShow('wechatAdBehavior') && <div className={style.newSpace}>
+                            <Form.Item
+                                name="wechatAdBehaviorType"
+                                label={<strong>微信再营销</strong>}
+                                style={{ marginBottom: 0 }}
+                                getValueFromEvent={(e: string[]) => {
+                                    if (e.length > 1 && !wechatAdBehaviorType.includes('0') && e.includes('0')) {
+                                        return ['0'];
+                                    }
+                                    return e.length > 0 ? (e.length > 1 && e.includes('0') ? e.filter(item => item !== '0') : e) : ['0'];
+                                }}
+                            >
+                                <Checkbox.Group
+                                    options={[
+                                        { label: '不限', value: '0' },
+                                        { label: '再营销', value: 'actions' },
+                                        { label: '排除营销', value: 'excludedActions' }
+                                    ]}
+                                />
+                            </Form.Item>
+                            {(wechatAdBehaviorType && !wechatAdBehaviorType?.includes('0')) && <div className={`${style.newSpace_bottom}`}>
+                                {wechatAdBehaviorType.includes('actions') && <>
+                                    <Title level={5} style={{ fontSize: 14 }}>再营销</Title>
+                                    <Form.Item style={{ marginBottom: 10 }} name={['wechatAdBehavior', 'actions']}>
+                                        {taskType === 'GAME' ?
+                                            <Checkbox.Group options={Object.keys(WECHAT_AD_NEHAVIOR_GAME_ENUM).filter(item => !['WE_COM_CORP_ID_ADDED', 'WECHAT_WORK_CONTACTS_ADDED'].includes(item)).map(key => ({ label: WECHAT_AD_NEHAVIOR_GAME_ENUM[key as keyof typeof WECHAT_AD_NEHAVIOR_GAME_ENUM], value: key, disabled: excludedActions?.some((k: string) => k === key) }))} />
+                                            :
+                                            <Checkbox.Group options={Object.keys(WECHAT_AD_NEHAVIOR_ENUM).filter(item => !['WE_COM_CORP_ID_ADDED', 'WECHAT_WORK_CONTACTS_ADDED'].includes(item)).map(key => ({ label: WECHAT_AD_NEHAVIOR_ENUM[key as keyof typeof WECHAT_AD_NEHAVIOR_ENUM], value: key, disabled: excludedActions?.some((k: string) => k === key) }))} />
+                                        }
+                                    </Form.Item>
+                                </>}
+                                {wechatAdBehaviorType.includes('excludedActions') && <>
+                                    <Title level={5} style={{ fontSize: 14 }}>排除营销</Title>
+                                    <Form.Item name={['wechatAdBehavior', 'excludedActions']}>
+                                        {taskType === 'GAME' ?
+                                            <Checkbox.Group options={Object.keys(WECHAT_AD_NEHAVIOR_GAME_ENUM).map(key => ({ label: WECHAT_AD_NEHAVIOR_GAME_ENUM[key as keyof typeof WECHAT_AD_NEHAVIOR_GAME_ENUM], value: key, disabled: actions?.some((k: string) => k === key) }))} />
+                                            :
+                                            <Checkbox.Group options={Object.keys(WECHAT_AD_NEHAVIOR_ENUM).map(key => ({ label: WECHAT_AD_NEHAVIOR_ENUM[key as keyof typeof WECHAT_AD_NEHAVIOR_ENUM], value: key, disabled: actions?.some((k: string) => k === key) }))} />
+                                        }
+                                    </Form.Item>
+                                </>}
+                                {excludedActions?.includes('WE_COM_CORP_ID_ADDED') && <>
+                                    <Form.Item label={<strong>企业微信</strong>} name={['wechatAdBehavior', 'corpId']} rules={[{ required: true, message: '请选择微信小程序' }]}>
+                                        <SelectCorpWechatCorpId />
+                                    </Form.Item>
+                                </>}
+                            </div>}
+                        </div>}
+                    </Card>
+                    <Card
+                        title={<strong style={{ fontSize: 18 }}>定向设置</strong>}
+                        className="cardResetCss"
                     >
-                        <Checkbox.Group
-                            options={[
-                                { label: '不限', value: '0' },
-                                ...Object.keys(GAME_CONSUMPTION_LEVEL_ENUM)?.map(key => ({ label: GAME_CONSUMPTION_LEVEL_ENUM[key as keyof typeof GAME_CONSUMPTION_LEVEL_ENUM], value: key }))
-                            ]}
-                        />
-                    </Form.Item>
-                </div>}
-
-
-                <div className={style.newSpace}>
-                    <Form.Item name="userOsType" label={<strong>操作系统版本</strong>} style={{ marginBottom: 0 }}>
-                        <Radio.Group>
-                            <Radio value="0">不限</Radio>
-                            <Radio value="1">自定义</Radio>
-                        </Radio.Group>
-                    </Form.Item>
-                    {userOsType === '1' && <div className={`${style.newSpace_bottom}`}>
                         <Form.Item
-                            name={'os'}
-                            style={{ marginBottom: 10 }}
+                            label={<strong>定向模板名称</strong>}
+                            name='targetingName'
+                            // tooltip="下标、日期时分秒、广告账户创建时默认自带"
                             rules={[
-                                { required: true, message: '请选择操作系统版本' },
-                                { type: 'array', max: 100, message: '操作系统版本最多选择100个设备型号' }
+                                { required: true, message: '请输入定向模板名称!' },
+                                {
+                                    required: true, message: '定向模板名称不能包含特殊字符:< > & ‘ ” / 以及TAB、换行、回车键,请修改', validator(_, value) {
+                                        let reg = /[&‘’“”/\n\t\f]/ig
+                                        if (value && reg.test(value)) {
+                                            return Promise.reject()
+                                        }
+                                        return Promise.resolve()
+                                    }
+                                },
+                                {
+                                    required: true, message: '请确保定向模板名称长度不超过30个字(1个汉字等于2个字符)', validator(_, value) {
+                                        if (value && txtLength(value) > 30) {
+                                            return Promise.reject()
+                                        }
+                                        return Promise.resolve()
+                                    }
+                                }
                             ]}
                         >
-                            <TreeSelect
-                                placeholder="请选择"
-                                showSearch={true}
-                                maxTagCount={10}
-                                treeCheckable={true}
-                                showCheckedStrategy={TreeSelect.SHOW_PARENT}
-                                treeData={osList}
-                                style={{ width: '100%' }}
-                                allowClear
-                                filterTreeNode={(inputValue: string, treeNode: any) => {
-                                    if (treeNode.title.includes(inputValue)) {
-                                        return true
-                                    } else {
-                                        return false
-                                    }
-                                }}
-                            />
+                            <InputName placeholder='定向模板名称' style={{ width: 480 }} length={30} />
                         </Form.Item>
-                        <Form.Item name='isExcludedOs' valuePropName="checked">
-                            <Checkbox>排除所选操作系统版本的用户</Checkbox>
-                        </Form.Item>
-                    </div>}
-                </div>
-
-                <div className={style.newSpace}>
-                    <Form.Item
-                        name="devicePrice"
-                        label={<strong>设备价格</strong>}
-                        style={{ marginBottom: 0 }}
-                        getValueFromEvent={(e: string[]) => {
-                            if (e.length > 1 && !devicePrice.includes('0') && e.includes('0')) {
-                                return ['0'];
-                            }
-                            return e.length > 0 ? (e.length > 1 && e.includes('0') ? e.filter(item => item !== '0') : e) : ['0'];
-                        }}
-                    >
-                        <Checkbox.Group
-                            options={[
-                                { label: '不限', value: '0' },
-                                ...Object.keys(DEVICE_PRICE_ENUM)?.map(key => ({ label: DEVICE_PRICE_ENUM[key as keyof typeof DEVICE_PRICE_ENUM], value: key }))
-                            ]}
-                        />
-                    </Form.Item>
-                </div>
-
-                <div className={style.newSpace}>
-                    <Form.Item
-                        name="wechatAdBehaviorType"
-                        label={<strong>微信再营销</strong>}
-                        style={{ marginBottom: 0 }}
-                        getValueFromEvent={(e: string[]) => {
-                            if (e.length > 1 && !wechatAdBehaviorType.includes('0') && e.includes('0')) {
-                                return ['0'];
-                            }
-                            return e.length > 0 ? (e.length > 1 && e.includes('0') ? e.filter(item => item !== '0') : e) : ['0'];
-                        }}
-                    >
-                        <Checkbox.Group
-                            options={[
-                                { label: '不限', value: '0' },
-                                { label: '再营销', value: 'actions' },
-                                { label: '排除营销', value: 'excludedActions' }
-                            ]}
-                        />
-                    </Form.Item>
-                    {(wechatAdBehaviorType && !wechatAdBehaviorType?.includes('0')) && <div className={`${style.newSpace_bottom}`}>
-                        {wechatAdBehaviorType.includes('actions') && <>
-                            <Title level={5} style={{ fontSize: 14 }}>再营销</Title>
-                            <Form.Item style={{ marginBottom: 10 }} name={['wechatAdBehavior', 'actions']}>
-                                {taskType === 'GAME' ?
-                                    <Checkbox.Group options={Object.keys(WECHAT_AD_NEHAVIOR_GAME_ENUM).filter(item => !['WE_COM_CORP_ID_ADDED', 'WECHAT_WORK_CONTACTS_ADDED'].includes(item)).map(key => ({ label: WECHAT_AD_NEHAVIOR_GAME_ENUM[key as keyof typeof WECHAT_AD_NEHAVIOR_GAME_ENUM], value: key, disabled: excludedActions?.some((k: string) => k === key) }))} />
-                                    :
-                                    <Checkbox.Group options={Object.keys(WECHAT_AD_NEHAVIOR_ENUM).filter(item => !['WE_COM_CORP_ID_ADDED', 'WECHAT_WORK_CONTACTS_ADDED'].includes(item)).map(key => ({ label: WECHAT_AD_NEHAVIOR_ENUM[key as keyof typeof WECHAT_AD_NEHAVIOR_ENUM], value: key, disabled: excludedActions?.some((k: string) => k === key) }))} />
-                                }
-                            </Form.Item>
-                        </>}
-                        {wechatAdBehaviorType.includes('excludedActions') && <>
-                            <Title level={5} style={{ fontSize: 14 }}>排除营销</Title>
-                            <Form.Item name={['wechatAdBehavior', 'excludedActions']}>
-                                {taskType === 'GAME' ?
-                                    <Checkbox.Group options={Object.keys(WECHAT_AD_NEHAVIOR_GAME_ENUM).map(key => ({ label: WECHAT_AD_NEHAVIOR_GAME_ENUM[key as keyof typeof WECHAT_AD_NEHAVIOR_GAME_ENUM], value: key, disabled: actions?.some((k: string) => k === key) }))} />
-                                    :
-                                    <Checkbox.Group options={Object.keys(WECHAT_AD_NEHAVIOR_ENUM).map(key => ({ label: WECHAT_AD_NEHAVIOR_ENUM[key as keyof typeof WECHAT_AD_NEHAVIOR_ENUM], value: key, disabled: actions?.some((k: string) => k === key) }))} />
-                                }
+                        {!isBackVal && <>
+                            <Form.Item
+                                label={<strong>定向模板描述</strong>}
+                                name='description'
+                            >
+                                <Input.TextArea style={{ width: 480 }} placeholder="定向模板描述" />
                             </Form.Item>
-                        </>}
-                        {excludedActions?.includes('WE_COM_CORP_ID_ADDED') && <>
-                            <Form.Item label={<strong>企业微信</strong>} name={['wechatAdBehavior', 'corpId']} rules={[{ required: true, message: '请选择微信小程序' }]}>
-                                <SelectCorpWechatCorpId />
+                            <Form.Item
+                                label={<strong>关联账户</strong>}
+                                name='accountId'
+                            >
+                                <Select
+                                    style={{ width: 480 }}
+                                    showSearch
+                                    filterOption={(input, option) =>
+                                        (option!.children as unknown as string)?.toLowerCase()?.includes(input?.toLowerCase())
+                                    }
+                                    allowClear
+                                    placeholder='请选择媒体账户'
+                                >
+                                    {getAllUserAccount?.data?.data?.map((item: any) => <Select.Option value={item.accountId} key={item.id}>{item.remark ? item.accountId + '_' + item.remark : item.accountId}</Select.Option>)}
+                                </Select>
                             </Form.Item>
                         </>}
-                    </div>}
-                </div>
-            </Card>
-            <Card
-                title={<strong style={{ fontSize: 18 }}>定向设置</strong>}
-                className="cardResetCss"
-            >
-                <Form.Item
-                    label={<strong>定向模板名称</strong>}
-                    name='targetingName'
-                    // tooltip="下标、日期时分秒、广告账户创建时默认自带"
-                    rules={[
-                        { required: true, message: '请输入定向模板名称!' },
-                        {
-                            required: true, message: '定向模板名称不能包含特殊字符:< > & ‘ ” / 以及TAB、换行、回车键,请修改', validator(_, value) {
-                                let reg = /[&‘’“”/\n\t\f]/ig
-                                if (value && reg.test(value)) {
-                                    return Promise.reject()
-                                }
-                                return Promise.resolve()
-                            }
-                        },
-                        {
-                            required: true, message: '请确保定向模板名称长度不超过30个字(1个汉字等于2个字符)', validator(_, value) {
-                                if (value && txtLength(value) > 30) {
-                                    return Promise.reject()
-                                }
-                                return Promise.resolve()
-                            }
-                        }
-                    ]}
-                >
-                    <InputName placeholder='定向模板名称' style={{ width: 480 }} length={30} />
-                </Form.Item>
-                {!isBackVal && <>
-                    <Form.Item
-                        label={<strong>定向模板描述</strong>}
-                        name='description'
-                    >
-                        <Input.TextArea style={{ width: 480 }} placeholder="定向模板描述" />
-                    </Form.Item>
-                    <Form.Item
-                        label={<strong>关联账户</strong>}
-                        name='accountId'
-                    >
-                        <Select
-                            style={{ width: 480 }}
-                            showSearch
-                            filterOption={(input, option) =>
-                                (option!.children as unknown as string)?.toLowerCase()?.includes(input?.toLowerCase())
-                            }
-                            allowClear
-                            placeholder='请选择媒体账户'
-                        >
-                            {getAllUserAccount?.data?.data?.map((item: any) => <Select.Option value={item.accountId} key={item.id}>{item.remark ? item.accountId + '_' + item.remark : item.accountId}</Select.Option>)}
-                        </Select>
+                    </Card>
+                    <Form.Item className="submit_pull">
+                        <Space>
+                            {isBackVal && !(value && Object.keys(value).length > 0) && <Checkbox checked={isAdd} onChange={(e) => setIsAdd(e.target.checked)}>是否保存到定向模板</Checkbox>}
+                            <Button onClick={onClose}>取消</Button>
+                            <Button type="primary" htmlType="submit" className="modalResetCss" loading={checkTargeting.loading || updateTargeting.loading || addTargeting.loading}>
+                                确定
+                            </Button>
+                        </Space>
                     </Form.Item>
-                </>}
-            </Card>
-            <Form.Item className="submit_pull">
-                <Space>
-                    {isBackVal && !(value && Object.keys(value).length > 0) && <Checkbox checked={isAdd} onChange={(e) => setIsAdd(e.target.checked)}>是否保存到定向模板</Checkbox>}
-                    <Button onClick={onClose}>取消</Button>
-                    <Button type="primary" htmlType="submit" className="modalResetCss" loading={checkTargeting.loading || updateTargeting.loading || addTargeting.loading}>
-                        确定
-                    </Button>
-                </Space>
-            </Form.Item>
-        </Form>
+                </Form>
+            </div>
+        </Spin>
     </Modal>
 }
 

+ 23 - 1
src/pages/launchSystemV3/tencentAdPutIn/create/Target/index.tsx

@@ -8,6 +8,9 @@ import { useModel } from "umi"
 import DataItem from "./dataItem"
 import AddTarget from "./addTarget"
 import GenerateTarget from "./generateTarget"
+import { sdpRules } from "../../rules"
+import { SMART_DELIVERY_PLATFORM_ENUM } from "../../const"
+import { toCamelCase } from "@/utils/utils"
 const { Title } = Typography;
 
 /**
@@ -18,7 +21,7 @@ const Target: React.FC = () => {
 
     /***************************************/
     const { geoLocationList, modelList } = useModel('useLaunchV3.useTargeting')
-    const { addelivery, setAddelivery, clearData, putInType, setIsDqSubmit } = useContext(DispatchAddelivery)!;
+    const { addelivery, setAddelivery, clearData, putInType, setIsDqSubmit, targetRules, setTargetRules } = useContext(DispatchAddelivery)!;
     const { targeting, adgroups } = addelivery
     const { smartTargetingMode } = adgroups
     const [addVisible, setAddVisible] = useState<boolean>(false)
@@ -34,6 +37,23 @@ const Target: React.FC = () => {
         setStm(smartTargetingMode || 'SMART_TARGETING_OPEN')
     }, [smartTargetingMode])
 
+    // 如果是智能投放 处理定向规则
+    useEffect(() => {
+        if (adgroups && adgroups?.deliveryMethod === "SMART" && adgroups?.smartDeliveryPlatform && adgroups?.smartDeliverySceneSpec?.smartDeliveryGoal) {
+            const { smartDeliveryPlatform, smartDeliverySceneSpec: { smartDeliveryGoal } } = adgroups
+            const option = sdpRules.find(item => item.smart_delivery_platform === smartDeliveryPlatform)?.smart_delivery_goal_options?.find(item => item.value === smartDeliveryGoal)
+            if (option) {
+                const targetingRules = option.parameter_definitions.adgroup.find(item => item.field_name === 'targeting')
+                setTargetRules?.({
+                    desc: '场景化投放-' + SMART_DELIVERY_PLATFORM_ENUM[smartDeliveryPlatform as keyof typeof SMART_DELIVERY_PLATFORM_ENUM],
+                    rules: targetingRules?.sub_field_whitelist?.map(item => toCamelCase(item.field_name) as string) || []
+                })
+            }
+        } else {
+            setTargetRules?.(undefined)
+        }
+    }, [adgroups])
+
     const setSmartTargetingMode = (smartTargetingMode: 'SMART_TARGETING_OPEN' | 'SMART_TARGETING_MANUAL') => {
         const adgroups = { ...addelivery.adgroups, smartTargetingMode }
         if (smartTargetingMode === 'SMART_TARGETING_OPEN') {
@@ -123,6 +143,7 @@ const Target: React.FC = () => {
             value={targeting?.filter(item => item?.id)}
             visible={addVisible}
             putInType={putInType}
+            targetRules={targetRules}
             onClose={() => {
                 setAddVisible(false)
             }}
@@ -142,6 +163,7 @@ const Target: React.FC = () => {
             isBackVal={true}
             putInType={putInType}
             visible={addTemVisible}
+            targetRules={targetRules}
             onClose={() => {
                 setAddTemVisible(false)
                 setModifyDta(undefined)

+ 32 - 4
src/pages/launchSystemV3/tencentAdPutIn/create/Target/selectTarget.tsx

@@ -11,6 +11,7 @@ import Tables from "@/components/Tables";
 import { TableConfig } from "./tableConfig";
 import { getTargetingGagsApi } from "@/services/adqV3/global";
 import { randomString } from "@/utils/utils";
+import { targetingData } from "@/pages/launchSystemV3/components/TargetingTooltip";
 const { Title, Text } = Typography;
 
 interface Props {
@@ -19,6 +20,7 @@ interface Props {
     visible?: boolean
     onClose?: () => void
     onChange?: (value: any) => void
+    targetRules?: PULLIN.TargetingRulesProps
 }
 
 /**
@@ -26,7 +28,7 @@ interface Props {
  * @param param0 
  * @returns 
  */
-const SelectTarget: React.FC<Props> = ({ value = [], putInType, visible, onChange, onClose }) => {
+const SelectTarget: React.FC<Props> = ({ value = [], putInType, visible, onChange, onClose, targetRules }) => {
 
     /*****************************/
     const [distributionRule, setDistributionRule] = useState<'1' | '2'>('1')
@@ -38,6 +40,7 @@ const SelectTarget: React.FC<Props> = ({ value = [], putInType, visible, onChang
     const [modelList, setModelList] = useState<any>({})  // 所有品牌手机
     const [modifyDta, setModifyDta] = useState<any>()
     const [selectedTargetKeys, setSelectedTargetKeys] = useState<any[]>(value)
+    const [tableList, setTableList] = useState<any[]>([])
 
     const getTargetingGags = useAjax((params) => getTargetingGagsApi(params))
     const getTargetingList = useAjax((params) => getTargetingListApi(params))
@@ -67,8 +70,30 @@ const SelectTarget: React.FC<Props> = ({ value = [], putInType, visible, onChang
     }, [])
 
     useEffect(() => {
-        getTargetingList.run({...queryParamsNew, taskType: putInType})
-    }, [queryParamsNew])
+        getTargetingList.run({ ...queryParamsNew, taskType: putInType }).then(res => {
+            let newTableList = res?.records || []
+            if (targetRules) {
+                let target = ''
+                const rulesField = new Set(targetRules.rules.map(item => {
+                    const fieldName = item
+                    let targetName = targetingData.find(item => item.key === fieldName)?.name
+                    if (!targetName) {
+                        targetName = { excludedCustomAudience: '排除用户群', customAudience: '定向用户群' }[fieldName]
+                    }
+                    target += target ? ',' + targetName : targetName
+                    return fieldName
+                }))
+                const msg = targetRules.desc + ',仅支持' + target
+                newTableList = newTableList.map((item: { targeting: Record<string, any> }) => {
+                    if (Object.keys(item.targeting).every(key => rulesField.has(key))) {
+                        return { ...item, isSelect: true, noSelectMsg: '' }
+                    }
+                    return { ...item, isSelect: false, noSelectMsg: msg }
+                })
+            }
+            setTableList(newTableList || [])
+        })
+    }, [queryParamsNew, targetRules])
 
     /** 编辑 复制 */
     const editHandle = (data: any, isCopy?: boolean) => {
@@ -141,7 +166,7 @@ const SelectTarget: React.FC<Props> = ({ value = [], putInType, visible, onChang
                         </div>
                         <Tables
                             columns={TableConfig(geoLocationList, modelList, editHandle)}
-                            dataSource={getTargetingList?.data?.records}
+                            dataSource={tableList}
                             size="small"
                             loading={getTargetingList?.loading}
                             scroll={{ y: 320 }}
@@ -149,6 +174,9 @@ const SelectTarget: React.FC<Props> = ({ value = [], putInType, visible, onChang
                             rowSelection={{
                                 type: 'checkbox',
                                 selectedRowKeys: selectedTargetKeys?.map((item: any) => item?.id?.toString()),
+                                getCheckboxProps: (record: any) => ({
+                                    disabled: Object.keys(record).includes('isSelect') ? !record.isSelect : false
+                                }),
                                 onChange: (_: React.Key[], selectedRows: any) => {
                                     setSelectedTargetKeys(selectedRows)
                                 }

+ 14 - 2
src/pages/launchSystemV3/tencentAdPutIn/create/Target/tableConfig.tsx

@@ -1,6 +1,6 @@
 import TargetingTooltip from "@/pages/launchSystemV3/components/TargetingTooltip";
 import { QuestionCircleFilled } from "@ant-design/icons";
-import { Button, Popover, Space, Typography } from "antd";
+import { Button, Popover, Space, Tooltip, Typography } from "antd";
 import { ColumnsType } from "antd/es/table";
 import React from "react";
 
@@ -31,6 +31,18 @@ export function TableConfig(geoLocationList: any, modelList: any, editHandle: (d
                 </div>
             }
         },
+        {
+            title: '说明',
+            dataIndex: 'isSelect',
+            key: 'isSelect',
+            align: 'center',
+            width: 120,
+            render(value, record) {
+                return (Object.keys(record).includes('isSelect') && !value && record?.noSelectMsg) ? <Tooltip placement="right" title={record.noSelectMsg}>
+                    <span style={{color: '#FF9B48'}}>包含不支持内容</span>
+                </Tooltip> : '--'
+            },
+        },
         {
             title: '关联账户',
             dataIndex: 'accountId',
@@ -77,7 +89,7 @@ export function TableConfig(geoLocationList: any, modelList: any, editHandle: (d
             key: 'cz',
             align: 'center',
             fixed: 'right',
-            width: 120,
+            width: 95,
             render: (a: any, b: any) => {
                 return <Space wrap>
                     <Button type="link" style={{ padding: 0, fontSize: 12 }} onClick={() => { editHandle(b) }} >编辑</Button>

+ 15 - 2
src/pages/launchSystemV3/tencentAdPutIn/create/addDynamic.tsx

@@ -127,13 +127,26 @@ const AddDynamic: React.FC<PULLIN.NewAddDynamic> = ({ visible, onChange, onClose
                 textData
             } = JSON.parse(tactics.strategyValue)
             setAccountCreateLogs(accountCreateLogs)
+            if (addelivery?.adgroups) {
+                if (addelivery?.adgroups?.smartDeliveryPlatform) {
+                    addelivery.adgroups.deliveryMethod = 'SMART'
+                } else {
+                    addelivery.adgroups.deliveryMethod = 'NORMAL'
+                }
+            }
             setAddelivery(addelivery)
             setAdData(adData)
             setMaterialData(materialData)
             setTextData(textData)
         } else if (selectData?.length > 0) {
-            const { siteSet, marketingCarrierType, marketingGoal, marketingTargetType, sceneSpec, automaticSiteEnabled, marketingSubGoal } = selectData[0]
-            setAddelivery({ ...addelivery, adgroups: { marketingGoal, marketingSubGoal, marketingCarrierType, siteSet, automaticSiteEnabled, sceneSpec, marketingAssetOuterSpec: { marketingTargetType } } })
+            const { siteSet, marketingCarrierType, marketingGoal, marketingTargetType, sceneSpec, automaticSiteEnabled, marketingSubGoal, smartDeliveryPlatform } = selectData[0]
+            let adgroups: Record<string, any> = {}
+            if (smartDeliveryPlatform) {
+                adgroups = { marketingGoal, marketingSubGoal, marketingCarrierType, automaticSiteEnabled: true, marketingAssetOuterSpec: { marketingTargetType }, deliveryMethod: 'SMART' }
+            } else {
+                adgroups = { marketingGoal, marketingSubGoal, marketingCarrierType, siteSet, automaticSiteEnabled, sceneSpec, marketingAssetOuterSpec: { marketingTargetType }, deliveryMethod: 'NORMAL' }
+            }
+            setAddelivery({ ...addelivery, adgroups })
             let AccountSet = new Set(selectData.map(item => item.accountId))
             setAccountCreateLogs([...AccountSet].map(accountId => ({ accountId })))
         }

+ 10 - 4
src/pages/launchSystemV3/tencentAdPutIn/create/index.tsx

@@ -66,6 +66,7 @@ const Create: React.FC = () => {
     const [copyTask, setCopyTask] = useState<{ copyTaskId?: number, uuid?: string }>({})
     const [ownerAccountId, setOwnerAccountId] = useState<number>()
     const [isDqSubmit, setIsDqSubmit] = useState<boolean>(false) // 是否提交过
+    const [targetRules, setTargetRules] = useState<PULLIN.TargetingRulesProps>()
 
     const createAdgroupTask = useAjax((params) => createAdgroupTaskApi(params))
     const createAdgroupTaskV2 = useAjax((params) => createAdgroupTaskV2Api(params))
@@ -312,7 +313,7 @@ const Create: React.FC = () => {
                             }
 
                             setAddelivery({
-                                adgroups: { ...adgroupDTO, isConversion, adgroupName: adgroupDTO.adgroupName + '_副本' + randomString(true, 3, 5), endDate, beginDate },
+                                adgroups: { ...adgroupDTO, isConversion, adgroupName: adgroupDTO.adgroupName + '_副本' + randomString(true, 3, 5), endDate, beginDate, deliveryMethod: adgroupDTO?.deliveryMethod || 'NORMAL' },
                                 targeting: targetings.map((item: any) => {
                                     const { targetingName, ...targeting } = item
                                     return { targetingName, targeting }
@@ -352,6 +353,9 @@ const Create: React.FC = () => {
                         }
                     }
                 }
+                if (addelivery?.adgroups && Object.keys(addelivery?.adgroups)?.length && !addelivery?.adgroups?.deliveryMethod) {
+                    addelivery.adgroups.deliveryMethod = 'NORMAL'
+                }
                 setAddelivery({ ...addelivery })
                 setAccountCreateLogs(accountCreateLogs)
                 setMaterialData(materialData)
@@ -1013,8 +1017,8 @@ const Create: React.FC = () => {
                             :
                             <Button type="primary" danger={!accountCreateLogs?.some(item => item?.newConversionList?.length)} onClick={() => { setConversionVisible(true) }}>{accountCreateLogs?.some(item => item?.newConversionList?.length) ? <>重新选择转化归因<CheckOutlined style={{ color: '#FFF' }} /></> : '请选择转化归因'}</Button>
                         }
-                        {(siteSet?.includes('SITE_SET_MOBILE_UNION') || automaticSiteEnabled) && <Button onClick={() => { setPositionPackageVisible(true) }}>优量汇流量包(选填){accountCreateLogs?.some(item => item?.unionPositionPackage?.length || item?.excludeUnionPositionPackage?.length) && <CheckOutlined style={{ color: accountCreateLogs?.every(item => item?.unionPositionPackage?.length && item?.excludeUnionPositionPackage?.length) ? '#1890ff' : '#52C41A' }} />}</Button>}
-                        <Button onClick={() => { setAudienceVisible(true) }}>自定义人群包(选填){accountCreateLogs?.some(item => item?.customAudience?.length || item?.excludedCustomAudience?.length) && <CheckOutlined style={{ color: accountCreateLogs?.every(item => item?.customAudience?.length && item?.excludedCustomAudience?.length) ? '#1890ff' : '#52C41A' }} />}</Button>
+                        {((siteSet?.includes('SITE_SET_MOBILE_UNION') || automaticSiteEnabled) && addelivery?.adgroups?.deliveryMethod !== 'SMART') && <Button onClick={() => { setPositionPackageVisible(true) }}>优量汇流量包(选填){accountCreateLogs?.some(item => item?.unionPositionPackage?.length || item?.excludeUnionPositionPackage?.length) && <CheckOutlined style={{ color: accountCreateLogs?.every(item => item?.unionPositionPackage?.length && item?.excludeUnionPositionPackage?.length) ? '#1890ff' : '#52C41A' }} />}</Button>}
+                        {((targetRules?.rules && targetRules?.rules?.length > 0) ? targetRules?.rules?.includes('excludedCustomAudience') : true) && <Button onClick={() => { setAudienceVisible(true) }}>自定义人群包(选填){accountCreateLogs?.some(item => item?.customAudience?.length || item?.excludedCustomAudience?.length) && <CheckOutlined style={{ color: accountCreateLogs?.every(item => item?.customAudience?.length && item?.excludedCustomAudience?.length) ? '#1890ff' : '#52C41A' }} />}</Button>}
                     </>}
                 </Space>
 
@@ -1034,7 +1038,9 @@ const Create: React.FC = () => {
                                 putInType,
                                 adLength,
                                 isDqSubmit,
-                                setIsDqSubmit
+                                setIsDqSubmit,
+                                targetRules, 
+                                setTargetRules
                             }}>
                             <div className={style.settingsBody_content_right}>
                                 {/* 广告信息 */}

+ 33 - 3
src/pages/launchSystemV3/tencentAdPutIn/create/tableConfig.tsx

@@ -4,7 +4,7 @@ const { Text, Title } = Typography;
 import style from './index.less'
 import VideoNews from "@/pages/launchSystemNew/components/newsModal/videoNews";
 import styles from './Material/index.less'
-import { MARKETING_TARGET_TYPE_ENUM, OPTIMIZATIONGOAL_ENUM } from "../const";
+import { MARKETING_TARGET_TYPE_ENUM, OPTIMIZATIONGOAL_ENUM, SMART_DELIVERY_GOAL_ENUM } from "../const";
 import ImageXXXC from "../../components/AdsComponent/ImageXXXC";
 
 const columns = (): TableProps<any>['columns'] => {
@@ -28,6 +28,19 @@ const columns = (): TableProps<any>['columns'] => {
                         rowSpan: record?.isRowSpan ? record.rowSpan : !(index % record.rowSpan) ? record.rowSpan : 0
                     })
                 },
+                {
+                    title: '投放方式',
+                    dataIndex: 'deliveryMethod',
+                    key: 'deliveryMethod',
+                    width: 90,
+                    align: 'center',
+                    render: (_, b) => {
+                        return <Text style={{ fontSize: 12 }}>{b?.adgroupsDto?.deliveryMethod === 'SMART' ? '智能投放' : '常规投放'}</Text>
+                    },
+                    onCell: (record, index = 0) => ({
+                        rowSpan: record?.isRowSpan ? record.rowSpan : !(index % record.rowSpan) ? record.rowSpan : 0
+                    })
+                },
                 {
                     title: '营销内容',
                     dataIndex: 'productName',
@@ -92,10 +105,27 @@ const columns = (): TableProps<any>['columns'] => {
                     key: 'dailyBudget',
                     width: 170,
                     render: (_, b) => {
-                        let { optimizationGoal, dailyBudget, bidAmount, bidMode } = b?.adgroupsDto
+                        const { optimizationGoal, dailyBudget, bidAmount, bidMode, deliveryMethod, smartDeliverySceneSpec, bidAllocationMode } = b?.adgroupsDto
+
+                        function getBidAmount() {
+                            if (deliveryMethod === 'SMART') {
+                                const goalDto = SMART_DELIVERY_GOAL_ENUM[smartDeliverySceneSpec?.smartDeliveryGoal as keyof typeof SMART_DELIVERY_GOAL_ENUM]
+                                if ([2, 3].includes(bidAllocationMode)) {
+                                    const data = smartDeliverySceneSpec?.smartDeliveryGoalSpec?.[goalDto?.smartDeliveryGoalSpecName]
+                                    return goalDto?.smartDeliveryGoalSpec?.map(item => <Text key={item.field_name} style={{ fontSize: 12 }}>{item.title}: {data?.[item.field_name + 'Min']}-{data?.[item.field_name + 'Max']}{item?.unitTips || ''}</Text>)
+                                } else {
+                                    return goalDto?.smartDeliveryGoalSpec?.map(item => <Text key={item.field_name} style={{ fontSize: 12 }}>{item.title}: {smartDeliverySceneSpec?.smartDeliveryGoalSpec?.[goalDto?.smartDeliveryGoalSpecName]?.[item.field_name]}{item?.unitTips || ''}</Text>)
+                                }
+                            }
+                            return null
+                        }
+
                         return <Space size={0} direction="vertical">
                             <Text style={{ fontSize: 12 }}>广告日预算:{dailyBudget ? dailyBudget + '元/天' : '不限'}</Text>
-                            <Text style={{ fontSize: 12 }}>出价:{bidAmount}元/{optimizationGoal ? (OPTIMIZATIONGOAL_ENUM as any)[optimizationGoal] : ['BID_MODE_OCPM', 'BID_MODE_OCPC'].includes(bidMode) ? '千次曝光' : '点击'}</Text>
+                            {deliveryMethod !== 'SMART' ?
+                                <Text style={{ fontSize: 12 }}>出价:{bidAmount}元/{optimizationGoal ? (OPTIMIZATIONGOAL_ENUM as any)[optimizationGoal] : ['BID_MODE_OCPM', 'BID_MODE_OCPC'].includes(bidMode) ? '千次曝光' : '点击'}</Text> :
+                                getBidAmount()
+                            }
                         </Space>
                     },
                     onCell: (record, index = 0) => ({

+ 842 - 21
src/pages/launchSystemV3/tencentAdPutIn/rules.ts

@@ -1535,9 +1535,9 @@ export const adRules: AdRules = {
 				"MARKETING_CARRIER_TYPE_JUMP_PAGE": {
 					"PRODUCT_TYPE": 43
 				},
-				"MARKETING_CARRIER_TYPE_WECHAT_OFFICIAL_ACCOUNT": {
-					"PRODUCT_TYPE": 23
-				}
+				// "MARKETING_CARRIER_TYPE_WECHAT_OFFICIAL_ACCOUNT": {
+				// 	"PRODUCT_TYPE": 23
+				// }
 			}
 		},
 		"MARKETING_TARGET_TYPE_MINI_PROGRAM_WECHAT": {
@@ -1555,9 +1555,9 @@ export const adRules: AdRules = {
 				"MARKETING_CARRIER_TYPE_JUMP_PAGE": {
 					"PRODUCT_TYPE": 43
 				},
-				"MARKETING_CARRIER_TYPE_WECHAT_OFFICIAL_ACCOUNT": {
-					"PRODUCT_TYPE": 23
-				}
+				// "MARKETING_CARRIER_TYPE_WECHAT_OFFICIAL_ACCOUNT": {
+				// 	"PRODUCT_TYPE": 23
+				// }
 			}
 		},
 		"MARKETING_TARGET_TYPE_WECHAT_CHANNELS": {
@@ -1577,13 +1577,13 @@ export const adRules: AdRules = {
 				}
 			}
 		},
-		"MARKETING_TARGET_TYPE_WECHAT_OFFICIAL_ACCOUNT": {
-			"MARKETING_SUB_GOAL_UNKNOWN": {
-				"MARKETING_CARRIER_TYPE_WECHAT_OFFICIAL_ACCOUNT": {
-					"PRODUCT_TYPE": 23
-				}
-			}
-		},
+		// "MARKETING_TARGET_TYPE_WECHAT_OFFICIAL_ACCOUNT": {
+		// 	"MARKETING_SUB_GOAL_UNKNOWN": {
+		// 		"MARKETING_CARRIER_TYPE_WECHAT_OFFICIAL_ACCOUNT": {
+		// 			"PRODUCT_TYPE": 23
+		// 		}
+		// 	}
+		// },
 		"MARKETING_TARGET_TYPE_WECHAT_WORK": {
 			"MARKETING_SUB_GOAL_UNKNOWN": {
 				"MARKETING_CARRIER_TYPE_JUMP_PAGE": {
@@ -1834,13 +1834,13 @@ export const adRules: AdRules = {
 				}
 			}
 		},
-		"MARKETING_TARGET_TYPE_WECHAT_WORK": {
-			"MARKETING_SUB_GOAL_UNKNOWN": {
-				"MARKETING_CARRIER_TYPE_JUMP_PAGE": {
-					"PRODUCT_TYPE": 43
-				}
-			}
-		},
+		// "MARKETING_TARGET_TYPE_WECHAT_WORK": {
+		// 	"MARKETING_SUB_GOAL_UNKNOWN": {
+		// 		"MARKETING_CARRIER_TYPE_JUMP_PAGE": {
+		// 			"PRODUCT_TYPE": 43
+		// 		}
+		// 	}
+		// },
 		"MARKETING_SUB_GOAL_MINI_GAME_NEW_CUSTOMER_GROWTH": {
 			"MARKETING_TARGET_TYPE_WECHAT_MINI_GAME": {
 				"MARKETING_SUB_GOAL_UNKNOWN": {
@@ -1857,5 +1857,826 @@ export const adRules: AdRules = {
 				}
 			}
 		}
+	},
+
+	// 智能投放
+	// 小说智投
+	"SMART_DELIVERY_PLATFORM_EDITION_FICTION": {
+		// 商品销售
+		"MARKETING_GOAL_PRODUCT_SALES": {
+			"MARKETING_TARGET_TYPE_FICTION": {
+				"MARKETING_SUB_GOAL_UNKNOWN": {
+					"MARKETING_CARRIER_TYPE_JUMP_PAGE": {
+						"PRODUCT_TYPE": 43,
+						"GOAL_TYPE": ["FICTION_REGISTER_PURCHASE_ROI", "_24H_FIRSTPAY"]
+					},
+					"MARKETING_CARRIER_TYPE_WECHAT_OFFICIAL_ACCOUNT": {
+						"PRODUCT_TYPE": 23,
+						"GOAL_TYPE": ["FICTION_FOLLOW_PURCHASE_ROI", "_24H_FIRSTPAY"]
+					}
+				}
+			},
+			"MARKETING_TARGET_TYPE_WECHAT_OFFICIAL_ACCOUNT": {
+				"MARKETING_SUB_GOAL_UNKNOWN": {
+					"MARKETING_CARRIER_TYPE_WECHAT_OFFICIAL_ACCOUNT": {
+						"PRODUCT_TYPE": 23,
+						"GOAL_TYPE": ["FICTION_FOLLOW_PURCHASE_ROI", "_24H_FIRSTPAY"]
+					}
+				}
+			},
+			"MARKETING_TARGET_TYPE_MINI_PROGRAM_WECHAT": {
+				"MARKETING_SUB_GOAL_UNKNOWN": {
+					"MARKETING_CARRIER_TYPE_JUMP_PAGE": {
+						"PRODUCT_TYPE": 43,
+						"GOAL_TYPE": ["FICTION_REGISTER_PURCHASE_ROI", "_24H_FIRSTPAY"]
+					}
+				}
+			},
+			"MARKETING_TARGET_TYPE_WECHAT_WORK": {
+				"MARKETING_SUB_GOAL_UNKNOWN": {
+					"MARKETING_CARRIER_TYPE_JUMP_PAGE": {
+						"PRODUCT_TYPE": 43,
+						"GOAL_TYPE": ["_24H_FIRSTPAY"]
+					}
+				}
+			}
+		},
+		// 用户增长
+		"MARKETING_GOAL_USER_GROWTH": {
+			"MARKETING_TARGET_TYPE_FICTION": {
+				"MARKETING_SUB_GOAL_UNKNOWN": {
+					"MARKETING_CARRIER_TYPE_JUMP_PAGE": {
+						"PRODUCT_TYPE": 43,
+						"GOAL_TYPE": ["FICTION_REGISTER_MONETIZATION_ROI"]
+					}
+				}
+			}
+		}
+	},
+	// 爆剧跑量
+	"SMART_DELIVERY_PLATFORM_EDITION_ECOLOGY_PLAYLET": {
+
+	},
+	// 线索跑量
+	"SMART_DELIVERY_PLATFORM_EDITION_ECOLOGY_LEADS": {
+
 	}
-}
+}
+
+
+// 投放目标设置
+export const sdpRules = [{
+	"smart_delivery_platform": "SMART_DELIVERY_PLATFORM_EDITION_FICTION",
+	"permissions": [{
+		"marketing_goal": "MARKETING_GOAL_PRODUCT_SALES",
+		"marketing_target_type": "MARKETING_TARGET_TYPE_FICTION",
+		"marketing_carrier_type": "MARKETING_CARRIER_TYPE_WECHAT_OFFICIAL_ACCOUNT",
+		"white_list": ["automatic_fiction_new"]
+	}, {
+		"marketing_goal": "MARKETING_GOAL_PRODUCT_SALES",
+		"marketing_target_type": "MARKETING_TARGET_TYPE_FICTION",
+		"marketing_carrier_type": "MARKETING_CARRIER_TYPE_JUMP_PAGE",
+		"white_list": ["automatic_fiction_new"]
+	}, {
+		"marketing_goal": "MARKETING_GOAL_PRODUCT_SALES",
+		"marketing_target_type": "MARKETING_TARGET_TYPE_WECHAT_OFFICIAL_ACCOUNT",
+		"marketing_carrier_type": "MARKETING_CARRIER_TYPE_WECHAT_OFFICIAL_ACCOUNT",
+		"white_list": ["automatic_fiction_new"]
+	}, {
+		"marketing_goal": "MARKETING_GOAL_PRODUCT_SALES",
+		"marketing_target_type": "MARKETING_TARGET_TYPE_MINI_PROGRAM_WECHAT",
+		"marketing_carrier_type": "MARKETING_CARRIER_TYPE_JUMP_PAGE",
+		"white_list": ["automatic_fiction_new"]
+	}, {
+		"marketing_goal": "MARKETING_GOAL_USER_GROWTH",
+		"marketing_target_type": "MARKETING_TARGET_TYPE_FICTION",
+		"marketing_carrier_type": "MARKETING_CARRIER_TYPE_JUMP_PAGE",
+		"white_list": ["automatic_fiction_new"]
+	}, {
+		"marketing_goal": "MARKETING_GOAL_PRODUCT_SALES",
+		"marketing_target_type": "MARKETING_TARGET_TYPE_WECHAT_WORK",
+		"marketing_carrier_type": "MARKETING_CARRIER_TYPE_JUMP_PAGE",
+		"white_list": ["automatic_fiction_new"]
+	}],
+	"smart_delivery_goal_options": [{
+		"value": "FICTION_FOLLOW_PURCHASE_ROI",
+		"optimization_goal_combos": [{
+			"optimization_goal": "OPTIMIZATIONGOAL_FOLLOW",
+			"deep_worth_optimization_goal": "GOAL_1DAY_PURCHASE_ROAS",
+			"title": "关注和首日付费ROI"
+		}],
+		"smart_delivery_goal_spec_name": "fiction_follow_purchase_roi_spec",
+		"parameter_definitions": {
+			"adgroup": [{
+				"field_name": "targeting",
+				"sub_field_whitelist": [{
+					"field_name": "age"
+				}, {
+					"field_name": "gender"
+				}, {
+					"field_name": "excluded_custom_audience"
+				}, {
+					"field_name": "custom_audience"
+				}, {
+					"field_name": "excluded_converted_audience"
+				}]
+			}, {
+				"field_name": "deep_conversion_worth_rate",
+				"hidden": true,
+				"is_idl_invisible": true,
+				"copy_by_field": "SmartDeliverySceneSpec.SmartDeliveryGoalSpec.FictionFollowPurchaseRoiSpec.FirstDayPurchaseRoi"
+			}, {
+				"field_name": "bid_amount",
+				"fixed_value": "IjE1MCI=",
+				"hidden": true,
+				"is_idl_invisible": true,
+				"copy_by_field": "SmartDeliverySceneSpec.SmartDeliveryGoalSpec.FictionFollowPurchaseRoiSpec.FollowCost"
+			}, {
+				"field_name": "automatic_site_enabled",
+				"fixed_value": "InRydWUi",
+				"is_idl_invisible": true,
+				"can_not_update": true
+			}, {
+				"field_name": "rta_policy",
+				"hidden": true,
+				"is_idl_invisible": true
+			}, {
+				"field_name": "total_budget",
+				"hidden": true,
+				"is_idl_invisible": true
+			}, {
+				"field_name": "rta_target_id",
+				"hidden": true,
+				"is_idl_invisible": true
+			}, {
+				"field_name": "deep_conversion_behavior_bid",
+				"is_idl_invisible": true
+			}, {
+				"field_name": "cloud_union_spec",
+				"is_idl_invisible": true
+			}, {
+				"field_name": "enable_breakthrough_siteset",
+				"is_idl_invisible": true
+			}, {
+				"field_name": "custom_cost_cap",
+				"is_idl_invisible": true
+			}, {
+				"field_name": "deep_conversion_spec",
+				"is_idl_invisible": true
+			}, {
+				"field_name": "deep_conversion_worth_advanced_rate",
+				"hidden": true,
+				"is_idl_invisible": true
+			}, {
+				"field_name": "smart_cost_cap",
+				"is_idl_invisible": true
+			}, {
+				"field_name": "flow_optimization_enabled",
+				"fixed_value": "ImZhbHNlIg==",
+				"is_idl_invisible": true,
+				"can_not_update": true
+			}, {
+				"field_name": "cost_constraint_scene",
+				"is_idl_invisible": true
+			}, {
+				"field_name": "ecom_pkam_switch",
+				"fixed_value": "IkVDT01fUEtBTV9TV0lUQ0hfQ0xPU0Ui",
+				"hidden": true,
+				"is_idl_invisible": true,
+				"can_not_update": true
+			}, {
+				"field_name": "poi_list",
+				"hidden": true,
+				"is_idl_invisible": true
+			}, {
+				"field_name": "site_set",
+				"is_idl_invisible": true,
+				"can_not_update": true
+			}, {
+				"field_name": "conversion_id",
+				"is_idl_invisible": true,
+				"can_not_update": true
+			}, {
+				"field_name": "deep_conversion_behavior_advanced_bid",
+				"is_idl_invisible": true
+			}, {
+				"field_name": "search_expand_targeting_switch",
+				"fixed_value": "IlNFQVJDSF9FWFBBTkRfVEFSR0VUSU5HX1NXSVRDSF9DTE9TRSI=",
+				"is_idl_invisible": true,
+				"can_not_update": true
+			}, {
+				"field_name": "exploration_strategy",
+				"fixed_value": "IkFVVE9NQVRJQ19FWFBMT1JBVElPTiI=",
+				"hidden": true,
+				"is_idl_invisible": true,
+				"can_not_update": true
+			}, {
+				"field_name": "optimization_goal",
+				"is_idl_invisible": true
+			}, {
+				"field_name": "bid_scene",
+				"hidden": true
+			}, {
+				"field_name": "feedback_id",
+				"hidden": true,
+				"is_idl_invisible": true
+			}, {
+				"field_name": "aoi_optimization_strategy",
+				"hidden": true,
+				"is_idl_invisible": true
+			}, {
+				"field_name": "additional_product_spec",
+				"hidden": true,
+				"is_idl_invisible": true
+			}, {
+				"field_name": "smart_bid_type",
+				"hidden": true
+			}, {
+				"field_name": "priority_site_set",
+				"is_idl_invisible": true,
+				"can_not_update": true
+			}, {
+				"field_name": "rta_id",
+				"hidden": true,
+				"is_idl_invisible": true
+			}, {
+				"field_name": "bid_mode",
+				"fixed_value": "IkJJRF9NT0RFX09DUE0i",
+				"is_idl_invisible": true,
+				"can_not_update": true
+			}, {
+				"field_name": "auto_acquisition_enabled",
+				"fixed_value": "ImZhbHNlIg==",
+				"hidden": true,
+				"is_idl_invisible": true,
+				"can_not_update": true
+			}, {
+				"field_name": "auto_acquisition_budget",
+				"is_idl_invisible": true
+			}, {
+				"field_name": "scene_spec",
+				"hidden": true,
+				"is_idl_invisible": true
+			}],
+			"smart_delivery_goal_spec": [{
+				"field_name": "follow_cost",
+				"title": "关注成本",
+				"display_component": "DISPLAY_COMPONENT_COST",
+				"placeholder": "请输入关注成本",
+				"min": 1.5,
+				"max": 999,
+				"decimal_length": 2,
+				"required": true,
+				"decimal_mkt_length": 2,
+				"unitTips": "元/关注"
+			}, {
+				"field_name": "first_day_purchase_roi",
+				"title": "首日付费ROI",
+				"display_component": "DISPLAY_COMPONENT_ROI",
+				"placeholder": "范围 0.001~50,输入0.05,ROI 目标为 5%",
+				"min": 0.001,
+				"max": 50,
+				"decimal_length": 3,
+				"required": true
+			}]
+		}
+	}, {
+		"value": "FICTION_REGISTER_PURCHASE_ROI",
+		"optimization_goal_combos": [{
+			"optimization_goal": "OPTIMIZATIONGOAL_APP_REGISTER",
+			"deep_worth_optimization_goal": "GOAL_1DAY_PURCHASE_ROAS",
+			"title": "注册和首日付费ROI"
+		}],
+		"smart_delivery_goal_spec_name": "fiction_register_purchase_roi_spec",
+		"parameter_definitions": {
+			"adgroup": [{
+				"field_name": "targeting",
+				"sub_field_whitelist": [{
+					"field_name": "age"
+				}, {
+					"field_name": "gender"
+				}, {
+					"field_name": "excluded_custom_audience"
+				}, {
+					"field_name": "custom_audience"
+				}, {
+					"field_name": "excluded_converted_audience"
+				}]
+			}, {
+				"field_name": "deep_conversion_worth_rate",
+				"hidden": true,
+				"is_idl_invisible": true,
+				"copy_by_field": "SmartDeliverySceneSpec.SmartDeliveryGoalSpec.FictionRegisterPurchaseRoiSpec.FirstDayPurchaseRoi"
+			}, {
+				"field_name": "bid_amount",
+				"fixed_value": "IjE1MCI=",
+				"hidden": true,
+				"is_idl_invisible": true,
+				"copy_by_field": "SmartDeliverySceneSpec.SmartDeliveryGoalSpec.FictionRegisterPurchaseRoiSpec.RegisterCost"
+			}, {
+				"field_name": "auto_acquisition_budget",
+				"is_idl_invisible": true
+			}, {
+				"field_name": "scene_spec",
+				"hidden": true,
+				"is_idl_invisible": true
+			}, {
+				"field_name": "rta_target_id",
+				"hidden": true,
+				"is_idl_invisible": true
+			}, {
+				"field_name": "automatic_site_enabled",
+				"fixed_value": "InRydWUi",
+				"is_idl_invisible": true,
+				"can_not_update": true
+			}, {
+				"field_name": "rta_policy",
+				"hidden": true,
+				"is_idl_invisible": true
+			}, {
+				"field_name": "total_budget",
+				"hidden": true,
+				"is_idl_invisible": true
+			}, {
+				"field_name": "enable_breakthrough_siteset",
+				"is_idl_invisible": true
+			}, {
+				"field_name": "deep_conversion_behavior_bid",
+				"is_idl_invisible": true
+			}, {
+				"field_name": "cloud_union_spec",
+				"is_idl_invisible": true
+			}, {
+				"field_name": "flow_optimization_enabled",
+				"fixed_value": "ImZhbHNlIg==",
+				"is_idl_invisible": true,
+				"can_not_update": true
+			}, {
+				"field_name": "cost_constraint_scene",
+				"is_idl_invisible": true
+			}, {
+				"field_name": "custom_cost_cap",
+				"is_idl_invisible": true
+			}, {
+				"field_name": "deep_conversion_spec",
+				"is_idl_invisible": true
+			}, {
+				"field_name": "deep_conversion_worth_advanced_rate",
+				"hidden": true,
+				"is_idl_invisible": true
+			}, {
+				"field_name": "smart_cost_cap",
+				"is_idl_invisible": true
+			}, {
+				"field_name": "search_expand_targeting_switch",
+				"fixed_value": "IlNFQVJDSF9FWFBBTkRfVEFSR0VUSU5HX1NXSVRDSF9DTE9TRSI=",
+				"is_idl_invisible": true,
+				"can_not_update": true
+			}, {
+				"field_name": "exploration_strategy",
+				"fixed_value": "IkFVVE9NQVRJQ19FWFBMT1JBVElPTiI=",
+				"hidden": true,
+				"is_idl_invisible": true,
+				"can_not_update": true
+			}, {
+				"field_name": "ecom_pkam_switch",
+				"fixed_value": "IkVDT01fUEtBTV9TV0lUQ0hfQ0xPU0Ui",
+				"hidden": true,
+				"is_idl_invisible": true,
+				"can_not_update": true
+			}, {
+				"field_name": "poi_list",
+				"hidden": true,
+				"is_idl_invisible": true
+			}, {
+				"field_name": "site_set",
+				"is_idl_invisible": true,
+				"can_not_update": true
+			}, {
+				"field_name": "conversion_id",
+				"is_idl_invisible": true,
+				"can_not_update": true
+			}, {
+				"field_name": "deep_conversion_behavior_advanced_bid",
+				"is_idl_invisible": true
+			}, {
+				"field_name": "aoi_optimization_strategy",
+				"hidden": true,
+				"is_idl_invisible": true
+			}, {
+				"field_name": "additional_product_spec",
+				"hidden": true,
+				"is_idl_invisible": true
+			}, {
+				"field_name": "optimization_goal",
+				"is_idl_invisible": true
+			}, {
+				"field_name": "bid_scene",
+				"hidden": true
+			}, {
+				"field_name": "feedback_id",
+				"hidden": true,
+				"is_idl_invisible": true
+			}, {
+				"field_name": "smart_bid_type",
+				"hidden": true
+			}, {
+				"field_name": "priority_site_set",
+				"is_idl_invisible": true,
+				"can_not_update": true
+			}, {
+				"field_name": "rta_id",
+				"hidden": true,
+				"is_idl_invisible": true
+			}, {
+				"field_name": "bid_mode",
+				"fixed_value": "IkJJRF9NT0RFX09DUE0i",
+				"is_idl_invisible": true,
+				"can_not_update": true
+			}, {
+				"field_name": "auto_acquisition_enabled",
+				"fixed_value": "ImZhbHNlIg==",
+				"hidden": true,
+				"is_idl_invisible": true,
+				"can_not_update": true
+			}],
+			"smart_delivery_goal_spec": [{
+				"field_name": "register_cost",
+				"title": "注册成本",
+				"display_component": "DISPLAY_COMPONENT_COST",
+				"placeholder": "请输入注册成本",
+				"min": 1.5,
+				"max": 999,
+				"decimal_length": 2,
+				"required": true,
+				"decimal_mkt_length": 2,
+				"unitTips": "元/关注"
+			}, {
+				"field_name": "first_day_purchase_roi",
+				"title": "首日付费ROI",
+				"display_component": "DISPLAY_COMPONENT_ROI",
+				"placeholder": "范围 0.001~50,输入0.05,ROI 目标为 5%",
+				"min": 0.001,
+				"max": 50,
+				"decimal_length": 3,
+				"required": true
+			}]
+		}
+	}, {
+		"value": "FICTION_REGISTER_MONETIZATION_ROI",
+		"optimization_goal_combos": [{
+			"optimization_goal": "OPTIMIZATIONGOAL_APP_REGISTER",
+			"deep_worth_optimization_goal": "GOAL_1DAY_MONETIZATION_ROAS",
+			"title": "注册和首日变现ROI"
+		}],
+		"smart_delivery_goal_spec_name": "fiction_register_monetization_roi_spec",
+		"parameter_definitions": {
+			"adgroup": [{
+				"field_name": "targeting",
+				"sub_field_whitelist": [{
+					"field_name": "age"
+				}, {
+					"field_name": "gender"
+				}, {
+					"field_name": "excluded_custom_audience"
+				}, {
+					"field_name": "custom_audience"
+				}, {
+					"field_name": "excluded_converted_audience"
+				}]
+			}, {
+				"field_name": "deep_conversion_worth_rate",
+				"hidden": true,
+				"is_idl_invisible": true,
+				"copy_by_field": "SmartDeliverySceneSpec.SmartDeliveryGoalSpec.FictionRegisterMonetizationRoiSpec.FirstDayMonetizationRoi"
+			}, {
+				"field_name": "bid_amount",
+				"fixed_value": "IjE1MCI=",
+				"hidden": true,
+				"is_idl_invisible": true,
+				"copy_by_field": "SmartDeliverySceneSpec.SmartDeliveryGoalSpec.FictionRegisterMonetizationRoiSpec.RegisterCost"
+			}, {
+				"field_name": "deep_conversion_behavior_advanced_bid",
+				"is_idl_invisible": true
+			}, {
+				"field_name": "search_expand_targeting_switch",
+				"fixed_value": "IlNFQVJDSF9FWFBBTkRfVEFSR0VUSU5HX1NXSVRDSF9DTE9TRSI=",
+				"is_idl_invisible": true,
+				"can_not_update": true
+			}, {
+				"field_name": "exploration_strategy",
+				"fixed_value": "IkFVVE9NQVRJQ19FWFBMT1JBVElPTiI=",
+				"hidden": true,
+				"is_idl_invisible": true,
+				"can_not_update": true
+			}, {
+				"field_name": "ecom_pkam_switch",
+				"fixed_value": "IkVDT01fUEtBTV9TV0lUQ0hfQ0xPU0Ui",
+				"hidden": true,
+				"is_idl_invisible": true,
+				"can_not_update": true
+			}, {
+				"field_name": "poi_list",
+				"hidden": true,
+				"is_idl_invisible": true
+			}, {
+				"field_name": "site_set",
+				"is_idl_invisible": true,
+				"can_not_update": true
+			}, {
+				"field_name": "conversion_id",
+				"is_idl_invisible": true,
+				"can_not_update": true
+			}, {
+				"field_name": "feedback_id",
+				"hidden": true,
+				"is_idl_invisible": true
+			}, {
+				"field_name": "aoi_optimization_strategy",
+				"hidden": true,
+				"is_idl_invisible": true
+			}, {
+				"field_name": "additional_product_spec",
+				"hidden": true,
+				"is_idl_invisible": true
+			}, {
+				"field_name": "optimization_goal",
+				"is_idl_invisible": true
+			}, {
+				"field_name": "bid_scene",
+				"hidden": true
+			}, {
+				"field_name": "rta_id",
+				"hidden": true,
+				"is_idl_invisible": true
+			}, {
+				"field_name": "smart_bid_type",
+				"hidden": true
+			}, {
+				"field_name": "priority_site_set",
+				"is_idl_invisible": true,
+				"can_not_update": true
+			}, {
+				"field_name": "bid_mode",
+				"fixed_value": "IkJJRF9NT0RFX09DUE0i",
+				"is_idl_invisible": true,
+				"can_not_update": true
+			}, {
+				"field_name": "auto_acquisition_enabled",
+				"fixed_value": "ImZhbHNlIg==",
+				"hidden": true,
+				"is_idl_invisible": true,
+				"can_not_update": true
+			}, {
+				"field_name": "auto_acquisition_budget",
+				"is_idl_invisible": true
+			}, {
+				"field_name": "scene_spec",
+				"hidden": true,
+				"is_idl_invisible": true
+			}, {
+				"field_name": "total_budget",
+				"hidden": true,
+				"is_idl_invisible": true
+			}, {
+				"field_name": "rta_target_id",
+				"hidden": true,
+				"is_idl_invisible": true
+			}, {
+				"field_name": "automatic_site_enabled",
+				"fixed_value": "InRydWUi",
+				"is_idl_invisible": true,
+				"can_not_update": true
+			}, {
+				"field_name": "rta_policy",
+				"hidden": true,
+				"is_idl_invisible": true
+			}, {
+				"field_name": "cloud_union_spec",
+				"is_idl_invisible": true
+			}, {
+				"field_name": "enable_breakthrough_siteset",
+				"is_idl_invisible": true
+			}, {
+				"field_name": "deep_conversion_behavior_bid",
+				"is_idl_invisible": true
+			}, {
+				"field_name": "smart_cost_cap",
+				"is_idl_invisible": true
+			}, {
+				"field_name": "flow_optimization_enabled",
+				"fixed_value": "ImZhbHNlIg==",
+				"is_idl_invisible": true,
+				"can_not_update": true
+			}, {
+				"field_name": "cost_constraint_scene",
+				"is_idl_invisible": true
+			}, {
+				"field_name": "custom_cost_cap",
+				"is_idl_invisible": true
+			}, {
+				"field_name": "deep_conversion_spec",
+				"is_idl_invisible": true
+			}, {
+				"field_name": "deep_conversion_worth_advanced_rate",
+				"hidden": true,
+				"is_idl_invisible": true
+			}],
+			"smart_delivery_goal_spec": [{
+				"field_name": "register_cost",
+				"title": "注册成本",
+				"display_component": "DISPLAY_COMPONENT_COST",
+				"placeholder": "请输入注册成本",
+				"min": 1.5,
+				"max": 999,
+				"decimal_length": 2,
+				"required": true,
+				"decimal_mkt_length": 2,
+				"unitTips": "元/关注"
+			}, {
+				"field_name": "first_day_monetization_roi",
+				"title": "首日变现ROI",
+				"display_component": "DISPLAY_COMPONENT_ROI",
+				"placeholder": "范围 0.001~50,输入0.05,ROI 目标为 5%",
+				"min": 0.001,
+				"max": 50,
+				"decimal_length": 3,
+				"required": true
+			}]
+		}
+	}, {
+		"value": "_24H_FIRSTPAY",
+		"optimization_goal_combos": [{
+			"optimization_goal": "OPTIMIZATIONGOAL_24H_FIRSTPAY",
+			"title": "首日首次付费"
+		}],
+		"smart_delivery_goal_spec_name": "bid_amount_spec",
+		"parameter_definitions": {
+			"adgroup": [{
+				"field_name": "targeting",
+				"sub_field_whitelist": [{
+					"field_name": "age"
+				}, {
+					"field_name": "gender"
+				}, {
+					"field_name": "excluded_custom_audience"
+				}, {
+					"field_name": "custom_audience"
+				}, {
+					"field_name": "excluded_converted_audience"
+				}]
+			}, {
+				"field_name": "bid_amount",
+				"fixed_value": "IjE1MCI=",
+				"hidden": true,
+				"is_idl_invisible": true,
+				"copy_by_field": "SmartDeliverySceneSpec.SmartDeliveryGoalSpec.BidAmountSpec.BidAmount"
+			}, {
+				"field_name": "poi_list",
+				"hidden": true,
+				"is_idl_invisible": true
+			}, {
+				"field_name": "site_set",
+				"is_idl_invisible": true,
+				"can_not_update": true
+			}, {
+				"field_name": "conversion_id",
+				"is_idl_invisible": true,
+				"can_not_update": true
+			}, {
+				"field_name": "deep_conversion_behavior_advanced_bid",
+				"is_idl_invisible": true
+			}, {
+				"field_name": "search_expand_targeting_switch",
+				"fixed_value": "IlNFQVJDSF9FWFBBTkRfVEFSR0VUSU5HX1NXSVRDSF9DTE9TRSI=",
+				"is_idl_invisible": true,
+				"can_not_update": true
+			}, {
+				"field_name": "exploration_strategy",
+				"fixed_value": "IkFVVE9NQVRJQ19FWFBMT1JBVElPTiI=",
+				"hidden": true,
+				"is_idl_invisible": true,
+				"can_not_update": true
+			}, {
+				"field_name": "ecom_pkam_switch",
+				"fixed_value": "IkVDT01fUEtBTV9TV0lUQ0hfQ0xPU0Ui",
+				"hidden": true,
+				"is_idl_invisible": true,
+				"can_not_update": true
+			}, {
+				"field_name": "optimization_goal",
+				"is_idl_invisible": true
+			}, {
+				"field_name": "bid_scene",
+				"hidden": true
+			}, {
+				"field_name": "feedback_id",
+				"hidden": true,
+				"is_idl_invisible": true
+			}, {
+				"field_name": "aoi_optimization_strategy",
+				"hidden": true,
+				"is_idl_invisible": true
+			}, {
+				"field_name": "additional_product_spec",
+				"hidden": true,
+				"is_idl_invisible": true
+			}, {
+				"field_name": "smart_bid_type",
+				"hidden": true
+			}, {
+				"field_name": "priority_site_set",
+				"is_idl_invisible": true,
+				"can_not_update": true
+			}, {
+				"field_name": "rta_id",
+				"hidden": true,
+				"is_idl_invisible": true
+			}, {
+				"field_name": "bid_mode",
+				"fixed_value": "IkJJRF9NT0RFX09DUE0i",
+				"is_idl_invisible": true,
+				"can_not_update": true
+			}, {
+				"field_name": "auto_acquisition_enabled",
+				"fixed_value": "ImZhbHNlIg==",
+				"hidden": true,
+				"is_idl_invisible": true,
+				"can_not_update": true
+			}, {
+				"field_name": "auto_acquisition_budget",
+				"is_idl_invisible": true
+			}, {
+				"field_name": "scene_spec",
+				"hidden": true,
+				"is_idl_invisible": true
+			}, {
+				"field_name": "automatic_site_enabled",
+				"fixed_value": "InRydWUi",
+				"is_idl_invisible": true,
+				"can_not_update": true
+			}, {
+				"field_name": "rta_policy",
+				"hidden": true,
+				"is_idl_invisible": true
+			}, {
+				"field_name": "total_budget",
+				"hidden": true,
+				"is_idl_invisible": true
+			}, {
+				"field_name": "rta_target_id",
+				"hidden": true,
+				"is_idl_invisible": true
+			}, {
+				"field_name": "deep_conversion_behavior_bid",
+				"is_idl_invisible": true
+			}, {
+				"field_name": "deep_conversion_worth_rate",
+				"hidden": true,
+				"is_idl_invisible": true
+			}, {
+				"field_name": "cloud_union_spec",
+				"is_idl_invisible": true
+			}, {
+				"field_name": "enable_breakthrough_siteset",
+				"is_idl_invisible": true
+			}, {
+				"field_name": "deep_conversion_spec",
+				"is_idl_invisible": true
+			}, {
+				"field_name": "deep_conversion_worth_advanced_rate",
+				"hidden": true,
+				"is_idl_invisible": true
+			}, {
+				"field_name": "smart_cost_cap",
+				"is_idl_invisible": true
+			}, {
+				"field_name": "flow_optimization_enabled",
+				"fixed_value": "ImZhbHNlIg==",
+				"is_idl_invisible": true,
+				"can_not_update": true
+			}, {
+				"field_name": "cost_constraint_scene",
+				"is_idl_invisible": true
+			}, {
+				"field_name": "custom_cost_cap",
+				"is_idl_invisible": true
+			}],
+			"smart_delivery_goal_spec": [{
+				"field_name": "bid_amount",
+				"title": "首日首次付费成本",
+				"display_component": "DISPLAY_COMPONENT_COST",
+				"placeholder": "请输入首日首次付费成本",
+				"min": 0.01,
+				"max": 10000,
+				"decimal_length": 2,
+				"required": true,
+				"decimal_mkt_length": 2,
+				"unitTips": "元/首日首次付费"
+			}]
+		}
+	}],
+	"placeholder": "系统帮助客户提升小说跑量能力,客户仅需表达必要的投放诉求,简化投放流程,提升投放效率,同时在达成客户期望的前提下提升跑量能力",
+	"targeting_placeholder": "系统将在受众倾向的基础上有所突破,为你优选更多高质量人群",
+	"industry_code": "ad30_concent"
+}]

+ 40 - 4
src/pages/launchSystemV3/tencentAdPutIn/typings.d.ts

@@ -12,6 +12,8 @@ declare namespace PULLIN {
         form: FormInstance<any>
         OGPParams: OGPParamsProps,
         setOGPparams: React.Dispatch<React.SetStateAction<OGPParamsProps>>
+        smartDeliveryGoalRules: SmartDeliveryGoalOption[]
+        setSmartDeliveryGoalRules: React.Dispatch<React.SetStateAction<SmartDeliveryGoalOption[]>>
         putInType?: 'NOVEL' | 'GAME'
     }
     interface AddeliveryProps {
@@ -38,19 +40,21 @@ declare namespace PULLIN {
         adLength: number
         isDqSubmit?: boolean
         setIsDqSubmit?: React.Dispatch<React.SetStateAction<boolean>>
+        targetRules?: PULLIN.TargetingRulesProps | undefined
+        setTargetRules?: React.Dispatch<React.SetStateAction<PULLIN.TargetingRulesProps | undefined>>
     }
-    type DataType = { label: string | number, value: any, disabled?: boolean }
+    type DataType = { label: string | number, value: any, disabled?: boolean, desc?: string }
     interface FormItemDataProps {
         data: { label: string, value: string, icon: string, iconSelected: string }[]
         id?: any
         value?: string,
         onChange?: (value?: string) => void
     }
-    interface FormItemDataNewProps {
+    interface FormItemDataNewProps<T = any> {
         data: DataType[]
         id?: any,
-        value?: any,
-        onChange?: (value?: any) => void
+        value?: T,
+        onChange?: (value?: T) => void
     }
     interface FormItemDataArrayProps {
         id?: number,
@@ -169,4 +173,36 @@ declare namespace PULLIN {
         type?: string,
         putInType?: 'NOVEL' | 'GAME'
     }
+    interface FormProps<T = any> {
+        value?: T,
+        onChange?: (value?: T) => void
+    }
+    type SmartDeliveryGoalSpecProps = {
+        field_name: string;
+        title: string;
+        display_component: string;
+        placeholder: string;
+        min: number;
+        max: number;
+        decimal_length: number;
+        required: boolean;
+        decimal_mkt_length?: number;
+        unitTips?: string;
+    }
+    type SmartDeliveryGoalOption = {
+        value: string;
+        optimization_goal_combos: Array<{
+            optimization_goal: string;
+            deep_worth_optimization_goal?: string;
+            title: string;
+        }>;
+        smart_delivery_goal_spec_name: string;
+        parameter_definitions: {
+            smart_delivery_goal_spec: Array<SmartDeliveryGoalSpecProps>;
+        };
+    };
+    type TargetingRulesProps = {
+        desc: string,
+        rules: string[]
+    }
 }

+ 10 - 1
src/utils/utils.ts

@@ -534,4 +534,13 @@ export function formatBytes(bytes: number) {
     } else {
         return (bytes / 1073741824).toFixed(2) + ' GB';
     }
-}  
+}
+
+/**
+ * 下划线转驼峰
+ * @param s 
+ * @returns 
+ */
+export const toCamelCase = (s: string): string => {
+    return s.replace(/_([a-zA-Z])/g, (_, g1) => g1.toUpperCase());
+}