index.tsx 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  1. import React, { useContext, useMemo, useState } from "react"
  2. import style from '../index.less'
  3. import NewCreateAd from "./newCreateAd"
  4. import { DispatchAddelivery } from "..";
  5. import { Button, Modal, Typography } from "antd";
  6. import { EditOutlined } from "@ant-design/icons";
  7. 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";
  8. import TimeSeriesLook from "@/pages/launchSystemNew/adq/ad/timeSeriesLook";
  9. import { arraysHaveSameValues } from "@/utils/utils";
  10. import '../../index.less'
  11. import { ShowMiniProgramWechatDetail } from "@/pages/launchSystemV3/tencenTasset/miniProgramWechat";
  12. import { ShowGameAppIdDetail } from "@/pages/launchSystemV3/tencenTasset/game";
  13. import { ShowApplication } from "@/pages/launchSystemV3/tencenTasset/application";
  14. /**
  15. * 广告信息
  16. * @returns
  17. */
  18. const Ad: React.FC = () => {
  19. /*****************************/
  20. const { addelivery, setAddelivery, accountCreateLogs, clearData, setAccountCreateLogs, putInType, setIsDqSubmit } = useContext(DispatchAddelivery)!;
  21. const { adgroups } = addelivery
  22. const {
  23. deliveryMethod, marketingGoal, marketingSubGoal, marketingAssetOuterSpec, marketingCarrierType, automaticSiteEnabled, explorationStrategy, siteSet, prioritySiteSet, searchExpandTargetingSwitch, bidMode, smartBidType, bidScene, bidAmount, optimizationGoal, isConversion, depthConversionEnabled,
  24. deepConversionSpec, ecomPkamSwitch, autoAcquisitionEnabled, autoAcquisitionBudget, dailyBudget, endDate, beginDate, timeSeries, firstDayBeginTime, configuredStatus, adgroupName, sceneSpec, autoDerivedCreativeEnabled, sysWechatAppId, wxGameAppId, promoteApplicationId, rtaId, rtaTargetId, bidAllocationMode,
  25. bidAmountMin, bidAmountMax, smartDeliveryPlatform, smartDeliverySceneSpec
  26. } = adgroups
  27. const [newVisible, setNewVisible] = useState<boolean>(false)
  28. /*****************************/
  29. // 智能投放出价
  30. const smartModel = useMemo(() => {
  31. if (deliveryMethod === 'SMART') {
  32. const goalDto = SMART_DELIVERY_GOAL_ENUM[smartDeliverySceneSpec?.smartDeliveryGoal as keyof typeof SMART_DELIVERY_GOAL_ENUM]
  33. if ([2, 3].includes(bidAllocationMode)) {
  34. const data = smartDeliverySceneSpec?.smartDeliveryGoalSpec?.[goalDto?.smartDeliveryGoalSpecName]
  35. 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>)
  36. } else {
  37. 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>)
  38. }
  39. }
  40. return null
  41. }, [smartDeliverySceneSpec, deliveryMethod, bidAllocationMode])
  42. return <>
  43. <div className={`${style.settingsBody_content_row} ${style.row1}`}>
  44. <div className={style.title}>
  45. <span>广告信息</span>
  46. </div>
  47. <div className={style.detail}>
  48. <div className={style.detail_body}>
  49. {(adgroups && Object.keys(adgroups).length > 0) ? <>
  50. <p style={{ fontWeight: 'bold', color: configuredStatus === 'AD_STATUS_NORMAL' ? '#52c41a' : '#FF4D4F' }}>广告状态:{AD_STATUS_ENUM[configuredStatus as keyof typeof AD_STATUS_ENUM]}</p>
  51. <p style={{ fontWeight: 'bold', color: '#000' }}>投放方式:{deliveryMethod === 'SMART' ? '智能投放' : '常规投放'}</p>
  52. {deliveryMethod === 'NORMAL' ? <>
  53. {putInType === 'NOVEL' ? <>
  54. <p>营销目的:{MARKETING_GOAL_ENUM[marketingGoal as keyof typeof MARKETING_GOAL_ENUM]}</p>
  55. <p style={{ fontWeight: 'bold', color: '#000' }}>推广产品类型:{MARKETING_TARGET_TYPE_ENUM[marketingAssetOuterSpec?.marketingTargetType as keyof typeof MARKETING_TARGET_TYPE_ENUM]}</p>
  56. </> : <>
  57. <p>营销目的:{MARKETING_SUB_GOAL_ENUM[marketingSubGoal as keyof typeof MARKETING_SUB_GOAL_ENUM]}</p>
  58. <p style={{ fontWeight: 'bold', color: '#000' }}>推广产品类型:{MARKETING_TARGET_TYPE_GAME_ENUM[marketingAssetOuterSpec?.marketingTargetType as keyof typeof MARKETING_TARGET_TYPE_GAME_ENUM]}</p>
  59. </>}
  60. {marketingAssetOuterSpec?.marketingTargetType === 'MARKETING_TARGET_TYPE_MINI_PROGRAM_WECHAT' ?
  61. <ShowMiniProgramWechatDetail id={sysWechatAppId} /> :
  62. marketingAssetOuterSpec?.marketingTargetType === 'MARKETING_TARGET_TYPE_WECHAT_MINI_GAME' ?
  63. <ShowGameAppIdDetail appId={wxGameAppId} /> :
  64. null
  65. }
  66. <p>营销载体类型:{MARKETING_CARRIER_TYPE_ENUM[marketingCarrierType as keyof typeof MARKETING_CARRIER_TYPE_ENUM]}</p>
  67. {['MARKETING_CARRIER_TYPE_APP_ANDROID', 'MARKETING_CARRIER_TYPE_APP_IOS'].includes(marketingCarrierType) && <ShowApplication id={promoteApplicationId} />}
  68. <p>版位选择:{automaticSiteEnabled ? '智能版位' : '选择特定版位'}</p>
  69. {!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>}
  70. {automaticSiteEnabled && <>
  71. <p>探索策略:{explorationStrategy === 'STEADY_EXPLORATION' ? '稳步探索' : '自动探索'}</p>
  72. {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>}
  73. </>}
  74. <p>搜索场景扩量:{searchExpandTargetingSwitch === 'SEARCH_EXPAND_TARGETING_SWITCH_OPEN' ? '开启' : '关闭'}</p>
  75. {rtaId && <p>RTA ID:{rtaId}</p>}
  76. {rtaTargetId && <p>策略 ID:{rtaTargetId}</p>}
  77. <p>计费方式:{BID_MODE_ENUM[bidMode as keyof typeof BID_MODE_ENUM]}</p>
  78. {putInType === 'GAME' ? <>
  79. <p>出价场景:{BID_SCENE_NORMAL_ENUM[bidScene as keyof typeof BID_SCENE_NORMAL_ENUM]}</p>
  80. </> : <p>出价类型:{SMART_BID_TYPE_ENUM[smartBidType as keyof typeof SMART_BID_TYPE_ENUM]}</p>}
  81. <p style={{ fontWeight: 'bold', color: '#000' }}>出价分配方式:{BID_ALL_OCATION_MODE.find(item => item.value === bidAllocationMode)?.label}</p>
  82. {[2, 3].includes(bidAllocationMode)
  83. ?
  84. <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>
  85. :
  86. <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>
  87. }
  88. {isConversion && <p style={{ fontWeight: 'bold', color: '#000' }}>转化:新链路转化</p>}
  89. {optimizationGoal && <p style={{ fontWeight: 'bold', color: '#000' }}>优化目标:{OPTIMIZATIONGOAL_ENUM[optimizationGoal as keyof typeof OPTIMIZATIONGOAL_ENUM]}</p>}
  90. {deepConversionSpec && <>
  91. <p style={{ fontWeight: 'bold', color: '#000' }}>深度转化优化:开启</p>
  92. <p style={{ fontWeight: 'bold', color: '#000' }}>深度优化类型:{DEEP_CONVERSION_ENUM[deepConversionSpec?.deepConversionType as keyof typeof DEEP_CONVERSION_ENUM]}</p>
  93. {deepConversionSpec.deepConversionType === 'DEEP_CONVERSION_BEHAVIOR' ? <>
  94. <p style={{ fontWeight: 'bold', color: '#000' }}>深度优化目标:{OPTIMIZATIONGOAL_ENUM[deepConversionSpec.deepConversionBehaviorSpec.goal as keyof typeof OPTIMIZATIONGOAL_ENUM]}</p>
  95. <p style={{ fontWeight: 'bold', color: '#000' }}>深度目标出价:{deepConversionSpec.deepConversionBehaviorSpec.bidAmount}元/{OPTIMIZATIONGOAL_ENUM[deepConversionSpec.deepConversionBehaviorSpec.goal as keyof typeof OPTIMIZATIONGOAL_ENUM] || '优化目标'}</p>
  96. </> : <>
  97. <p style={{ fontWeight: 'bold', color: '#000' }}>深度优化目标:{GOAL_ROAS_ENUM[deepConversionSpec.deepConversionWorthSpec.goal as keyof typeof GOAL_ROAS_ENUM]}</p>
  98. <p style={{ fontWeight: 'bold', color: '#000' }}>ROI分配方式:{ROI_ALL_OCATION_MODE.find(item => item.value === deepConversionSpec?.deepConversionWorthSpec?.roiAllocationMode)?.label}</p>
  99. {[2, 3].includes(deepConversionSpec?.deepConversionWorthSpec?.roiAllocationMode)
  100. ?
  101. <p style={{ fontWeight: 'bold', color: '#000' }}>期望ROI:{deepConversionSpec.deepConversionWorthSpec.expectedRoiMin}-{deepConversionSpec.deepConversionWorthSpec.expectedRoiMax}</p>
  102. :
  103. <p style={{ fontWeight: 'bold', color: '#000' }}>期望ROI:{deepConversionSpec.deepConversionWorthSpec.expectedRoi}</p>
  104. }
  105. </>}
  106. </>}
  107. <p>一方人群跑量加强:{ecomPkamSwitch === 'ECOM_PKAM_SWITCH_OPEN' ? '开启' : '关闭'}</p>
  108. <p>一键起量:{autoAcquisitionEnabled ? '开启' : '关闭'}</p>
  109. {autoAcquisitionEnabled && <p>起量预算:{autoAcquisitionBudget}元/天</p>}
  110. <p>广告日预算:{dailyBudget ? dailyBudget + '元/天' : '不限'}</p>
  111. <p style={{ fontWeight: 'bold', color: '#000' }}>投放日期:{beginDate} 至 {endDate || '长期投放'}</p>
  112. <p>投放时段:{timeSeries.includes('0') ? <TimeSeriesLook timeSeries={timeSeries} /> : '全天'}</p>
  113. <p>首日开始时间:{firstDayBeginTime ? firstDayBeginTime : '关闭'}</p>
  114. <p>自动衍生创意:{autoDerivedCreativeEnabled ? '系统衍生' : '关闭衍生'}</p>
  115. <p>广告名称:{adgroupName}</p>
  116. </> : <>
  117. {/* 智能投放 */}
  118. <p style={{ fontWeight: 'bold', color: '#000' }}>投放场景:{SMART_DELIVERY_PLATFORM_ENUM[smartDeliveryPlatform as keyof typeof SMART_DELIVERY_PLATFORM_ENUM]}</p>
  119. {putInType === 'NOVEL' ? <>
  120. <p>营销目的:{MARKETING_GOAL_ENUM[marketingGoal as keyof typeof MARKETING_GOAL_ENUM]}</p>
  121. <p style={{ fontWeight: 'bold', color: '#000' }}>推广产品类型:{MARKETING_TARGET_TYPE_ENUM[marketingAssetOuterSpec?.marketingTargetType as keyof typeof MARKETING_TARGET_TYPE_ENUM]}</p>
  122. </> : <>
  123. <p>营销目的:{MARKETING_SUB_GOAL_ENUM[marketingSubGoal as keyof typeof MARKETING_SUB_GOAL_ENUM]}</p>
  124. <p style={{ fontWeight: 'bold', color: '#000' }}>推广产品类型:{MARKETING_TARGET_TYPE_GAME_ENUM[marketingAssetOuterSpec?.marketingTargetType as keyof typeof MARKETING_TARGET_TYPE_GAME_ENUM]}</p>
  125. </>}
  126. {marketingAssetOuterSpec?.marketingTargetType === 'MARKETING_TARGET_TYPE_MINI_PROGRAM_WECHAT' ?
  127. <ShowMiniProgramWechatDetail id={sysWechatAppId} /> :
  128. marketingAssetOuterSpec?.marketingTargetType === 'MARKETING_TARGET_TYPE_WECHAT_MINI_GAME' ?
  129. <ShowGameAppIdDetail appId={wxGameAppId} /> :
  130. null
  131. }
  132. <p>营销载体类型:{MARKETING_CARRIER_TYPE_ENUM[marketingCarrierType as keyof typeof MARKETING_CARRIER_TYPE_ENUM]}</p>
  133. {['MARKETING_CARRIER_TYPE_APP_ANDROID', 'MARKETING_CARRIER_TYPE_APP_IOS'].includes(marketingCarrierType) && <ShowApplication id={promoteApplicationId} />}
  134. <p>版位选择:{automaticSiteEnabled ? '智能版位' : '选择特定版位'}</p>
  135. {automaticSiteEnabled && <>
  136. <p>探索策略:{explorationStrategy === 'STEADY_EXPLORATION' ? '稳步探索' : '自动探索'}</p>
  137. </>}
  138. <p>搜索场景扩量:{searchExpandTargetingSwitch === 'SEARCH_EXPAND_TARGETING_SWITCH_OPEN' ? '开启' : '关闭'}</p>
  139. <p>计费方式:{BID_MODE_ENUM[bidMode as keyof typeof BID_MODE_ENUM]}</p>
  140. {smartDeliverySceneSpec?.smartDeliveryGoal && <p style={{ fontWeight: 'bold', color: '#000' }}>投放目标:{SMART_DELIVERY_GOAL_ENUM[smartDeliverySceneSpec?.smartDeliveryGoal as keyof typeof SMART_DELIVERY_GOAL_ENUM]?.title}</p>}
  141. <p style={{ fontWeight: 'bold', color: '#000' }}>出价分配方式:{BID_ALL_OCATION_MODE.find(item => item.value === bidAllocationMode)?.label}</p>
  142. {smartModel}
  143. {isConversion && <p style={{ fontWeight: 'bold', color: '#000' }}>转化:新链路转化</p>}
  144. <p>广告日预算:{dailyBudget ? dailyBudget + '元/天' : '不限'}</p>
  145. <p style={{ fontWeight: 'bold', color: '#000' }}>投放日期:{beginDate} 至 {endDate || '长期投放'}</p>
  146. <p>投放时段:{timeSeries.includes('0') ? <TimeSeriesLook timeSeries={timeSeries} /> : '全天'}</p>
  147. <p>首日开始时间:{firstDayBeginTime ? firstDayBeginTime : '关闭'}</p>
  148. <p>广告名称:{adgroupName}</p>
  149. </>}
  150. </> : <div className={style.ad_config}>
  151. {accountCreateLogs?.length > 0 ?
  152. <div className={style.ad_config_item} onClick={() => setNewVisible(true)}>新建广告</div>
  153. :
  154. <div className={style.ad_config_item} style={{ backgroundColor: '#FFF' }}>请完善媒体账户信息</div>
  155. }
  156. </div>}
  157. </div>
  158. <div className={style.detail_footer}>
  159. {(adgroups && Object.keys(adgroups).length > 0) ? <>
  160. <Button type="link" icon={<EditOutlined />} style={{ padding: 0, fontSize: 12 }} onClick={() => setNewVisible(true)}>编辑</Button>
  161. </> : <></>}
  162. </div>
  163. </div>
  164. </div>
  165. {/* 新建广告 */}
  166. {newVisible && <NewCreateAd
  167. accountIdList={accountCreateLogs.map(item => item.accountId)}
  168. putInType={putInType}
  169. value={addelivery.adgroups}
  170. visible={newVisible}
  171. onClose={() => {
  172. setNewVisible(false)
  173. }}
  174. onChange={(adgroups) => {
  175. setIsDqSubmit?.(false)
  176. if (
  177. adgroups.marketingGoal === marketingGoal && // 营销内容
  178. adgroups.marketingCarrierType === marketingCarrierType && // 营销载体
  179. adgroups.marketingAssetOuterSpec.marketingTargetType === marketingAssetOuterSpec.marketingTargetType && // 推广产品
  180. adgroups.automaticSiteEnabled === automaticSiteEnabled && // 版位选择
  181. arraysHaveSameValues(adgroups?.siteSet || [], siteSet || []) && // 版位
  182. arraysHaveSameValues(adgroups?.sceneSpec?.wechatPosition || [], sceneSpec?.wechatPosition || []) // 微信公众号与小程序定投
  183. ) {
  184. if (adgroups?.isConversion !== isConversion || ((isConversion || adgroups?.isConversion) && adgroups?.depthConversionEnabled !== depthConversionEnabled)) {
  185. setAccountCreateLogs(accountCreateLogs.map(item => {
  186. delete item?.newConversionList
  187. delete item?.userActionSetsList
  188. return item
  189. }))
  190. }
  191. setNewVisible(false)
  192. setAddelivery({ ...addelivery, adgroups })
  193. clearData()
  194. } else {
  195. setAccountCreateLogs(accountCreateLogs.map(item => ({ accountId: item.accountId })))
  196. if (
  197. addelivery?.adgroups && Object.keys(addelivery?.adgroups).length &&
  198. ((addelivery?.dynamic && Object.keys(addelivery?.dynamic).length)
  199. || addelivery?.targeting?.length
  200. || (addelivery?.dynamicMaterialDTos && Object.keys(addelivery?.dynamicMaterialDTos).length)
  201. || (addelivery?.dynamicCreativesTextDTOS && Object.keys(addelivery?.dynamicCreativesTextDTOS).length)
  202. )
  203. ) {
  204. Modal.confirm({
  205. title: <strong style={{ color: '#FAAD14' }}>注意</strong>,
  206. content: <span>当前改变了“营销内容”、“营销载体”、“推广产品”、“版位选择”、“版位”、“微信公众号与小程序定投”中的某些内容,不清空后面内容可能会导致当前“定向”、“创意”、“素材”等一些内容不匹配,<span style={{ color: 'red' }}>是否清空内容</span></span>,
  207. okText: '清空',
  208. cancelText: '不清空',
  209. keyboard: false,
  210. onOk() { // 清空
  211. setNewVisible(false)
  212. setAddelivery({ adgroups, targeting: [], dynamic: {}, dynamicMaterialDTos: {}, dynamicCreativesTextDTOS: {}, mediaType: 0 })
  213. clearData()
  214. },
  215. onCancel() { // 不清空
  216. setNewVisible(false)
  217. setAddelivery({ ...addelivery, adgroups })
  218. clearData()
  219. },
  220. className: 'modalResetCss'
  221. })
  222. } else {
  223. setNewVisible(false)
  224. setAddelivery({ adgroups, targeting: [], dynamic: {}, dynamicMaterialDTos: {}, dynamicCreativesTextDTOS: {}, mediaType: 0 })
  225. clearData()
  226. }
  227. }
  228. }}
  229. />}
  230. </>
  231. }
  232. export default React.memo(Ad)