|
@@ -0,0 +1,411 @@
|
|
|
+import { useAjax } from "@/Hook/useAjax"
|
|
|
+import { configRuleApi } from "@/services/gameData/adlist"
|
|
|
+import { MinusCircleOutlined, PlusOutlined } from "@ant-design/icons"
|
|
|
+import { Badge, Button, Col, Form, Input, InputNumber, Modal, Radio, Row, Select, Space, Switch, message } from "antd"
|
|
|
+import React from "react"
|
|
|
+
|
|
|
+// 监控的数据时间段类型
|
|
|
+export const monitorTimeEnum = [
|
|
|
+ { label: '今日', value: 1 },
|
|
|
+ { label: '过去3天(包括今日)', value: 2 },
|
|
|
+ { label: '过去5天(包括今日)', value: 3 },
|
|
|
+ { label: '过去7天(包括今日)', value: 4 },
|
|
|
+ { label: '过去3天(不包括今日)', value: 5 },
|
|
|
+ { label: '过去5天(不包括今日)', value: 6 },
|
|
|
+ { label: '过去7天(不包括今日)', value: 7 },
|
|
|
+ { label: '广告开始消耗首日(0)', value: 8 },
|
|
|
+ { label: '广告开始消耗(累计3天)', value: 9 },
|
|
|
+ { label: '广告开始消耗(累计5天)', value: 10 },
|
|
|
+ { label: '广告开始消耗(累计7天)', value: 11 }
|
|
|
+]
|
|
|
+export const dataEnum = [
|
|
|
+ { label: '消耗', value: 1 },
|
|
|
+ { label: '预算', value: 2 },
|
|
|
+ { label: '点击率', value: 3 },
|
|
|
+ { label: 'ecpm(千次曝光成本)', value: 4 },
|
|
|
+ { label: '注册', value: 5 },
|
|
|
+ { label: '注册成本(消耗/注册人数)', value: 6 },
|
|
|
+ { label: '付费人数', value: 7 },
|
|
|
+ { label: '付费率(付费人数/注册人数)', value: 8 },
|
|
|
+ { label: '付费成本(消耗/付费人数)', value: 9 },
|
|
|
+ { label: 'arpu(付费金额/注册人数)', value: 10 },
|
|
|
+ { label: 'ROI1', value: 11 },
|
|
|
+ { label: 'ROI2', value: 12 },
|
|
|
+ { label: 'ROI3', value: 13 },
|
|
|
+ { label: 'ROI4', value: 14 },
|
|
|
+ { label: 'ROI5', value: 15 },
|
|
|
+ { label: 'ROI6', value: 16 },
|
|
|
+ { label: 'ROI7', value: 17 },
|
|
|
+ { label: 'LTV1', value: 18 },
|
|
|
+ { label: 'LTV2', value: 19 },
|
|
|
+ { label: 'LTV3', value: 20 },
|
|
|
+ { label: 'LTV4', value: 21 },
|
|
|
+ { label: 'LTV5', value: 22 },
|
|
|
+ { label: 'LTV6', value: 23 },
|
|
|
+ { label: 'LTV7', value: 24 }
|
|
|
+]
|
|
|
+
|
|
|
+export const conditionEnum = [
|
|
|
+ { label: '大于', value: 1 },
|
|
|
+ { label: '大于等于', value: 2 },
|
|
|
+ { label: '等于', value: 3 },
|
|
|
+ { label: '小于等于', value: 4 },
|
|
|
+ { label: '小于', value: 5 }
|
|
|
+]
|
|
|
+
|
|
|
+export const ruleDimensionEnum = [
|
|
|
+ { label: '默认', value: 1 },
|
|
|
+ { label: '渠道', value: 2 },
|
|
|
+ { label: '账号', value: 3 },
|
|
|
+ { label: '广告', value: 4 },
|
|
|
+]
|
|
|
+
|
|
|
+export const executeScopeEnum = [
|
|
|
+ { label: '所有广告(不含删除)', value: 1 },
|
|
|
+ { label: '投放中', value: 2 },
|
|
|
+ { label: '暂停投放', value: 3 },
|
|
|
+ { label: '预算不足', value: 4 },
|
|
|
+]
|
|
|
+
|
|
|
+export const operateTypeEnum = [
|
|
|
+ { label: '仅告警通知', value: 1 },
|
|
|
+ { label: '暂停广告', value: 2 },
|
|
|
+ { label: '启动广告', value: 3 },
|
|
|
+ { label: '增加预算', value: 4 },
|
|
|
+ { label: '减少预算', value: 5 },
|
|
|
+ { label: '广告置顶标黄', value: 6 },
|
|
|
+ { label: '广告置顶标红', value: 7 },
|
|
|
+]
|
|
|
+
|
|
|
+interface Props {
|
|
|
+ gameList: any[]
|
|
|
+ accountList: any[]
|
|
|
+ getChannelChoiceList: any
|
|
|
+ accountLoading?: boolean
|
|
|
+ initialValues?: any
|
|
|
+ visible?: boolean,
|
|
|
+ onClose?: () => void
|
|
|
+ onChange?: () => void
|
|
|
+}
|
|
|
+const ConfigModal: React.FC<Props> = ({ gameList, accountList, getChannelChoiceList, accountLoading, initialValues = {}, visible, onClose, onChange }) => {
|
|
|
+
|
|
|
+ /****************************/
|
|
|
+ const [form] = Form.useForm()
|
|
|
+ const ruleDimension = Form.useWatch('ruleDimension', form)
|
|
|
+
|
|
|
+ const configRule = useAjax((params) => configRuleApi(params))
|
|
|
+ /****************************/
|
|
|
+
|
|
|
+ const handleOk = async () => {
|
|
|
+ form.submit()
|
|
|
+ let data = await form.validateFields()
|
|
|
+ console.log('===========>', data)
|
|
|
+ if (initialValues?.id) {
|
|
|
+ data.id = initialValues?.id
|
|
|
+ }
|
|
|
+ data.ruleCondition = data.ruleCondition.map((item: any, index: number) => ({ ...item, id: index + 1 }))
|
|
|
+ if (data.ruleDimension === 1) {
|
|
|
+ data.effectiveScope = null
|
|
|
+ }
|
|
|
+ configRule.run(data).then(res => {
|
|
|
+ if (res) {
|
|
|
+ if (initialValues?.id) {
|
|
|
+ message.success('修改成功')
|
|
|
+ } else {
|
|
|
+ message.success('新增成功')
|
|
|
+ }
|
|
|
+ onChange?.()
|
|
|
+ }
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+ return <Modal
|
|
|
+ title={`新建规则提醒`}
|
|
|
+ visible={visible}
|
|
|
+ onCancel={onClose}
|
|
|
+ onOk={handleOk}
|
|
|
+ bodyStyle={{ height: 600, overflow: 'auto' }}
|
|
|
+ width={700}
|
|
|
+ confirmLoading={configRule.loading}
|
|
|
+ >
|
|
|
+ <Form
|
|
|
+ name="basicStrategy"
|
|
|
+ form={form}
|
|
|
+ layout="vertical"
|
|
|
+ autoComplete="off"
|
|
|
+ colon={false}
|
|
|
+ initialValues={Object.keys(initialValues).length > 0 ? { ...initialValues } : { ruleDimension: 1, isStart: true, ruleType: 1, department: 1, ruleCondition: [{}] }}
|
|
|
+ >
|
|
|
+ <Row gutter={10}>
|
|
|
+ <Col span={24}><h3 style={{ borderBottom: '1px solid #f0f0f0' }}><strong>基本配置</strong></h3></Col>
|
|
|
+ <Col span={12}>
|
|
|
+ <Form.Item label='规则名称' name='ruleName' rules={[{ required: true, message: '请输入规则名称!' }]}>
|
|
|
+ <Input placeholder="请输入规则名称" />
|
|
|
+ </Form.Item>
|
|
|
+ </Col>
|
|
|
+ <Col span={12}>
|
|
|
+ <Form.Item label='规则类型' name='ruleType' rules={[{ required: true, message: '请选择规则类型!' }]}>
|
|
|
+ <Select
|
|
|
+ showSearch
|
|
|
+ allowClear
|
|
|
+ placeholder={'请选择规则类型'}
|
|
|
+ filterOption={(input, option) =>
|
|
|
+ (option?.children as any)?.toLowerCase().indexOf(input.toLowerCase()) >= 0
|
|
|
+ }
|
|
|
+ >
|
|
|
+ <Select.Option value={1}>个人规则</Select.Option>
|
|
|
+ </Select>
|
|
|
+ </Form.Item>
|
|
|
+ </Col>
|
|
|
+ <Col span={12}>
|
|
|
+ <Form.Item label='部门' name='department' rules={[{ required: true, message: '请选择规则类型!' }]}>
|
|
|
+ <Select
|
|
|
+ showSearch
|
|
|
+ allowClear
|
|
|
+ placeholder={'请选择规则类型'}
|
|
|
+ filterOption={(input, option) =>
|
|
|
+ (option?.children as any)?.toLowerCase().indexOf(input.toLowerCase()) >= 0
|
|
|
+ }
|
|
|
+ >
|
|
|
+ <Select.Option value={1}>游戏投放</Select.Option>
|
|
|
+ </Select>
|
|
|
+ </Form.Item>
|
|
|
+ </Col>
|
|
|
+ <Col span={12}>
|
|
|
+ <Form.Item label='游戏' name='gameId' rules={[{ required: true, message: '请选择游戏!' }]}>
|
|
|
+ <Select
|
|
|
+ showSearch
|
|
|
+ allowClear
|
|
|
+ placeholder={'请选择游戏'}
|
|
|
+ filterOption={(input, option) =>
|
|
|
+ (option?.children as any)?.toLowerCase().indexOf(input.toLowerCase()) >= 0
|
|
|
+ }
|
|
|
+ >
|
|
|
+ {gameList?.map((item: any) => <Select.Option value={item.id} key={item.id}>{item.game_name}</Select.Option>)}
|
|
|
+ </Select>
|
|
|
+ </Form.Item>
|
|
|
+ </Col>
|
|
|
+ <Col span={12}>
|
|
|
+ <Form.Item label='媒体' name='mediaType' rules={[{ required: true, message: '请选择媒体!' }]}>
|
|
|
+ <Select
|
|
|
+ style={{ minWidth: 140 }}
|
|
|
+ allowClear
|
|
|
+ placeholder={'请选择媒体类型'}
|
|
|
+ filterOption={(input, option) =>
|
|
|
+ (option?.children as any)?.toLowerCase().indexOf(input.toLowerCase()) >= 0
|
|
|
+ }
|
|
|
+ >
|
|
|
+ <Select.Option value={1}>腾讯</Select.Option>
|
|
|
+ <Select.Option value={2}>头条</Select.Option>
|
|
|
+ </Select>
|
|
|
+ </Form.Item>
|
|
|
+ </Col>
|
|
|
+ <Col span={12}>
|
|
|
+ <Form.Item label='规则是否启用' name='isStart' rules={[{ required: true, message: '规则是否启用!' }]} valuePropName="checked">
|
|
|
+ <Switch />
|
|
|
+ </Form.Item>
|
|
|
+ </Col>
|
|
|
+ <Col span={12}>
|
|
|
+ <Form.Item
|
|
|
+ label='规则维度'
|
|
|
+ name='ruleDimension'
|
|
|
+ rules={[{ required: true, message: '请选择规则维度!' }]}
|
|
|
+ help={<Space direction="vertical" size={1}>
|
|
|
+ <Badge status="default" style={{ fontSize: 12 }} text="告警规则可以配置为游戏对应媒体的默认规则,或者给游戏指定媒体内账号/渠道的所有广告、以及指定的广告配置。" />
|
|
|
+ <Badge status="default" style={{ fontSize: 12 }} text="告警的优先级为 广告 > 广告账号/渠道 > 媒体。" />
|
|
|
+ <Badge status="default" style={{ fontSize: 12 }} text="(只会触发同一级别的告警规则,如果在广告上配置了告警规则,那么广告账号的告警规则就不会触发)。" />
|
|
|
+ </Space>}
|
|
|
+ >
|
|
|
+ <Radio.Group onChange={() => form.setFieldsValue({ effectiveScope: undefined })}>
|
|
|
+ {ruleDimensionEnum.map(item => <Radio value={item.value} key={item.value}>{item.label}</Radio>)}
|
|
|
+ </Radio.Group>
|
|
|
+ </Form.Item>
|
|
|
+ </Col>
|
|
|
+ {ruleDimension !== 1 && <Col span={12}><Form.Item label='生效范围' name='effectiveScope' rules={[{ required: true, message: '请选择生效范围!' }]}>
|
|
|
+ <Select
|
|
|
+ mode="multiple"
|
|
|
+ maxTagCount={1}
|
|
|
+ showSearch
|
|
|
+ style={{ minWidth: 140 }}
|
|
|
+ allowClear
|
|
|
+ placeholder={'请选择生效范围'}
|
|
|
+ filterOption={(input, option) =>
|
|
|
+ (option?.children as any)?.toLowerCase().indexOf(input.toLowerCase()) >= 0
|
|
|
+ }
|
|
|
+ loading={accountLoading}
|
|
|
+ >
|
|
|
+ {ruleDimension === 2 ?
|
|
|
+ getChannelChoiceList?.data?.map((item: { id: React.Key | null | undefined; agentName: boolean | React.ReactChild | React.ReactFragment | React.ReactPortal | null | undefined }) => <Select.Option value={item.id} key={item.id}>{item.agentName}</Select.Option>) :
|
|
|
+ ruleDimension === 3 ? accountList.map(item => <Select.Option key={item.value} value={item.value}>{item.label.toString() + (item.corporationName ? `_${item.corporationName}` : '')}</Select.Option>) :
|
|
|
+ undefined
|
|
|
+ }
|
|
|
+ </Select>
|
|
|
+ </Form.Item></Col>}
|
|
|
+
|
|
|
+
|
|
|
+ <Col span={24}>
|
|
|
+ <h3 style={{ borderBottom: '1px solid #f0f0f0' }}><strong>告警动作</strong></h3>
|
|
|
+ </Col>
|
|
|
+ <Col span={12}>
|
|
|
+ <Form.Item label='告警方式' name='alarmType' rules={[{ required: true, message: '请选择告警方式!' }]}>
|
|
|
+ <Select
|
|
|
+ style={{ minWidth: 140 }}
|
|
|
+ allowClear
|
|
|
+ placeholder={'请选择告警方式'}
|
|
|
+ filterOption={(input, option) =>
|
|
|
+ (option?.children as any)?.toLowerCase().indexOf(input.toLowerCase()) >= 0
|
|
|
+ }
|
|
|
+ >
|
|
|
+ <Select.Option value={1}>短信</Select.Option>
|
|
|
+ <Select.Option value={2}>电话</Select.Option>
|
|
|
+ <Select.Option value={3}>钉钉</Select.Option>
|
|
|
+ </Select>
|
|
|
+ </Form.Item>
|
|
|
+ </Col>
|
|
|
+ <Col span={12}>
|
|
|
+ <Form.Item label='通知频率' name='alarmFrequency' rules={[{ required: true, message: '请输入通知频率!' }]}>
|
|
|
+ <InputNumber addonAfter="分钟/次" min={0} />
|
|
|
+ </Form.Item>
|
|
|
+ </Col>
|
|
|
+ <Col span={12}>
|
|
|
+ <Form.Item label='通知总次数' name='alarmCount' rules={[{ required: true, message: '请输入通知总次数!' }]}>
|
|
|
+ <InputNumber addonAfter="次数" min={0} />
|
|
|
+ </Form.Item>
|
|
|
+ </Col>
|
|
|
+ <Col span={12}>
|
|
|
+ <Form.Item label='操作维度' name='operateDimension' rules={[{ required: true, message: '请选择操作维度!' }]}>
|
|
|
+ <Select
|
|
|
+ style={{ minWidth: 140 }}
|
|
|
+ allowClear
|
|
|
+ placeholder={'请选择操作维度'}
|
|
|
+ filterOption={(input, option) =>
|
|
|
+ (option?.children as any)?.toLowerCase().indexOf(input.toLowerCase()) >= 0
|
|
|
+ }
|
|
|
+ >
|
|
|
+ <Select.Option value={1}>广告</Select.Option>
|
|
|
+ </Select>
|
|
|
+ </Form.Item>
|
|
|
+ </Col>
|
|
|
+ <Col span={12}>
|
|
|
+ <Form.Item label='操作类型' name='operateType' rules={[{ required: true, message: '请选择操作类型!' }]}>
|
|
|
+ <Select
|
|
|
+ style={{ minWidth: 140 }}
|
|
|
+ allowClear
|
|
|
+ placeholder={'请选择操作类型'}
|
|
|
+ filterOption={(input, option) =>
|
|
|
+ (option?.children as any)?.toLowerCase().indexOf(input.toLowerCase()) >= 0
|
|
|
+ }
|
|
|
+ >
|
|
|
+ {operateTypeEnum.map(item => <Select.Option value={item.value} key={item.value}>{item.label}</Select.Option>)}
|
|
|
+ </Select>
|
|
|
+ </Form.Item>
|
|
|
+ </Col>
|
|
|
+ <Col span={12}>
|
|
|
+ <Form.Item label='执行范围' name='executeScope' rules={[{ required: true, message: '请选择执行范围!' }]}>
|
|
|
+ <Select
|
|
|
+ style={{ minWidth: 140 }}
|
|
|
+ allowClear
|
|
|
+ placeholder={'请选择执行范围'}
|
|
|
+ filterOption={(input, option) =>
|
|
|
+ (option?.children as any)?.toLowerCase().indexOf(input.toLowerCase()) >= 0
|
|
|
+ }
|
|
|
+ >
|
|
|
+ {executeScopeEnum.map(item => <Select.Option value={item.value} key={item.value}>{item.label}</Select.Option>)}
|
|
|
+ </Select>
|
|
|
+ </Form.Item>
|
|
|
+ </Col>
|
|
|
+ <Col span={12}>
|
|
|
+ <Form.Item label='数据巡视周期' name='dataVisitsPeriod' rules={[{ required: true, message: '请选择数据巡视周期!' }]}>
|
|
|
+ <Select
|
|
|
+ style={{ minWidth: 140 }}
|
|
|
+ allowClear
|
|
|
+ placeholder={'请选择数据巡视周期'}
|
|
|
+ filterOption={(input, option) =>
|
|
|
+ (option?.children as any)?.toLowerCase().indexOf(input.toLowerCase()) >= 0
|
|
|
+ }
|
|
|
+ >
|
|
|
+ <Select.Option value={1}>实时巡视周期</Select.Option>
|
|
|
+ </Select>
|
|
|
+ </Form.Item>
|
|
|
+ </Col>
|
|
|
+ <Col span={24}><h3 style={{ borderBottom: '1px solid #f0f0f0' }}><strong>规则条件</strong><span style={{ fontSize: 12 }}>注:最多可同时设置5个指标条件</span></h3></Col>
|
|
|
+ <Col span={24}>
|
|
|
+ <Form.List name="ruleCondition">
|
|
|
+ {(fields, { add, remove }) => (<>
|
|
|
+ {fields.map(({ key, name, ...restField }, index) => (<Space key={key} align="center">
|
|
|
+ <strong style={{ paddingTop: 6, display: 'inline-block' }}>条件{index + 1}</strong>
|
|
|
+ <Form.Item
|
|
|
+ {...restField}
|
|
|
+ name={[name, 'monitorTimeType']}
|
|
|
+ rules={[{ required: true, message: '请选择监控的数据时间段' }]}
|
|
|
+ label='监控的数据时间段'
|
|
|
+ style={{ width: 180 }}
|
|
|
+ >
|
|
|
+ <Select
|
|
|
+ allowClear
|
|
|
+ placeholder={'请选择执行范围'}
|
|
|
+ filterOption={(input, option) =>
|
|
|
+ (option?.children as any)?.toLowerCase().indexOf(input.toLowerCase()) >= 0
|
|
|
+ }
|
|
|
+ >
|
|
|
+ {monitorTimeEnum.map(item => <Select.Option value={item.value} key={item.value}>{item.label}</Select.Option>)}
|
|
|
+ </Select>
|
|
|
+ </Form.Item>
|
|
|
+ <Form.Item
|
|
|
+ {...restField}
|
|
|
+ name={[name, 'dataType']}
|
|
|
+ rules={[{ required: true, message: '请选择指标类型' }]}
|
|
|
+ label='指标类型'
|
|
|
+ >
|
|
|
+ <Select
|
|
|
+ allowClear
|
|
|
+ placeholder={'请选择指标类型'}
|
|
|
+ filterOption={(input, option) =>
|
|
|
+ (option?.children as any)?.toLowerCase().indexOf(input.toLowerCase()) >= 0
|
|
|
+ }
|
|
|
+ style={{ width: 140 }}
|
|
|
+ >
|
|
|
+ {dataEnum.map(item => <Select.Option value={item.value} key={item.value}>{item.label}</Select.Option>)}
|
|
|
+ </Select>
|
|
|
+ </Form.Item>
|
|
|
+ <Form.Item
|
|
|
+ {...restField}
|
|
|
+ name={[name, 'conditionType']}
|
|
|
+ rules={[{ required: true, message: '请选择判断条件' }]}
|
|
|
+ label='判断条件'
|
|
|
+ >
|
|
|
+ <Select
|
|
|
+ style={{ width: 100 }}
|
|
|
+ allowClear
|
|
|
+ placeholder={'请选择判断条件'}
|
|
|
+ filterOption={(input, option) =>
|
|
|
+ (option?.children as any)?.toLowerCase().indexOf(input.toLowerCase()) >= 0
|
|
|
+ }
|
|
|
+ >
|
|
|
+ {conditionEnum.map(item => <Select.Option value={item.value} key={item.value}>{item.label}</Select.Option>)}
|
|
|
+ </Select>
|
|
|
+ </Form.Item>
|
|
|
+ <Form.Item
|
|
|
+ {...restField}
|
|
|
+ name={[name, 'dataNum']}
|
|
|
+ rules={[{ required: true, message: '请输入数值' }]}
|
|
|
+ label='数值'
|
|
|
+ >
|
|
|
+ <InputNumber min={0} placeholder="请输入数值" style={{ width: 130 }} />
|
|
|
+ </Form.Item>
|
|
|
+ {fields.length > 1 && <div style={{ paddingTop: 5, color: 'red' }}><MinusCircleOutlined onClick={() => remove(name)} /></div>}
|
|
|
+ </Space>))}
|
|
|
+ <Form.Item noStyle>
|
|
|
+ <Button type="dashed" disabled={fields.length >= 5} onClick={() => add()} block icon={<PlusOutlined />}>
|
|
|
+ 新增
|
|
|
+ </Button>
|
|
|
+ </Form.Item>
|
|
|
+ </>)}
|
|
|
+ </Form.List>
|
|
|
+ </Col>
|
|
|
+ </Row>
|
|
|
+ </Form>
|
|
|
+ </Modal>
|
|
|
+}
|
|
|
+
|
|
|
+export default React.memo(ConfigModal)
|