|
@@ -2,7 +2,7 @@ import { Button, Card, Checkbox, Form, Input, Modal, Radio, Select, Space, Spin,
|
|
import React, { useEffect, useState } from "react"
|
|
import React, { useEffect, useState } from "react"
|
|
import style from '../index.less'
|
|
import style from '../index.less'
|
|
import { DEVICE_PRICE_ENUM, EDUCATION_ENUM, EXCLUDED_DAY_ENUM, EXCLUDED_DIMENSION_ENUM, GAME_CONSUMPTION_LEVEL_ENUM, GENDER_ENUM, LOCATION_TYPES_ENUM, MARITAL_STATUS_ENUM, NETWORK_ENUM, OPTIMIZATIONGOAL_ENUM, USER_OS_ENUM, WECHAT_AD_NEHAVIOR_ENUM, WECHAT_AD_NEHAVIOR_GAME_ENUM } from "../../const"
|
|
import { DEVICE_PRICE_ENUM, EDUCATION_ENUM, EXCLUDED_DAY_ENUM, EXCLUDED_DIMENSION_ENUM, GAME_CONSUMPTION_LEVEL_ENUM, GENDER_ENUM, LOCATION_TYPES_ENUM, MARITAL_STATUS_ENUM, NETWORK_ENUM, OPTIMIZATIONGOAL_ENUM, USER_OS_ENUM, WECHAT_AD_NEHAVIOR_ENUM, WECHAT_AD_NEHAVIOR_GAME_ENUM } from "../../const"
|
|
-import { QuestionCircleFilled } from "@ant-design/icons"
|
|
|
|
|
|
+import { DeleteOutlined, PlusOutlined, QuestionCircleFilled } from "@ant-design/icons"
|
|
import { getTargetingGagsApi } from "@/services/adqV3/global"
|
|
import { getTargetingGagsApi } from "@/services/adqV3/global"
|
|
import { useAjax } from "@/Hook/useAjax"
|
|
import { useAjax } from "@/Hook/useAjax"
|
|
import { DefaultOptionType } from "antd/lib/select"
|
|
import { DefaultOptionType } from "antd/lib/select"
|
|
@@ -35,6 +35,7 @@ const AddTarget: React.FC<Props> = ({ isBackVal, putInType, value, visible, onCh
|
|
const ageType = Form.useWatch('ageType', form);
|
|
const ageType = Form.useWatch('ageType', form);
|
|
const min = Form.useWatch(['age', 'min'], form);
|
|
const min = Form.useWatch(['age', 'min'], form);
|
|
const max = Form.useWatch(['age', 'max'], form);
|
|
const max = Form.useWatch(['age', 'max'], form);
|
|
|
|
+ const age = Form.useWatch('age', form);
|
|
const education = Form.useWatch('education', form);
|
|
const education = Form.useWatch('education', form);
|
|
const networkType = Form.useWatch('networkType', form);
|
|
const networkType = Form.useWatch('networkType', form);
|
|
const devicePrice = Form.useWatch('devicePrice', form);
|
|
const devicePrice = Form.useWatch('devicePrice', form);
|
|
@@ -225,7 +226,7 @@ const AddTarget: React.FC<Props> = ({ isBackVal, putInType, value, visible, onCh
|
|
let [min, max] = ageType.split('_')
|
|
let [min, max] = ageType.split('_')
|
|
targetValues.age = [{ min: Number(min), max: Number(max) }]
|
|
targetValues.age = [{ min: Number(min), max: Number(max) }]
|
|
} else if (ageType === '1') {
|
|
} else if (ageType === '1') {
|
|
- targetValues.age = [age]
|
|
|
|
|
|
+ targetValues.age = age
|
|
}
|
|
}
|
|
// 排除已转化用户
|
|
// 排除已转化用户
|
|
if (excludedConvertedAudience?.excludedDimension !== '0') {
|
|
if (excludedConvertedAudience?.excludedDimension !== '0') {
|
|
@@ -266,6 +267,7 @@ const AddTarget: React.FC<Props> = ({ isBackVal, putInType, value, visible, onCh
|
|
accountId,
|
|
accountId,
|
|
targeting: targetValues
|
|
targeting: targetValues
|
|
}
|
|
}
|
|
|
|
+
|
|
if (isBackVal && !isAdd) {
|
|
if (isBackVal && !isAdd) {
|
|
delete targetingDTO.accountId
|
|
delete targetingDTO.accountId
|
|
delete targetingDTO.description
|
|
delete targetingDTO.description
|
|
@@ -319,7 +321,7 @@ const AddTarget: React.FC<Props> = ({ isBackVal, putInType, value, visible, onCh
|
|
} = JSON.parse(JSON.stringify(value))
|
|
} = JSON.parse(JSON.stringify(value))
|
|
let targetValues: any = {
|
|
let targetValues: any = {
|
|
...surplusValues,
|
|
...surplusValues,
|
|
- age: age?.[0] || undefined,
|
|
|
|
|
|
+ age: age?.length > 0 ? age : undefined,
|
|
gender: gender?.[0] || '0',
|
|
gender: gender?.[0] || '0',
|
|
education: education || '0',
|
|
education: education || '0',
|
|
networkType: networkType || '0',
|
|
networkType: networkType || '0',
|
|
@@ -349,8 +351,8 @@ const AddTarget: React.FC<Props> = ({ isBackVal, putInType, value, visible, onCh
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (age?.length > 0) {
|
|
if (age?.length > 0) {
|
|
- let g = age?.[0]?.min + '_' + age?.[0]?.max
|
|
|
|
- if (['14_18', '19_24', '25_29', '30_39', '40_49', '50_66'].includes(g)) {
|
|
|
|
|
|
+ const g = age?.[0]?.min + '_' + age?.[0]?.max
|
|
|
|
+ if (age?.length === 1 && ['14_18', '19_24', '25_29', '30_39', '40_49', '50_66'].includes(g)) {
|
|
targetValues.ageType = g
|
|
targetValues.ageType = g
|
|
} else {
|
|
} else {
|
|
targetValues.ageType = '1'
|
|
targetValues.ageType = '1'
|
|
@@ -396,6 +398,18 @@ const AddTarget: React.FC<Props> = ({ isBackVal, putInType, value, visible, onCh
|
|
}
|
|
}
|
|
}, [value, regionsList])
|
|
}, [value, regionsList])
|
|
|
|
|
|
|
|
+ /** 判断数组是否重叠 */
|
|
|
|
+ const hasOverlap = (intervals: any[]) => {
|
|
|
|
+ intervals = intervals.filter(item => item)
|
|
|
|
+ for (let i = 0; i < intervals.length; i++) {
|
|
|
|
+ for (let j = i + 1; j < intervals.length; j++) {
|
|
|
|
+ const a = intervals[i], b = intervals[j];
|
|
|
|
+ if (a?.min < b?.max && a?.max > b?.min) return true;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+
|
|
return <Modal
|
|
return <Modal
|
|
title={isBackVal ? <strong style={{ fontSize: 20 }}>
|
|
title={isBackVal ? <strong style={{ fontSize: 20 }}>
|
|
{(value && Object.keys(value).length > 0) ? `修改定向` : `新增定向`}
|
|
{(value && Object.keys(value).length > 0) ? `修改定向` : `新增定向`}
|
|
@@ -433,10 +447,7 @@ const AddTarget: React.FC<Props> = ({ isBackVal, putInType, value, visible, onCh
|
|
userOsType: '0',
|
|
userOsType: '0',
|
|
ageType: '0',
|
|
ageType: '0',
|
|
wechatAdBehaviorType: ['0'],
|
|
wechatAdBehaviorType: ['0'],
|
|
- age: {
|
|
|
|
- min: 14,
|
|
|
|
- max: 66
|
|
|
|
- },
|
|
|
|
|
|
+ age: [{}],
|
|
gender: '0',
|
|
gender: '0',
|
|
education: ['0'],
|
|
education: ['0'],
|
|
networkType: ['0'],
|
|
networkType: ['0'],
|
|
@@ -541,23 +552,61 @@ const AddTarget: React.FC<Props> = ({ isBackVal, putInType, value, visible, onCh
|
|
<Radio value="1">自定义</Radio>
|
|
<Radio value="1">自定义</Radio>
|
|
</Radio.Group>
|
|
</Radio.Group>
|
|
</Form.Item>
|
|
</Form.Item>
|
|
- {ageType === '1' && <div className={`${style.newSpace_bottom} flexStart`} style={{ '--g': '5px' } as React.CSSProperties}>
|
|
|
|
- <Form.Item name={['age', 'min']} style={{ marginBottom: 0 }}>
|
|
|
|
- <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 > max} value={i} key={i}>{i === 66 ? '66 岁及以上' : i + ' 岁'}</Select.Option>
|
|
|
|
- })}
|
|
|
|
- </Select>
|
|
|
|
- </Form.Item>
|
|
|
|
- <span>-</span>
|
|
|
|
- <Form.Item name={['age', 'max']} style={{ marginBottom: 0 }}>
|
|
|
|
- <Select style={{ width: 185 }} placeholder="请选择">
|
|
|
|
- {Array(66 - 17).fill('').map((_, i) => {
|
|
|
|
- return <Select.Option disabled={i + 18 < min} value={i + 18} key={i + 18}>{i + 18 === 66 ? '66 岁及以上' : i + 18 + ' 岁'}</Select.Option>
|
|
|
|
|
|
+ {ageType === '1' && <Form.List
|
|
|
|
+ name='age'
|
|
|
|
+ rules={[
|
|
|
|
+ {
|
|
|
|
+ validator: (_, ranges) => {
|
|
|
|
+ console.log('ranges', 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: '请选择最小年龄!' }]}
|
|
|
|
+ >
|
|
|
|
+ <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: '请选择最大年龄!' }]}
|
|
|
|
+ >
|
|
|
|
+ <Select style={{ width: 185 }} placeholder="请选择">
|
|
|
|
+ {Array(66 - 17).fill('').map((_, i) => {
|
|
|
|
+ return <Select.Option disabled={i + 18 < ag?.min} 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>
|
|
})}
|
|
})}
|
|
- </Select>
|
|
|
|
- </Form.Item>
|
|
|
|
- </div>}
|
|
|
|
|
|
+ {age?.length < 5 && <Form.Item noStyle>
|
|
|
|
+ <Button type="dashed" onClick={() => add()} style={{ width: '100%' }} icon={<PlusOutlined />}>
|
|
|
|
+ 新增年龄段
|
|
|
|
+ </Button>
|
|
|
|
+ </Form.Item>}
|
|
|
|
+ </>
|
|
|
|
+ }}
|
|
|
|
+ </Form.List>}
|
|
</div>
|
|
</div>
|
|
|
|
|
|
<div className={style.newSpace}>
|
|
<div className={style.newSpace}>
|