wechat.tsx 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636
  1. import React, { useCallback, useEffect, useState } from 'react'
  2. import { Modal, Form, Input, Divider, Select, Radio, DatePicker, Switch, Checkbox, message, Tooltip, Row, Col, Space, TimePicker, Button } from 'antd'
  3. import { BidModeEnum, OptimizationGoalEnum, BidStrategyEnum, AdStatus, GoalRoasEnum } from '@/services/launchAdq/enum'
  4. import { ModalConfig } from '../index'
  5. import moment from 'moment';
  6. import { useAjax } from '@/Hook/useAjax';
  7. import { getSceneTagsList } from '@/services/launchAdq/global';
  8. import { ExclamationCircleOutlined } from '@ant-design/icons';
  9. import { CreateAdProps } from '@/services/launchAdq/createAd';
  10. import { createSysAdgroups } from '@/services/launchAdq/localAd';
  11. import AdPositionList from './adPositionList';
  12. import { SiteSetPackageDataProps } from './leadAd';
  13. import BidAdjustment from './bidAdjustment';
  14. import { useModel } from 'umi';
  15. const { RangePicker }: { RangePicker: any } = DatePicker;
  16. let DatePickers: any = DatePicker
  17. interface Props {
  18. queryForm: Partial<CreateAdProps>,
  19. visible: boolean,
  20. PupFn: (arg: ModalConfig) => void,
  21. callback: (params: any) => void,
  22. confirmLoading?: boolean,
  23. type?: 'add' | 'look' | 'edit',//新增,查看,编辑
  24. dataInfo?: any,
  25. ajax: any
  26. }
  27. /**微信公众号广告弹窗*/
  28. function WeChatAdModal(props: Props) {
  29. /*******************************/
  30. let { visible, confirmLoading, PupFn, callback, type, dataInfo, queryForm, ajax } = props
  31. const { currentUser }: any = useModel('@@initialState', model => ({ currentUser: model.initialState?.currentUser }))
  32. const createSysAdgroup = useAjax((params) => createSysAdgroups(params))
  33. let [state, setState] = useState<any>({ isShowTime: [] })
  34. let [template_checked, settemplate_checked] = useState<boolean>(dataInfo?.isTemplate || false)
  35. let arg = type === 'look' ? { footer: null } : {}
  36. const sceneTagsList = useAjax((params) => getSceneTagsList(params))
  37. const [form] = Form.useForm();
  38. let dateType = Form.useWatch('dateType', form)
  39. let bidMode = Form.useWatch('bidMode', form)
  40. let smartBidType = Form.useWatch('smartBidType', form)
  41. let autoAcquisitionEnabled = Form.useWatch('autoAcquisitionEnabled', form)
  42. let siteSet = Form.useWatch('siteSet', form)
  43. let wechatPositionType = Form.useWatch('wechatPositionType', form)
  44. let wechatSceneType = Form.useWatch('wechatSceneType', form)
  45. let automaticSiteEnabled = Form.useWatch('automaticSiteEnabled', form)
  46. let optimizationGoal = Form.useWatch('optimizationGoal', form)
  47. let depthConversionEnabled = Form.useWatch('depthConversionEnabled', form)
  48. let deepConversionType = Form.useWatch('deepConversionType', form)
  49. let goal = Form.useWatch('goal', form)
  50. let bidAdjustmentEnabled = Form.useWatch('bidAdjustmentEnabled', form)
  51. let siteSetPackage = Form.useWatch('siteSetPackage', form)
  52. let deepBidAmount = Form.useWatch('deepBidAmount', form)
  53. let bidAmountAdjustmentEnabled = Form.useWatch('bidAmountAdjustmentEnabled', form)
  54. let bidAmount = Form.useWatch('bidAmount', form)
  55. const [behaviorList, setBehaviorList] = useState<string[]>([])
  56. const [worthList, setWorthList] = useState<string[]>([])
  57. /*******************************/
  58. // 确定事件
  59. const handleOk = useCallback(() => {
  60. form.validateFields().then(values => {
  61. let newValues = JSON.parse(JSON.stringify(values))
  62. newValues.sceneSpec = {}
  63. if (newValues.dateType === '2') {
  64. newValues['beginDate'] = moment(newValues.date).format('YYYY-MM-DD')
  65. } else {
  66. newValues['beginDate'] = moment(newValues.date[0]).format('YYYY-MM-DD')
  67. newValues['endDate'] = moment(newValues.date[1]).format('YYYY-MM-DD')
  68. }
  69. if (newValues.firstDayBeginTime) {
  70. newValues['firstDayBeginTime'] = moment(newValues.firstDayBeginTime).format('HH:mm:ss')
  71. }
  72. Object.keys(newValues).forEach(key => {
  73. switch (key) {
  74. case 'wechatPositionType':
  75. if (newValues[key] === '1') {
  76. newValues.sceneSpec = { ...newValues.sceneSpec, wechatPosition: newValues.wechatPosition }
  77. }
  78. break;
  79. case 'wechatSceneType':
  80. if (newValues[key] === '1') {
  81. newValues.sceneSpec = {
  82. ...newValues.sceneSpec, wechatScene: {
  83. officialAccountMediaCategory: newValues.officialAccountMediaCategory,
  84. miniProgramAndMiniGame: newValues.miniProgramAndMiniGame,
  85. payScene: newValues.payScene
  86. }
  87. }
  88. }
  89. break;
  90. case 'siteSetPackage': // 处理分版位出价
  91. if (newValues[key]?.length > 0) {
  92. let newSiteSetPackage: SiteSetPackageDataProps[] = JSON.parse(JSON.stringify(newValues[key]))
  93. if (!newValues?.bidAmountAdjustmentEnabled) {
  94. newSiteSetPackage = newSiteSetPackage.map(item => {
  95. let { bidCoefficient, ...newItem } = item
  96. return { ...newItem }
  97. })
  98. }
  99. if (!newValues?.bidAdjustmentEnabled) {
  100. newSiteSetPackage = newSiteSetPackage.map(item => {
  101. let { deepBidCoefficient, ...newItem } = item
  102. return { ...newItem }
  103. })
  104. }
  105. newValues.bidAdjustment = {
  106. siteSetPackage: newSiteSetPackage
  107. }
  108. delete newValues.siteSetPackage
  109. }
  110. break
  111. case 'deepConversionType': // 处理深度优化
  112. let deepConversionSpec: any = {
  113. deepConversionType: newValues[key]
  114. }
  115. if (newValues[key] === 'DEEP_CONVERSION_WORTH') { // 优化 ROI
  116. deepConversionSpec.deepConversionWorthSpec = {
  117. goal: newValues.goal,
  118. expectedRoi: newValues.deepBidAmount
  119. }
  120. } else if (newValues[key] === 'DEEP_CONVERSION_BEHAVIOR') { // 优化转化行为
  121. deepConversionSpec.deepConversionBehaviorSpec = {
  122. goal: newValues.goal,
  123. bidAmount: newValues.deepBidAmount * 100
  124. }
  125. }
  126. newValues.deepConversionSpec = deepConversionSpec
  127. delete newValues.deepBidAmount
  128. delete newValues.goal
  129. delete newValues.optimizationMode
  130. delete newValues.deepConversionType
  131. delete newValues.depthConversionEnabled
  132. break
  133. }
  134. })
  135. if (newValues.sceneSpec.wechatPosition?.length === 0) {
  136. delete newValues.sceneSpec.wechatPosition
  137. }
  138. if (newValues.sceneSpec.wechatScene) {
  139. newValues.sceneSpec.wechatScene.officialAccountMediaCategory?.length === 0 && (delete newValues.sceneSpec.wechatScene.officialAccountMediaCategory)
  140. newValues.sceneSpec.wechatScene.miniProgramAndMiniGame?.length === 0 && (delete newValues.sceneSpec.wechatScene.miniProgramAndMiniGame)
  141. newValues.sceneSpec.wechatScene.payScene?.length === 0 && (delete newValues.sceneSpec.wechatScene.payScene)
  142. }
  143. if (!newValues.sceneSpec.wechatPosition && !newValues.sceneSpec.wechatScene) {
  144. delete newValues.sceneSpec
  145. }
  146. delete newValues.officialAccountMediaCategory
  147. delete newValues.miniProgramAndMiniGame
  148. delete newValues?.bidAmountAdjustmentEnabled
  149. delete newValues?.bidAdjustmentEnabled
  150. delete newValues.payScene
  151. delete newValues.wechatPositionType
  152. delete newValues.wechatPosition
  153. delete newValues.wechatScene
  154. delete newValues['dateType']
  155. delete newValues['date']
  156. newValues['timeSeries'] = Array(336).fill(1).join('')
  157. newValues['promotedObjectType'] = queryForm.promotedObjectType
  158. newValues['isTemplate'] = template_checked
  159. console.log(newValues)
  160. // 开启存为模板开关执行
  161. // if (template_checked && type === 'add') {
  162. // createSysAdgroup.run(newValues).then(res => {
  163. // if (res) {
  164. // callback(newValues)
  165. // }
  166. // })
  167. // } else {
  168. callback(newValues)
  169. // }
  170. })
  171. }, [form, template_checked, queryForm, type])
  172. // 场景定向
  173. useEffect(() => {
  174. sceneTagsList.run({ typeList: ['WECHAT_POSITION', 'OFFICIAL_ACCOUNT_MEDIA_CATEGORY', 'MINI_PROGRAM_AND_MINI_GAME', 'PAY_SCENE'] })
  175. }, [])
  176. // 数据回填
  177. useEffect(() => {
  178. if (dataInfo) {
  179. let formData: any = {
  180. adgroupName: dataInfo?.adgroupName,//广告名称
  181. promotedObjectType: dataInfo?.promotedObjectType,//推广目标
  182. siteSet: dataInfo?.siteSet,//广告版位
  183. autoAcquisitionEnabled: dataInfo?.autoAcquisitionEnabled,//一键起量
  184. bidAmount: dataInfo?.bidAmount,//出价
  185. smartBidType: dataInfo?.smartBidType,//出价类型
  186. bidStrategy: dataInfo?.bidStrategy,//出价策略
  187. bidMode: dataInfo?.bidMode,//出价方式
  188. optimizationGoal: dataInfo?.optimizationGoal,//优化目标
  189. dateType: dataInfo?.endDate ? '1' : '2',//投放日期
  190. dailyBudget: dataInfo?.dailyBudget,//广告日预算
  191. date: dataInfo?.endDate ? [moment(dataInfo?.beginDate), moment(dataInfo?.endDate)] : moment(dataInfo?.beginDate),//日期
  192. autoAcquisitionBudget: dataInfo?.autoAcquisitionBudget,//起量预算
  193. wechatPositionType: dataInfo?.sceneSpec?.wechatPosition ? '1' : '0',//微信公众号与小程序定投
  194. wechatPosition: dataInfo?.sceneSpec?.wechatPosition,//微信公众号与小程序定投
  195. wechatSceneType: dataInfo?.sceneSpec?.wechatScene?.officialAccountMediaCategory || dataInfo?.sceneSpec?.wechatScene?.miniProgramAndMiniGame || dataInfo?.sceneSpec?.wechatScene?.payScene ? '1' : '0',//微信公众号与小程序场景
  196. officialAccountMediaCategory: dataInfo?.sceneSpec?.wechatScene?.officialAccountMediaCategory,//公众号媒体类型
  197. miniProgramAndMiniGame: dataInfo?.sceneSpec?.wechatScene?.miniProgramAndMiniGame,//小程序小游戏流量类型
  198. payScene: dataInfo?.sceneSpec?.wechatScene?.payScene,//订单详情页消费场景
  199. firstDayBeginTime: dataInfo?.firstDayBeginTime ? moment(`${dataInfo?.beginDate} ${dataInfo?.firstDayBeginTime}`) : undefined,//首日开始时间
  200. configuredStatus: dataInfo?.configuredStatus || 'AD_STATUS_SUSPEND',//广告启停
  201. }
  202. Object.keys(dataInfo).forEach(key => {
  203. switch (key) {
  204. case 'bidAdjustment': // 处理分版位出价
  205. if (dataInfo[key]?.siteSetPackage && dataInfo[key]?.siteSetPackage?.length > 0) {
  206. let siteSetPackage: SiteSetPackageDataProps[] = dataInfo[key].siteSetPackage
  207. if (siteSetPackage.some(item => item.bidCoefficient)) { // 判断出价是否开启了分版位
  208. formData.bidAmountAdjustmentEnabled = true
  209. } else {
  210. siteSetPackage = siteSetPackage.map(item => ({ ...item, bidCoefficient: 1 }))
  211. }
  212. if (siteSetPackage.some(item => item.deepBidCoefficient)) { // 判断深度出价是否开启了分版位
  213. formData.bidAdjustmentEnabled = true
  214. } else {
  215. siteSetPackage = siteSetPackage.map(item => ({ ...item, deepBidCoefficient: 1 }))
  216. }
  217. formData.siteSetPackage = siteSetPackage
  218. }
  219. break
  220. case 'deepConversionSpec': // 处理深度优化
  221. if (dataInfo[key]?.deepConversionType === 'DEEP_CONVERSION_WORTH') {
  222. formData = {
  223. ...formData,
  224. optimizationMode: 'DEEP_CONVERSION_TARGET',
  225. depthConversionEnabled: true,
  226. deepConversionType: dataInfo[key]?.deepConversionType,
  227. goal: dataInfo[key]?.deepConversionWorthSpec?.goal,
  228. deepBidAmount: dataInfo[key]?.deepConversionWorthSpec?.expectedRoi,
  229. }
  230. } else if (dataInfo[key]?.deepConversionType === 'DEEP_CONVERSION_BEHAVIOR') {
  231. formData = {
  232. ...formData,
  233. optimizationMode: 'DEEP_CONVERSION_TARGET',
  234. depthConversionEnabled: true,
  235. deepConversionType: dataInfo[key]?.deepConversionType,
  236. goal: dataInfo[key]?.deepConversionBehaviorSpec?.goal,
  237. deepBidAmount: dataInfo[key]?.deepConversionBehaviorSpec?.bidAmount / 100,
  238. }
  239. }
  240. break
  241. }
  242. })
  243. form.setFieldsValue(formData)
  244. if (dataInfo?.firstDayBeginTime) {//存在首日开始时间,选中开关
  245. setState({ ...state, isShowTime: ['1'] })
  246. }
  247. } else {
  248. form.setFieldsValue({
  249. adgroupName: '广告_微信朋友圈_' + moment().format('YYYYMMDDhhmmss') + '_' + currentUser.userId,
  250. date: moment().startOf('day').add(4, 'M'),
  251. optimizationGoal: "OPTIMIZATIONGOAL_ECOMMERCE_ORDER",
  252. bidStrategy: "BID_STRATEGY_TARGET_COST",
  253. bidAmount: '1000'
  254. })
  255. }
  256. }, [dataInfo])
  257. // 出价方式改变清空某些数据
  258. const bidModeChange = useCallback((props) => {
  259. form.setFieldsValue({
  260. ...props,
  261. optimizationGoal: null,
  262. smartBidType: null,
  263. // bidAmount:null,
  264. bidStrategy: null,
  265. autoAcquisitionEnabled: false,
  266. autoAcquisitionBudget: null,
  267. dailyBudget: null,
  268. })
  269. }, [])
  270. // 出价和版位改变时查询
  271. useEffect(() => {
  272. if (bidMode && siteSet && siteSet?.length > 0) {
  273. let obj: any = { siteSet, promotedObjectType: queryForm.promotedObjectType }
  274. if (bidMode === 'BID_MODE_OCPC' || bidMode === 'BID_MODE_OCPM') {
  275. obj = { ...obj, bidMode }
  276. }
  277. ajax.run(obj).then((res: any) => {
  278. console.log(res)
  279. })
  280. }
  281. }, [bidMode, siteSet])
  282. // 处理深度转化优化
  283. useEffect(() => {
  284. if (optimizationGoal && ajax?.data) {
  285. let { deepBehaviorOptimizationGoalPermissionList, deepWorthOptimizationGoalPermissionList } = ajax?.data
  286. // deepBehaviorOptimizationGoalPermissionList 优化转化行为
  287. // deepWorthOptimizationGoalPermissionList 优化ROI
  288. let behavior = deepBehaviorOptimizationGoalPermissionList?.find((item: { optimizationGoal: string }) => item.optimizationGoal === optimizationGoal)
  289. let worth = deepWorthOptimizationGoalPermissionList?.find((item: { optimizationGoal: string }) => item.optimizationGoal === optimizationGoal)
  290. setBehaviorList(behavior?.deepBehaviorOptimizationGoalList || [])
  291. setWorthList(worth?.deepWorthOptimizationGoalList || [])
  292. }
  293. }, [optimizationGoal, ajax?.data])
  294. /**处理分版位数据 */
  295. const setSiteSetHandle = (siteSet: string[]) => {
  296. let data: SiteSetPackageDataProps[] = []
  297. if (siteSet && siteSet?.length > 0) {
  298. data = siteSet?.map((item: string) => ({ siteSet: [item], bidCoefficient: 1, deepBidCoefficient: 1 }))
  299. } else {
  300. data = []
  301. }
  302. form.setFieldsValue({
  303. siteSetPackage: data
  304. })
  305. }
  306. return <Modal
  307. visible={visible}
  308. title={type === 'add' ? '新建广告' : type === 'look' ? '广告详情' : '编辑广告'}
  309. onCancel={() => { PupFn({ visible: false, dataInfo: null, type: 'add' }) }}
  310. width={900}
  311. confirmLoading={createSysAdgroup?.loading}
  312. footer={<Space>
  313. <Button onClick={() => { PupFn({ visible: false, dataInfo: null, type: 'add' }) }}>取消</Button>
  314. <Button type='primary' onClick={handleOk}>确定</Button>
  315. {<Checkbox checked={template_checked} onChange={(e) => {
  316. let checked = e.target.checked
  317. settemplate_checked(checked)
  318. }}>存为模板</Checkbox>}
  319. </Space>}
  320. {...arg}
  321. >
  322. <Form
  323. form={form}
  324. labelCol={{ span: 5 }}
  325. className='ad_form_style'
  326. initialValues={
  327. {
  328. promotedObjectType: queryForm.promotedObjectType,
  329. siteSet: ['SITE_SET_MOMENTS', 'SITE_SET_WECHAT'],
  330. bidMode: 'BID_MODE_OCPM',
  331. automaticSiteEnabled: false,
  332. dateType: '2',
  333. bidStrategy: 'BID_STRATEGY_AVERAGE_COST',
  334. timeSeries: '1',
  335. smartBidType: 'SMART_BID_TYPE_CUSTOM',
  336. autoAcquisitionEnabled: false,
  337. wechatSceneType: '0',
  338. wechatPositionType: '0',
  339. // optimizationGoal: 'OPTIMIZATIONGOAL_ECOMMERCE_ORDER',
  340. configuredStatus: 'AD_STATUS_SUSPEND',
  341. optimizationMode: 'DEEP_CONVERSION_TARGET',
  342. siteSetPackage: [{ siteSet: ["SITE_SET_MOMENTS"], bidCoefficient: 1, deepBidCoefficient: 1 }, { siteSet: ["SITE_SET_WECHAT"], bidCoefficient: 1, deepBidCoefficient: 1 }]
  343. }
  344. }
  345. >
  346. {/* ============================================================基本信息============================================================= */}
  347. <Divider orientation='center'>基本信息</Divider>
  348. <Form.Item label={<strong>广告名称</strong>} name='adgroupName' rules={[{ required: true, message: '请输入广告名称!' }]}>
  349. <Input placeholder='广告名称' style={{ width: 300 }} />
  350. </Form.Item>
  351. <Form.Item label={<strong>广告版位</strong>}>
  352. <Form.Item name='automaticSiteEnabled'>
  353. <Radio.Group buttonStyle="solid">
  354. <Radio.Button value={true} disabled={queryForm.promotedObjectType === 'PROMOTED_OBJECT_TYPE_WECHAT_OFFICIAL_ACCOUNT'}>自动版位</Radio.Button>
  355. <Radio.Button value={false}>选择特定版位</Radio.Button>
  356. </Radio.Group>
  357. </Form.Item>
  358. {!automaticSiteEnabled && <Form.Item name='siteSet' noStyle rules={[{ required: true, message: '请输入选择广告版位!' }]}>
  359. <Checkbox.Group style={{ width: '100%' }} onChange={(e) => { bidModeChange({ bidMode: 'BID_MODE_OCPM' }); setSiteSetHandle(e as string[]) }}>
  360. <Row>
  361. <Col span={5}>
  362. <Checkbox value="SITE_SET_MOMENTS">微信朋友圈</Checkbox>
  363. </Col>
  364. <Col span={6}>
  365. <Checkbox value="SITE_SET_WECHAT">微信公众号与小程序</Checkbox>
  366. </Col>
  367. <Col span={5}>
  368. <Checkbox value="SITE_SET_WECHAT_PLUGIN">微信新闻插件</Checkbox>
  369. </Col>
  370. <Col span={4}>
  371. <Checkbox value="SITE_SET_MOBILE_UNION">优量汇</Checkbox>
  372. </Col>
  373. <Col span={4}>
  374. <Checkbox value="SITE_SET_TENCENT_NEWS">腾讯新闻</Checkbox>
  375. </Col>
  376. <Col span={4}>
  377. <Checkbox value="SITE_SET_TENCENT_VIDEO">腾讯视频</Checkbox>
  378. </Col>
  379. <Col span={4}>
  380. <Checkbox value="SITE_SET_KANDIAN">QQ 浏览器</Checkbox>
  381. </Col>
  382. <Col span={6}>
  383. <Checkbox value="SITE_SET_QQ_MUSIC_GAME">QQ、腾讯音乐及游戏</Checkbox>
  384. </Col>
  385. </Row>
  386. </Checkbox.Group>
  387. </Form.Item>}
  388. </Form.Item>
  389. {
  390. siteSet?.some((s: string) => s === 'SITE_SET_WECHAT') && <>
  391. <Form.Item label={<strong>微信公众号与小程序定投</strong>} name='wechatPositionType' style={wechatPositionType === '1' ? { marginBottom: 5 } : {}}>
  392. <Radio.Group >
  393. <Radio.Button value="0">不限</Radio.Button>
  394. <Radio.Button value="1">自定义</Radio.Button>
  395. </Radio.Group>
  396. </Form.Item>
  397. {wechatPositionType === '1' && <Form.Item style={{ marginLeft: 177 }} name='wechatPosition'>
  398. <Checkbox.Group options={sceneTagsList?.data?.WECHAT_POSITION?.map((item: { description: any; id: any; }) => ({ label: item.description, value: item.id }))} />
  399. </Form.Item>}
  400. <Form.Item label={<strong>微信公众号与小程序场景</strong>} name='wechatSceneType' style={wechatSceneType === '1' ? { marginBottom: 5 } : {}} >
  401. <Radio.Group >
  402. <Radio.Button value="0">不限</Radio.Button>
  403. <Radio.Button value="1">自定义</Radio.Button>
  404. </Radio.Group>
  405. </Form.Item>
  406. {wechatSceneType === '1' && <>
  407. <p style={{ marginBottom: 5, marginLeft: 177 }}><strong style={{ marginRight: 20 }}>公众号媒体类型</strong></p>
  408. <Form.Item style={{ marginLeft: 177 }} name='officialAccountMediaCategory'>
  409. <Checkbox.Group options={sceneTagsList?.data?.OFFICIAL_ACCOUNT_MEDIA_CATEGORY?.filter((i: { description: string; }) => i.description !== '不限')?.map((item: { description: any; id: any; }) => ({ label: item.description, value: item.id }))} />
  410. </Form.Item>
  411. <p style={{ marginBottom: 5, marginLeft: 177 }}><strong style={{ marginRight: 20 }}>小程序小游戏流量类型</strong></p>
  412. <Form.Item style={{ marginLeft: 177 }} name='miniProgramAndMiniGame'>
  413. <Checkbox.Group options={sceneTagsList?.data?.MINI_PROGRAM_AND_MINI_GAME?.filter((i: { description: string; }) => i.description !== '不限')?.map((item: { description: any; id: any; }) => ({ label: item.description, value: item.id }))} />
  414. </Form.Item>
  415. <p style={{ marginBottom: 5, marginLeft: 177 }}><strong style={{ marginRight: 20 }}>订单详情页消费场景</strong></p>
  416. <Form.Item style={{ marginLeft: 177 }} name='payScene'>
  417. <Checkbox.Group options={sceneTagsList?.data?.PAY_SCENE?.filter((i: { description: string; }) => i.description !== '不限')?.map((item: { description: any; id: any; }) => ({ label: item.description, value: item.id }))} />
  418. </Form.Item>
  419. </>}
  420. </>
  421. }
  422. {/* ============================================================排期与出价============================================================= */}
  423. <Divider orientation='center'>排期与出价</Divider>
  424. <Form.Item label={<strong>投放日期</strong>} name='dateType'>
  425. <Radio.Group onChange={(e) => {
  426. if (e.target.value === "1") {
  427. form.setFieldsValue({ date: [moment().startOf('day').add(4, 'M'), moment().startOf('day').add(12, 'M')] })
  428. }
  429. if (e.target.value === "2") {
  430. form.setFieldsValue({ date: moment().startOf('day').add(4, 'M') })
  431. }
  432. }}>
  433. <Radio.Button value="1">选择开始与结束日期</Radio.Button>
  434. <Radio.Button value="2">长期投放</Radio.Button>
  435. </Radio.Group>
  436. </Form.Item>
  437. {/* 投放日期的不同展示不同的日期选择 */}
  438. {
  439. dateType === '1' ? <Form.Item name='date' rules={[{ required: true, message: '请选择日期' }]}>
  440. <RangePicker style={{ marginLeft: 177 }}></RangePicker>
  441. </Form.Item> : <Form.Item name='date' style={{ marginLeft: 177 }} rules={[{ required: true, message: '请选择日期' }]}>
  442. <DatePickers />
  443. </Form.Item>
  444. }
  445. <Form.Item label={<strong>投放时段</strong>}>
  446. <Space>
  447. <Radio.Group name='timeSeries' defaultValue='1'>
  448. <Radio.Button value={'1'}>全天投放</Radio.Button>
  449. </Radio.Group>
  450. <Checkbox.Group options={[{ label: '指定首日开始投放时间', value: '1' }]} onChange={(checkedValue) => {
  451. setState({ ...state, isShowTime: checkedValue })
  452. }
  453. } value={state.isShowTime} />
  454. </Space>
  455. {state?.isShowTime?.length > 0 && <Form.Item name='firstDayBeginTime' noStyle rules={[{ required: true, message: '请选择时间' }]}>
  456. <TimePicker />
  457. </Form.Item>}
  458. </Form.Item>
  459. <Form.Item label={<strong>出价方式<Tooltip title='oCPC/oCPM出价,或开启自动扩量/智能扩量时不支持二方人群'><ExclamationCircleOutlined style={{ color: '#e91e63', marginLeft: 5 }} /></Tooltip></strong>} name='bidMode' rules={[{ required: true, message: '请选择出价方式' }]}>
  460. <Radio.Group onChange={(e) => {
  461. if (e.target.value === "BID_MODE_CPM") {
  462. form.setFieldsValue({
  463. optimizationGoal: null,
  464. smartBidType: null,
  465. // bidAmount:null,
  466. bidStrategy: null,
  467. autoAcquisitionEnabled: false,
  468. autoAcquisitionBudget: null,
  469. dailyBudget: null,
  470. })
  471. } else {
  472. form.setFieldsValue({
  473. optimizationGoal: "OPTIMIZATIONGOAL_ECOMMERCE_ORDER",
  474. smartBidType: "SMART_BID_TYPE_CUSTOM",
  475. bidAmount: '1000',
  476. bidStrategy: "BID_STRATEGY_TARGET_COST",
  477. autoAcquisitionEnabled: false,
  478. autoAcquisitionBudget: null,
  479. dailyBudget: null,
  480. })
  481. }
  482. }}>
  483. {
  484. Object.keys(BidModeEnum).filter(key => { if (siteSet?.some((name: string) => name === "SITE_SET_MOMENTS")) { return key === 'BID_MODE_OCPM' || key === 'BID_MODE_CPM' } else { return true } })?.map(key => {
  485. return <Radio.Button value={key} key={key} >{BidModeEnum[key]}</Radio.Button>
  486. })
  487. }
  488. </Radio.Group>
  489. </Form.Item>
  490. {/* 出价方式为OCPM才展示 */}
  491. {
  492. bidMode === 'BID_MODE_OCPM' && <>
  493. <Form.Item label={<strong>优化目标</strong>} name='optimizationGoal' rules={[{ required: true, message: '请选择优化目标' }]}>
  494. <Select style={{ width: 300 }} showSearch filterOption={(input, option) =>
  495. (option!.children as unknown as string).toLowerCase().includes(input.toLowerCase())
  496. } allowClear>
  497. {
  498. Object.keys(OptimizationGoalEnum).map(key => {
  499. return <Select.Option value={key} key={key}>{OptimizationGoalEnum[key]}</Select.Option>
  500. })
  501. }
  502. </Select>
  503. </Form.Item>
  504. <Form.Item label={<strong>出价类型</strong>} name='smartBidType' rules={[{ required: true, message: '请选择出价类型' }]}>
  505. <Radio.Group >
  506. <Radio.Button value="SMART_BID_TYPE_CUSTOM">手动出价</Radio.Button>
  507. <Radio.Button value="SMART_BID_TYPE_SYSTEMATIC">自动出价</Radio.Button>
  508. </Radio.Group>
  509. </Form.Item>
  510. <Form.Item label={<strong>出价策略</strong>} name='bidStrategy' rules={[{ required: true, message: '请选择出价策略' }]}>
  511. <Radio.Group >
  512. {
  513. Object.keys(BidStrategyEnum).map(key => {
  514. return <Radio.Button value={key} key={key} disabled={smartBidType === 'SMART_BID_TYPE_SYSTEMATIC' && key === 'BID_STRATEGY_PRIORITY_CAP_COST'}> {BidStrategyEnum[key]}</Radio.Button>
  515. })
  516. }
  517. </Radio.Group>
  518. </Form.Item>
  519. </>
  520. }
  521. {/* 出价类型为手动出价才展示 */}
  522. {smartBidType !== 'SMART_BID_TYPE_SYSTEMATIC' && <>
  523. <Form.Item label={<strong>出价</strong>} name='bidAmount' rules={[{ required: true, message: '请输入价格' }]}>
  524. <Input placeholder={`输入价格 元/${bidMode === 'BID_MODE_CPM' ? '千次曝光' : bidMode === 'BID_MODE_CPC' ? '点击' : OptimizationGoalEnum[optimizationGoal]}`} style={{ width: 300 }} />
  525. </Form.Item>
  526. {bidMode === 'BID_MODE_OCPM' && <>
  527. {/* 当版位选择大于1时才出现 */}
  528. {siteSet?.length > 1 && <Form.Item label={<strong>分版位出价</strong>} name='bidAmountAdjustmentEnabled' valuePropName="checked">
  529. <Switch checkedChildren="开启" unCheckedChildren="关闭" />
  530. </Form.Item>}
  531. {bidAmountAdjustmentEnabled && <Form.Item
  532. label={<strong>分版位出价</strong>}
  533. name='siteSetPackage'
  534. rules={[{ required: bidAmountAdjustmentEnabled ? true : false, message: '请设置系数' }]}
  535. >
  536. <BidAdjustment bidAmount={bidAmount} deepConversionType='BID_MODE' goal={goal}>
  537. <AdPositionList value={siteSetPackage} onChange={(data) => {
  538. form.setFieldsValue({
  539. siteSetPackage: data
  540. })
  541. }} />
  542. </BidAdjustment>
  543. </Form.Item>}
  544. <Form.Item label={<strong>一键起量</strong>} name='autoAcquisitionEnabled' valuePropName="checked">
  545. <Switch checkedChildren="开启" unCheckedChildren="关闭" />
  546. </Form.Item>
  547. {/* 一键起量开启时才出现 */}
  548. {autoAcquisitionEnabled && <Form.Item label={<strong>起量预算</strong>} name='autoAcquisitionBudget' rules={[{ required: true, message: '请输入起量预算' }]}>
  549. <Input placeholder='起量预算' style={{ width: 300 }} />
  550. </Form.Item>}
  551. {/* 深度优化 */}
  552. {(behaviorList?.length > 0 || worthList?.length > 0) && <Form.Item label={<strong>深度转化优化</strong>} name='depthConversionEnabled' valuePropName="checked">
  553. <Switch checkedChildren="开启" unCheckedChildren="关闭" onChange={(e) => {
  554. if (e) {
  555. form.setFieldsValue({
  556. optimizationMode: 'DEEP_CONVERSION_TARGET',
  557. deepConversionType: behaviorList?.length > 0 ? 'DEEP_CONVERSION_BEHAVIOR' : worthList?.length > 0 ? 'DEEP_CONVERSION_WORTH' : ''
  558. })
  559. }
  560. }} />
  561. </Form.Item>}
  562. {depthConversionEnabled && <div style={{ backgroundColor: 'rgb(247, 248, 250)', padding: '18px 0 3px', marginBottom: 10, borderRadius: 8 }}>
  563. <Form.Item label={<strong>深度优化方式</strong>} name='optimizationMode' rules={[{ required: true, message: '请选择深度优化方式' }]}>
  564. <Radio.Group>
  565. <Radio.Button value="DEEP_CONVERSION_TARGET">深度目标优化</Radio.Button>
  566. </Radio.Group>
  567. </Form.Item>
  568. <Form.Item label={<strong>深度优化类型</strong>} name='deepConversionType' rules={[{ required: true, message: '请选择深度优化类型' }]}>
  569. <Radio.Group onChange={() => {
  570. form.setFieldsValue({
  571. goal: undefined,
  572. deepBidAmount: undefined
  573. })
  574. }}>
  575. {behaviorList?.length > 0 && <Radio.Button value="DEEP_CONVERSION_BEHAVIOR">优化转化行为</Radio.Button>}
  576. {worthList?.length > 0 && <Radio.Button value="DEEP_CONVERSION_WORTH">优化 ROI</Radio.Button>}
  577. </Radio.Group>
  578. </Form.Item>
  579. <Form.Item label={<strong>深度优化目标</strong>} name='goal' rules={[{ required: true, message: '请选择深度优化目标' }]}>
  580. <Select style={{ width: 380 }} placeholder='请选择'>
  581. {deepConversionType === 'DEEP_CONVERSION_BEHAVIOR' ? Object.keys(OptimizationGoalEnum).filter(key => behaviorList?.includes(key)).map(key => <Select.Option value={key} key={key}>{OptimizationGoalEnum[key]}</Select.Option>) : deepConversionType === 'DEEP_CONVERSION_WORTH' ?
  582. Object.keys(GoalRoasEnum).filter(key => worthList?.includes(key)).map(key => <Select.Option value={key} key={key}>{GoalRoasEnum[key]}</Select.Option>) : null}
  583. </Select>
  584. </Form.Item>
  585. {deepConversionType === 'DEEP_CONVERSION_BEHAVIOR' ? <>
  586. <Form.Item label={<strong>深度目标出价</strong>} name='deepBidAmount' rules={[{ required: true, message: '请输入深度目标出价' }]}>
  587. <Input style={{ width: 380 }} suffix={`元/${OptimizationGoalEnum[goal] || '优化目标'}`} placeholder={`请输入深度目标出价,范围0.1~10000`} />
  588. </Form.Item>
  589. </> :
  590. deepConversionType === 'DEEP_CONVERSION_WORTH' ? <>
  591. <Form.Item label={<strong>期望ROI</strong>} name='deepBidAmount' rules={[{ required: true, message: '请输入期望ROI' }]}>
  592. <Input style={{ width: 380 }} placeholder={`期望ROI目标范围0.001~1000,输入0.05,表示ROI目标为5%`} />
  593. </Form.Item>
  594. </> : null}
  595. {siteSet?.length > 1 && <Form.Item label={<strong>开启分版位深度目标出价</strong>} name='bidAdjustmentEnabled' valuePropName="checked">
  596. <Switch checkedChildren="开启" unCheckedChildren="关闭" />
  597. </Form.Item>}
  598. {bidAdjustmentEnabled && <Form.Item
  599. label={<strong>分版位深度目标出价</strong>}
  600. name='siteSetPackage'
  601. rules={[{ required: bidAdjustmentEnabled ? true : false, message: '请设置系数' }]}
  602. >
  603. <BidAdjustment bidAmount={deepBidAmount} deepConversionType={deepConversionType} goal={goal}>
  604. {!(bidAmountAdjustmentEnabled) ? <AdPositionList value={siteSetPackage} onChange={(data) => {
  605. form.setFieldsValue({
  606. siteSetPackage: data
  607. })
  608. }} /> : <></>}
  609. </BidAdjustment>
  610. </Form.Item>}
  611. </div>}
  612. </>}
  613. </>}
  614. <Form.Item label={<strong>广告日预算</strong>} name='dailyBudget'>
  615. <Input placeholder='不填默认为不限' style={{ width: 300 }} />
  616. </Form.Item>
  617. <Form.Item label={<strong>广告状态</strong>} name="configuredStatus" rules={[{ required: true, message: '请选择广告状态' }]}>
  618. <Select placeholder="选择广告状态" style={{ width: 300 }}>
  619. {Object.keys(AdStatus).map(key => {
  620. return <Select.Option value={key} key={key}>{AdStatus[key]}</Select.Option>
  621. })}
  622. </Select>
  623. </Form.Item>
  624. </Form>
  625. </Modal >
  626. }
  627. export default WeChatAdModal