wjx 2 سال پیش
والد
کامیت
1d408f887e

+ 140 - 0
src/components/EarlyWarning/addEdit.tsx

@@ -0,0 +1,140 @@
+import { DeleteOutlined, PlusOutlined, QuestionCircleOutlined } from "@ant-design/icons"
+import { Button, DatePicker, Form, Input, InputNumber, message, Modal, Popconfirm, Select, Space, Switch, TimePicker, Tooltip } from "antd"
+import { RuleObject } from "antd/es/form"
+import { StoreValue } from "antd/es/form/interface"
+import React from "react"
+import { MonitorFieldEnum } from "./config"
+import './index.less'
+import PriceInput from "./priceInput"
+
+
+interface Props {
+    visible?: boolean
+    onClose?: () => void
+    onChange?: () => void
+}
+const AddEdit: React.FC<Props> = (props) => {
+
+    /******************************/
+    const { visible, onClose } = props
+    const [form] = Form.useForm();
+    const rules = Form.useWatch('rules', form);
+    /******************************/
+
+
+    const handleOk = () => {
+        console.log(JSON.stringify(rules));
+        form.validateFields().then(values => {
+            console.log(values);
+            if (values?.rules) {
+                let newValues = JSON.parse(JSON.stringify(values))
+                let params = newValues?.rules?.map((item: any) => {
+                    const { field, ...newItem } = item
+                    return {
+                        rule: Object.keys(newItem).map((item: any) => {
+                            return {
+                                ...newItem[item],
+                                field: item
+                            }
+                        })
+                    }
+                })
+                console.log('params--->', params);
+
+            } else {
+                message.error('请添加最少一项规则')
+            }
+        })
+    }
+
+    return <Modal
+        title={<Space size={2} align='end'>
+            <strong>设置预警</strong>
+            <span style={{ fontSize: 12, color: 'red' }}>(条件与条件之间是或者关系,条件内字段是并且关系, 满足任意一条件立即触发报警提醒)</span>
+        </Space>}
+        visible={visible}
+        onOk={handleOk}
+        width={750}
+        onCancel={() => onClose?.()}
+    >
+        <Form
+            name="dynamic_form_nest_item"
+            form={form}
+            className="addEdit_form"
+            labelCol={{ span: 5 }}
+            colon={false}
+            initialValues={{
+                enable: true,
+                notifyFrequency: 5,
+                rules: [{
+                    field: [],
+                }]
+            }}
+        >
+            <div style={{ padding: '0 4px' }}>
+                <Form.Item name="ruleName" label={<strong>规则名称</strong>} rules={[{ required: true, message: '请输入规则名称' }]}>
+                    <Input placeholder="规则名称" />
+                </Form.Item>
+                <Form.Item name="notifyFrequency" label={<strong>通知频率</strong>} rules={[{ required: true, message: '请选择通知频率' }]}>
+                    <InputNumber min={5} addonAfter="分钟"/>
+                </Form.Item>
+                <Form.Item name="enable" label={<strong>Enable?</strong>} valuePropName="checked">
+                    <Switch />
+                </Form.Item>
+            </div>
+            <Form.List name="rules">
+                {(fields, { add, remove }) => <>
+                    <>{fields.map(({ key, name, ...restField }) => {
+                        return <div key={key} style={{ width: '100%' }} className="field">
+                            <Space className="field_name">
+                                <span>条件{key + 1}</span>
+                                {fields.length > 1 && <Popconfirm
+                                    title="确定删除"
+                                    onConfirm={() => remove(name)}
+                                    okText="Yes"
+                                    cancelText="No"
+                                >
+                                    <DeleteOutlined style={{ color: 'red' }} />
+                                </Popconfirm>}
+                            </Space>
+                            <Form.Item
+                                {...restField}
+                                label={<strong>字段</strong>}
+                                name={[name, 'field']}
+                                rules={[{ required: true, message: '请选择字段' }]}
+                            >
+                                <Select
+                                    mode="multiple"
+                                    showSearch
+                                    allowClear
+                                    placeholder="选择要设置的字段"
+                                    filterOption={(input, option) =>
+                                        ((option?.label ?? '') as any).toLowerCase().includes(input.toLowerCase())
+                                    }
+                                >
+                                    {Object.keys(MonitorFieldEnum).map((item, index) => <Select.Option disabled={rules?.[key]?.['field']?.length >= 3 && !rules?.[key]['field'].includes(item)} value={item} key={index}>{MonitorFieldEnum[item]}</Select.Option>)}
+                                </Select>
+                            </Form.Item>
+                            {rules?.[key]?.['field']?.map((field: string, index: number) => <Form.Item
+                                {...restField}
+                                key={index}
+                                label={<strong>{MonitorFieldEnum[field]}</strong>}
+                                name={[name, field]}
+                                rules={[{ required: true, message: '请设置条件' }]}
+                            >
+                                <PriceInput />
+                            </Form.Item>)}
+                        </div>
+                    })}</>
+
+                    <Form.Item>
+                        <Button type="dashed" onClick={() => add()} block icon={<PlusOutlined />}>新增条件</Button>
+                    </Form.Item>
+                </>}
+            </Form.List>
+
+        </Form>
+    </Modal>
+}
+
+export default React.memo(AddEdit)

