modal.tsx 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  1. import React, { useCallback, useEffect } from 'react'
  2. import { Modal, Form, Input, Divider, Select, Radio, DatePicker, Switch, Checkbox, message,Tooltip } from 'antd'
  3. import { SiteSetEnum, BidModeEnum, OptimizationGoalEnum, BidStrategyEnum, PromotedObjectType } from '@/services/launchAdq/enum'
  4. import { ModalConfig } from '.'
  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. const { RangePicker }: { RangePicker: any } = DatePicker;
  10. let DatePickers: any = DatePicker
  11. interface Props {
  12. visible: boolean,
  13. PupFn: (arg: ModalConfig) => void,
  14. callback: (params: any) => void,
  15. confirmLoading?: boolean,
  16. type?: 'add' | 'look' | 'edit',//新增,查看,编辑
  17. dataInfo?: any
  18. }
  19. /**广告模板*/
  20. function AdModal(props: Props) {
  21. let { visible, confirmLoading, PupFn, callback, type, dataInfo } = props
  22. let arg = type === 'look' ? { footer: null } : {}
  23. const sceneTagsList = useAjax((params) => getSceneTagsList(params))
  24. const [form] = Form.useForm();
  25. let dateType = Form.useWatch('dateType', form)
  26. let bidMode = Form.useWatch('bidMode', form)
  27. let smartBidType = Form.useWatch('smartBidType', form)
  28. let autoAcquisitionEnabled = Form.useWatch('autoAcquisitionEnabled', form)
  29. let siteSet = Form.useWatch('siteSet', form)
  30. let wechatPositionType = Form.useWatch('wechatPositionType', form)
  31. let wechatSceneType = Form.useWatch('wechatSceneType', form)
  32. // 确定事件
  33. const handleOk = useCallback(() => {
  34. form.validateFields().then(values => {
  35. let newValues = JSON.parse(JSON.stringify(values))
  36. newValues.sceneSpec = {}
  37. if (newValues.dateType === '2') {
  38. newValues['beginDate'] = moment(newValues.date).format('YYYY-MM-DD')
  39. } else {
  40. newValues['beginDate'] = moment(newValues.date[0]).format('YYYY-MM-DD')
  41. newValues['endDate'] = moment(newValues.date[1]).format('YYYY-MM-DD')
  42. }
  43. Object.keys(newValues).forEach(key => {
  44. switch (key) {
  45. case 'wechatPositionType':
  46. if (newValues[key] === '1') {
  47. newValues.sceneSpec = { ...newValues.sceneSpec, wechatPosition: newValues.wechatPosition }
  48. }
  49. break;
  50. case 'wechatSceneType':
  51. if (newValues[key] === '1') {
  52. newValues.sceneSpec = {
  53. ...newValues.sceneSpec, wechatScene: {
  54. officialAccountMediaCategory: newValues.officialAccountMediaCategory,
  55. miniProgramAndMiniGame: newValues.miniProgramAndMiniGame,
  56. payScene: newValues.payScene
  57. }
  58. }
  59. }
  60. break;
  61. }
  62. })
  63. if (newValues.sceneSpec.wechatPosition?.length === 0) {
  64. delete newValues.sceneSpec.wechatPosition
  65. }
  66. if (newValues.sceneSpec.wechatScene) {
  67. newValues.sceneSpec.wechatScene.officialAccountMediaCategory?.length === 0 && (delete newValues.sceneSpec.wechatScene.officialAccountMediaCategory)
  68. newValues.sceneSpec.wechatScene.miniProgramAndMiniGame?.length === 0 && (delete newValues.sceneSpec.wechatScene.miniProgramAndMiniGame)
  69. newValues.sceneSpec.wechatScene.payScene?.length === 0 && (delete newValues.sceneSpec.wechatScene.payScene)
  70. }
  71. if (!newValues.sceneSpec.wechatPosition && !newValues.sceneSpec.wechatScene) {
  72. delete newValues.sceneSpec
  73. }
  74. delete newValues.officialAccountMediaCategory
  75. delete newValues.miniProgramAndMiniGame
  76. delete newValues.payScene
  77. delete newValues.wechatPositionType
  78. delete newValues.wechatPosition
  79. delete newValues.wechatScene
  80. delete newValues['dateType']
  81. delete newValues['date']
  82. newValues['timeSeries'] = Array(336).fill(1).join('')
  83. console.log(newValues)
  84. callback(newValues)
  85. })
  86. }, [form])
  87. // 场景定向
  88. useEffect(() => {
  89. sceneTagsList.run({ typeList: ['WECHAT_POSITION', 'OFFICIAL_ACCOUNT_MEDIA_CATEGORY', 'MINI_PROGRAM_AND_MINI_GAME', 'PAY_SCENE'] })
  90. }, [])
  91. // 数据回填
  92. useEffect(() => {
  93. if (dataInfo) {
  94. form.setFieldsValue({
  95. adgroupName: dataInfo?.adgroupName,//广告名称
  96. promotedObjectType: dataInfo?.promotedObjectType,//推广目标
  97. siteSet: dataInfo?.siteSet,//广告版位
  98. autoAcquisitionEnabled: dataInfo?.autoAcquisitionEnabled,//一键起量
  99. bidAmount: dataInfo?.bidAmount,//出价
  100. smartBidType: dataInfo?.smartBidType,//出价类型
  101. bidStrategy: dataInfo?.bidStrategy,//出价策略
  102. bidMode: dataInfo?.bidMode,//出价方式
  103. optimizationGoal: dataInfo?.optimizationGoal,//优化目标
  104. dateType: dataInfo?.endDate ? '1' : '2',//投放日期
  105. dailyBudget: dataInfo?.dailyBudget,//广告日预算
  106. date: dataInfo?.endDate ? [moment(dataInfo?.beginDate), moment(dataInfo?.endDate)] : moment(dataInfo?.beginDate),//日期
  107. autoAcquisitionBudget: dataInfo?.autoAcquisitionBudget,//起量预算
  108. wechatPositionType: dataInfo?.sceneSpec?.wechatPosition ? '1' : '0',//微信公众号与小程序定投
  109. wechatPosition: dataInfo?.sceneSpec?.wechatPosition,//微信公众号与小程序定投
  110. wechatSceneType: dataInfo?.sceneSpec?.wechatScene?.officialAccountMediaCategory || dataInfo?.sceneSpec?.wechatScene?.miniProgramAndMiniGame || dataInfo?.sceneSpec?.wechatScene?.payScene ? '1' : '0',//微信公众号与小程序场景
  111. officialAccountMediaCategory: dataInfo?.sceneSpec?.wechatScene?.officialAccountMediaCategory,//公众号媒体类型
  112. miniProgramAndMiniGame: dataInfo?.sceneSpec?.wechatScene?.miniProgramAndMiniGame,//小程序小游戏流量类型
  113. payScene: dataInfo?.sceneSpec?.wechatScene?.payScene,//订单详情页消费场景
  114. })
  115. }
  116. }, [dataInfo])
  117. return <Modal
  118. visible={visible}
  119. title={type === 'add' ? '新建广告' : type === 'look' ? '广告详情' : '编辑广告'}
  120. onCancel={() => { PupFn({ visible: false,dataInfo:null,type:'add' }) }}
  121. onOk={type === 'look' ? () => message.warning('详情无法改动内容') : handleOk}
  122. width={900}
  123. confirmLoading={confirmLoading}
  124. {...arg}
  125. >
  126. <Form
  127. form={form}
  128. labelCol={{ span: 5 }}
  129. initialValues={
  130. {
  131. promotedObjectType: 'PROMOTED_OBJECT_TYPE_WECHAT_OFFICIAL_ACCOUNT',
  132. siteSet: ['SITE_SET_MOMENTS', 'SITE_SET_WECHAT'],
  133. bidMode: 'BID_MODE_OCPM',
  134. dateType: '2',
  135. bidStrategy: 'BID_STRATEGY_AVERAGE_COST',
  136. timeSeries: '1',
  137. smartBidType: 'SMART_BID_TYPE_CUSTOM',
  138. autoAcquisitionEnabled: false,
  139. wechatSceneType: '0',
  140. wechatPositionType: '0',
  141. }
  142. }
  143. >
  144. {/* ============================================================基本信息============================================================= */}
  145. <Divider orientation='center'>基本信息</Divider>
  146. <Form.Item label={<strong>广告名称</strong>} name='adgroupName' rules={[{ required: true, message: '请输入广告名称!' }]}>
  147. <Input placeholder='广告名称' style={{ width: 300 }} />
  148. </Form.Item>
  149. <Form.Item label={<strong>推广目标类型</strong>} name='promotedObjectType' rules={[{ required: true, message: '请选择推广告推广目标类型!' }]}>
  150. <Select style={{ width: 300 }} showSearch filterOption={(input, option) =>
  151. (option!.children as unknown as string).toLowerCase().includes(input.toLowerCase())
  152. } allowClear>
  153. {
  154. Object.keys(PromotedObjectType).map(key => {
  155. return <Select.Option value={key} key={key}>{PromotedObjectType[key]}</Select.Option>
  156. })
  157. }
  158. </Select>
  159. </Form.Item>
  160. <Form.Item label={<strong>广告版位</strong>} name='siteSet' rules={[{ required: true, message: '请输入选择广告版位!' }]}>
  161. <Select mode='multiple' style={{ width: 300 }} allowClear>
  162. {
  163. Object.keys(SiteSetEnum).map(key => {
  164. return <Select.Option value={key} key={key}>{SiteSetEnum[key]}</Select.Option>
  165. })
  166. }
  167. </Select>
  168. </Form.Item>
  169. {
  170. siteSet?.some((s: string) => s === 'SITE_SET_WECHAT') && <>
  171. <Form.Item label={<strong>微信公众号与小程序定投</strong>} name='wechatPositionType' style={wechatPositionType === '1' ? { marginBottom: 5 } : {}}>
  172. <Radio.Group >
  173. <Radio.Button value="0">不限</Radio.Button>
  174. <Radio.Button value="1">自定义</Radio.Button>
  175. </Radio.Group>
  176. </Form.Item>
  177. {wechatPositionType === '1' && <Form.Item style={{ marginLeft: 177 }} name='wechatPosition'>
  178. <Checkbox.Group options={sceneTagsList?.data?.WECHAT_POSITION?.map((item: { description: any; id: any; }) => ({ label: item.description, value: item.id }))} />
  179. </Form.Item>}
  180. <Form.Item label={<strong>微信公众号与小程序场景</strong>} name='wechatSceneType' style={wechatSceneType === '1' ? { marginBottom: 5 } : {}} >
  181. <Radio.Group >
  182. <Radio.Button value="0">不限</Radio.Button>
  183. <Radio.Button value="1">自定义</Radio.Button>
  184. </Radio.Group>
  185. </Form.Item>
  186. {wechatSceneType === '1' && <>
  187. <p style={{ marginBottom: 5, marginLeft: 177 }}><strong style={{ marginRight: 20 }}>公众号媒体类型</strong></p>
  188. <Form.Item style={{ marginLeft: 177 }} name='officialAccountMediaCategory'>
  189. <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 }))} />
  190. </Form.Item>
  191. <p style={{ marginBottom: 5, marginLeft: 177 }}><strong style={{ marginRight: 20 }}>小程序小游戏流量类型</strong></p>
  192. <Form.Item style={{ marginLeft: 177 }} name='miniProgramAndMiniGame'>
  193. <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 }))} />
  194. </Form.Item>
  195. <p style={{ marginBottom: 5, marginLeft: 177 }}><strong style={{ marginRight: 20 }}>订单详情页消费场景</strong></p>
  196. <Form.Item style={{ marginLeft: 177 }} name='payScene'>
  197. <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 }))} />
  198. </Form.Item>
  199. </>}
  200. </>
  201. }
  202. {/* ============================================================排期与出价============================================================= */}
  203. <Divider orientation='center'>排期与出价</Divider>
  204. <Form.Item label={<strong>投放日期</strong>} name='dateType'>
  205. <Radio.Group >
  206. <Radio.Button value="1">选择开始与结束日期</Radio.Button>
  207. <Radio.Button value="2">长期投放</Radio.Button>
  208. </Radio.Group>
  209. </Form.Item>
  210. {/* 投放日期的不同展示不同的日期选择 */}
  211. {
  212. dateType === '1' ? <Form.Item name='date' rules={[{ required: true, message: '请选择日期' }]}>
  213. <RangePicker style={{ marginLeft: 177 }}></RangePicker>
  214. </Form.Item> : <Form.Item name='date' style={{ marginLeft: 177 }} rules={[{ required: true, message: '请选择日期' }]}>
  215. <DatePickers />
  216. </Form.Item>
  217. }
  218. <Form.Item label={<strong>投放时段</strong>}>
  219. <Radio.Group name='timeSeries' defaultValue='1'>
  220. <Radio.Button value={'1'}>全天投放</Radio.Button>
  221. </Radio.Group>
  222. </Form.Item>
  223. <Form.Item label={<strong>出价方式<Tooltip title='出价方式不同将影响自定义人群,行为兴趣意向等某些功能无法使用'><ExclamationCircleOutlined style={{color:'#e91e63',marginLeft:5}}/></Tooltip></strong>} name='bidMode'>
  224. <Radio.Group >
  225. {
  226. Object.keys(BidModeEnum).map(key => {
  227. return <Radio.Button value={key} key={key} disabled={!key.includes('CPM')}>{BidModeEnum[key]}</Radio.Button>
  228. })
  229. }
  230. </Radio.Group>
  231. </Form.Item>
  232. {/* 出价方式为OCPM才展示 */}
  233. {
  234. bidMode === 'BID_MODE_OCPM' && <>
  235. <Form.Item label={<strong>优化目标</strong>} name='optimizationGoal' rules={[{ required: true, message: '请选择优化目标' }]}>
  236. <Select style={{ width: 300 }} showSearch filterOption={(input, option) =>
  237. (option!.children as unknown as string).toLowerCase().includes(input.toLowerCase())
  238. } allowClear>
  239. {
  240. Object.keys(OptimizationGoalEnum).map(key => {
  241. return <Select.Option value={key} key={key}>{OptimizationGoalEnum[key]}</Select.Option>
  242. })
  243. }
  244. </Select>
  245. </Form.Item>
  246. <Form.Item label={<strong>出价类型</strong>} name='smartBidType'>
  247. <Radio.Group >
  248. <Radio.Button value="SMART_BID_TYPE_CUSTOM">手动出价</Radio.Button>
  249. <Radio.Button value="SMART_BID_TYPE_SYSTEMATIC">自动出价</Radio.Button>
  250. </Radio.Group>
  251. </Form.Item>
  252. <Form.Item label={<strong>出价策略</strong>} name='bidStrategy'>
  253. <Radio.Group >
  254. {
  255. Object.keys(BidStrategyEnum).map(key => {
  256. return <Radio.Button value={key} key={key} disabled={smartBidType === 'SMART_BID_TYPE_SYSTEMATIC' && key === 'BID_STRATEGY_PRIORITY_CAP_COST'}> {BidStrategyEnum[key]}</Radio.Button>
  257. })
  258. }
  259. </Radio.Group>
  260. </Form.Item>
  261. </>
  262. }
  263. {/* 出价类型为手动出价才展示 */}
  264. {
  265. smartBidType !== 'SMART_BID_TYPE_SYSTEMATIC' && <>
  266. <Form.Item label={<strong>出价</strong>} name='bidAmount' rules={[{ required: true, message: '请输入价格' }]}>
  267. <Input placeholder='输入价格 元/千次曝光' style={{ width: 300 }} />
  268. </Form.Item>
  269. {/* 当版位选择大于1时才出现 */}
  270. {/* {siteSet?.length > 1 &&<Form.Item label={<strong>分版位出价</strong>} name='bidAdjustment'>
  271. <Switch checkedChildren="开启" unCheckedChildren="关闭" />
  272. </Form.Item>} */}
  273. <Form.Item label={<strong>一键起量</strong>} name='autoAcquisitionEnabled' valuePropName="checked">
  274. <Switch checkedChildren="开启" unCheckedChildren="关闭" />
  275. </Form.Item>
  276. {/* 一键起量开启时才出现 */}
  277. {autoAcquisitionEnabled && <Form.Item label={<strong>起量预算</strong>} name='autoAcquisitionBudget' rules={[{ required: true, message: '请输入起量预算' }]}>
  278. <Input placeholder='起量预算' style={{ width: 300 }} />
  279. </Form.Item>}
  280. </>
  281. }
  282. <Form.Item label={<strong>广告日预算</strong>} name='dailyBudget'>
  283. <Input placeholder='不填默认为不限' style={{ width: 300 }} />
  284. </Form.Item>
  285. </Form>
  286. </Modal >
  287. }
  288. export default AdModal