+ 27 - 0
src/components/EarlyWarning/config.ts

@@ -0,0 +1,27 @@
+/** 监控可配置字段 */
+export enum MonitorFieldEnum {
+    cost_total = '总消耗',
+    cost_day = '今日消耗',
+    cost_hour = '当前小时消耗',
+    cost_trend_last_three_hour = '消耗趋势(前 3小时)',
+    view_total = '总曝光量',
+    thousand_display_price_total = '总千次曝光成本',
+    click_total = '总点击量',
+    ctr_total = '总点击率',
+    cpc_total = '总点击均价',
+    conversions_count_total = '总转化目标量',
+    conversions_cost_total = '总转化目标成本',
+    conversions_rate_total = '总目标转化率',
+    order_count_total = '总下单量',
+    order_amount_total = '总下单金额',
+    order_cost_total = '总下单成本',
+    order_rate_total = '总下单率',
+    order_roi_total = '总下单roi',
+    first_day_order_count_total = '总首日下单量',
+    first_day_order_amount_total = '总首日下单金额',
+    first_day_order_roi_total = '总首日下单率',
+    atv_total = '总下单客单价',
+    mp_follow_uv_total = '总公众号关注人数',
+    mp_follow_cost_total = '总公众号关注成本',
+    mp_follow_rate_total = '总公众号关注率'
+}

+ 27 - 0
src/components/EarlyWarning/index.less

@@ -0,0 +1,27 @@
+
+
+.addEdit_form {
+
+    .field {
+        border: 1px dashed #cfcfcf;
+        border-radius: 4px;
+        padding: 15px 4px 4px;
+        margin-bottom: 14px;
+        position: relative;
+        transition: all .2s;
+
+        &_name {
+            position: absolute;
+            background-color: #FFFFFF;
+            top: -14px;
+            font-weight: 700;
+            left: 10px;
+            padding: 0 6px;
+            font-size: 16px;
+        }
+
+        &:hover {
+            border-color: #1890FF;
+        }
+    }
+}

+ 40 - 0
src/components/EarlyWarning/index.tsx

@@ -0,0 +1,40 @@
+import { Button, Drawer, Form, Modal, Space } from "antd"
+import React, { useState } from "react"
+import AddEdit from "./addEdit"
+
+
+
+/**
+ * 监控预警
+ * @returns 
+ */
+const EarlyWarning: React.FC = () => {
+
+    /**************************/
+    const [visible, setVisible] = useState<boolean>(false)
+    const [addVisible, setAddVisible] = useState<boolean>(true)
+    /**************************/
+
+
+    return <>
+        <Button type="primary" onClick={() => setVisible(true)}>监控预警</Button>
+
+        {/* 预警列表 */}
+        {visible && <Drawer
+            title="监控预警"
+            placement="right"
+            onClose={() => setVisible(false)}
+            visible={visible}
+            width='800px'
+        >
+            <Space direction="vertical">
+                <Button type="primary" onClick={() => setAddVisible(true)}>设置预警</Button>
+            </Space>
+        </Drawer>}
+
+        {/* 设置预警 */}
+        {addVisible && <AddEdit visible={addVisible} onClose={() => setAddVisible(false)} />}
+    </>
+}
+
+export default React.memo(EarlyWarning)

+ 71 - 0
src/components/EarlyWarning/priceInput.tsx

@@ -0,0 +1,71 @@
+import { Input, Select } from "antd";
+import React, { useState } from "react"
+
+
+type Condition = '>' | '>=' | '<' | '<=' | '=';
+
+interface PriceValue {
+    value?: number
+    condition?: Condition
+}
+interface Props {
+    value?: PriceValue,
+    onChange?: (value: PriceValue) => void;
+}
+
+/**
+ * 自定义数据input
+ * @param param0 
+ */
+const PriceInput: React.FC<Props> = ({ value = {}, onChange }) => {
+
+    /**********************/
+    const [number, setNumber] = useState(0);
+    const [condition, setCondition] = useState<Condition>('>');
+    /**********************/
+
+    const triggerChange = (changedValue: { value?: number; condition?: Condition }) => {
+        onChange?.({ value: number, condition, ...value, ...changedValue });
+    };
+
+    const onNumberChange = (e: React.ChangeEvent<HTMLInputElement>) => {
+        const newNumber = parseInt(e.target.value || '0', 10);
+        if (Number.isNaN(number)) {
+            return;
+        }
+        if (!('number' in value)) {
+            setNumber(newNumber);
+        }
+        triggerChange({ value: newNumber });
+    };
+
+    const onConditionChange = (newCondition: Condition) => {
+        if (!('currency' in value)) {
+            setCondition(newCondition);
+        }
+        triggerChange({ condition: newCondition });
+    }
+
+    return <span>
+        <Select
+            value={value.condition || condition}
+            style={{ width: 100 }}
+            onChange={onConditionChange}
+        >
+            <Select.Option value=">">大于</Select.Option>
+            <Select.Option value=">=">大于等于</Select.Option>
+            <Select.Option value="<">小于</Select.Option>
+            <Select.Option value="<=">小于等于</Select.Option>
+            <Select.Option value="=">等于</Select.Option>
+        </Select>
+        <Input
+            type="text"
+            value={value.value || number}
+            onChange={onNumberChange}
+            style={{ width: 130, margin: '0 8px' }}
+        />
+
+    </span>
+}
+
+export default React.memo(PriceInput)

+ 14 - 1
src/global.less

@@ -381,4 +381,17 @@ body {
   .ant-form-item{
     margin-bottom: 15px;
   }
-}
+}
+
+.ant-select-selector, .ant-input, .ant-input-affix-wrapper, .ant-btn, .ant-modal-content, .ant-select-dropdown, .ant-input-number-input {
+  border-radius: 4px !important;
+}
+
+.ant-radio-button-wrapper {
+  &:first-child {
+    border-radius: 4px 0 0 4px !important;
+  }
+  &:last-child {
+    border-radius: 0 4px 4px 0 !important;
+  }
+}

+ 4 - 0
src/pages/launchSystemNew/adq/ad/index.tsx

@@ -12,6 +12,7 @@ import Copy from './copy'
 import PlanDetail from '@/pages/adMonitor/adMonitorList/components/planDetail'
 import { txAdConfig } from '../config'
 import Log from '../log'
+import EarlyWarning from '@/components/EarlyWarning'
 
 type Props = {
     accountId: string,
@@ -398,6 +399,9 @@ const Ad: React.FC<Props> = (props) => {
                     <Col>
                         <Button type='dashed' onClick={() => { setCzjlShow(true) }}>操作记录</Button>
                     </Col>
+                    <Col>
+                        <EarlyWarning />
+                    </Col>
                 </Row>
             </Space>}
             rowSelection={{

+ 3 - 3
src/pages/launchSystemNew/adq/ad/tableConfig.tsx

@@ -41,7 +41,7 @@ function tableConfig(
             dataIndex: 'accountId',
             key: 'accountId',
             align: 'center',
-            width: 100,
+            width: 80,
             ellipsis: true,
             render: (a: string) => {
                 return <Space>
@@ -74,7 +74,7 @@ function tableConfig(
             dataIndex: 'adgroupId',
             key: 'adgroupId',
             align: 'center',
-            width: 120,
+            width: 100,
             ellipsis: true,
             render: (a: string, b: any) => {
                 return <Space>
@@ -87,7 +87,7 @@ function tableConfig(
             dataIndex: 'campaignId',
             key: 'campaignId',
             align: 'center',
-            width: 120,
+            width: 100,
             ellipsis: true,
             render: (a: string, b: any) => {
                 return <Space >

+ 0 - 21
src/pages/launchSystemNew/adq/ad/updateAdName.tsx

@@ -1,21 +0,0 @@
-import React from "react"
-
-
-
-
-interface Props {
-
-}
-const updateAdName: React.FC<Props> = (props) => {
-
-    /*******************************/
-    const {} = props
-    /*******************************/
-
-    return <div>
-
-    </div>
-}
-
-
-export default React.memo(updateAdName)

+ 3 - 3
src/pages/launchSystemNew/adq/config.ts

@@ -4,11 +4,11 @@ const txAdConfig = [
         label: '设置信息',
         data: [
             { title: '启停', dataIndex: 'configuredStatus', label: '设置信息', default: 1, width: 40 },
-            { title: '所属账号', dataIndex: 'accountId', label: '设置信息', default: 2, width: 100 },
+            { title: '所属账号', dataIndex: 'accountId', label: '设置信息', default: 2, width: 75 },
             { title: '腾讯备注', dataIndex: 'memo', label: '设置信息', default: 3, width: 80 },
             { title: '本地备注', dataIndex: 'remark', label: '设置信息', default: 4, width: 80 },
-            { title: '广告ID', dataIndex: 'adgroupId', label: '设置信息', default: 5, width: 120 },
-            { title: '所属计划ID', dataIndex: 'campaignId', label: '设置信息', default: 6, width: 120 },
+            { title: '广告ID', dataIndex: 'adgroupId', label: '设置信息', default: 5, width: 90 },
+            { title: '所属计划ID', dataIndex: 'campaignId', label: '设置信息', default: 6, width: 90 },
             { title: '广告名称', dataIndex: 'adgroupName', label: '设置信息', default: 7, width: 280 },
             { title: '推广目标类型', dataIndex: 'promotedObjectType', label: '设置信息', default: 8, width: 75 },
             { title: '投放日期', dataIndex: 'beginDate', label: '设置信息', default: 9, width: 150 },