wjx před 1 rokem
rodič
revize
56234e2464

+ 2 - 1
package.json

@@ -80,10 +80,11 @@
     "react-color": "^2.19.3",
     "react-cropper": "^2.1.7",
     "react-dom": "^16.8.6",
+    "react-draggable": "^4.4.5",
     "react-helmet-async": "^1.0.4",
     "react-image-crop": "^8.6.9",
     "react-lazyimg-component": "^1.0.1",
-    "react-resizable": "^3.0.4",
+    "react-resizable": "3.0.4",
     "react-responsive-carousel": "^3.2.18",
     "react-sortable-hoc": "^2.0.0",
     "react-window": "^1.8.6",

+ 1 - 1
src/pages/adMonitor/adMonitorList/data.tsx

@@ -12,7 +12,7 @@ export const GGStateData = {
     'STATUS_ACTIVE_CAMPAIGN_SUSPEND': '广告被暂停',
     'STATUS_PART_READY': '部分待投放',
     'STATUS_PART_ACTIVE': '部分投放中',
-    'STATUS_DELETED': '已删除',
+    'STATUS_DELETED': <Badge status="error" text={<span style={{ fontSize: 12 }}>已删除</span>}/>,
     'STATUS_UNKNOWN': '未知状态',
     'STATUS_FROZEN': '冻结',
     'STATUS_PREPARE': '准备中'

+ 235 - 0
src/pages/launchSystemNew/adq/ad/adIdSearch.tsx

@@ -0,0 +1,235 @@
+import { Button, Progress, Select, Space, Statistic, Table, Tag } from "antd"
+import React, { useEffect, useState } from "react"
+import style from './index.less'
+import Draggable from "react-draggable"
+import { CloseCircleOutlined, SearchOutlined, SyncOutlined } from "@ant-design/icons"
+import { allPlanProps, getAdqAccountListApi, getAllPlanListApi } from "@/services/adMonitor/adMonitor"
+import { useAjax } from "@/Hook/useAjax"
+import { ColumnsType } from "antd/lib/table"
+import { GGStateData } from "@/pages/adMonitor/adMonitorList/data"
+import { GUANGGAOZHUANGTAI } from "@/pages/adMonitor/adMonitorList/enum"
+import SearchSelect from "./searchSelect"
+import moment from "moment"
+
+interface Props {
+    userId: string
+    onChange?: (adidList?: number[]) => void
+}
+/**
+ * 开启监控过滤
+ * @returns 
+ */
+const AdIdSearch: React.FC<Props> = ({ userId, onChange }) => {
+
+    /***************************/
+    const [show, setShow] = useState<boolean>(false)
+    const [editSelectedRow, setEditSelectedRow] = useState<any[]>([])
+    const [queryFrom, setQueryForm] = useState<allPlanProps>({ pageNum: 1, pageSize: 20, createStartTime: moment().subtract(3, 'days').format('YYYY-MM-DD'), createEndTime: moment().format('YYYY-MM-DD') })
+
+    const getAllPlanList = useAjax((params) => getAllPlanListApi(params))
+    // 获取广告账号列表
+    const getAdqAccountList = useAjax(() => getAdqAccountListApi(), { formatResult: true })
+    /***************************/
+
+    useEffect(() => {
+        if (show) {
+            getAllPlanList.run({ sysUserId: [userId], ...queryFrom })
+        }
+    }, [userId, show, queryFrom])
+
+    const open = () => {
+        setShow(true)
+        getAdqAccountList.run()
+    }
+
+    const handleOk = () => {
+        onChange?.(editSelectedRow)
+    }
+
+    return <>
+        <Button onClick={() => open()}>开启监控过滤</Button>
+        {show && <Draggable>
+            <div className={`floating-window MYtable ${style.searchModal}`}>
+                <div className={style.close} onClick={() => setShow(false)}><CloseCircleOutlined /></div>
+                <Space>
+                    <Select
+                        showSearch
+                        mode='multiple'
+                        maxTagCount={1}
+                        value={queryFrom.accountId}
+                        style={{ minWidth: 140, maxWidth: 250 }}
+                        allowClear
+                        placeholder="请选择广告账号"
+                        onChange={(value: number[]) => {
+                            setQueryForm({ ...queryFrom, accountId: value, pageNum: 1 })
+                        }}
+                    >
+                        {getAdqAccountList?.data?.data?.map((item: { id: number, accountId: number }) => <Select.Option
+                            value={item.accountId}
+                            key={item.id}
+                        >
+                            {item.accountId}
+                        </Select.Option>)}
+                    </Select>
+                    <Select style={{ width: 140 }} placeholder="请选择广告状态" value={queryFrom.adStatus} onChange={(value: number) => {
+                        setQueryForm({ ...queryFrom, pageNum: 1, adStatus: value })
+                    }} allowClear>
+                        {Object.keys(GUANGGAOZHUANGTAI).map(key => {
+                            return <Select.Option value={key} key={key}>{GUANGGAOZHUANGTAI[key]}</Select.Option>
+                        })}
+                    </Select>
+                    <SearchSelect queryFrom={queryFrom} setQueryForm={setQueryForm} />
+                    <Button type="link" icon={<SyncOutlined />} style={{ padding: 0 }} onClick={() => getAllPlanList?.refresh()}>刷新</Button>
+                </Space>
+                <Table
+                    size="small"
+                    loading={getAllPlanList.loading}
+                    dataSource={getAllPlanList?.data?.records}
+                    columns={columns}
+                    rowKey={'id'}
+                    scroll={{ x: 300, y: 200 }}
+                    pagination={{
+                        total: getAllPlanList?.data?.total,
+                        showTotal: (total) => <Tag color="cyan">总共{total}数据</Tag>,
+                        current: getAllPlanList?.data?.current || 1,
+                        pageSize: getAllPlanList?.data?.size || 20,
+                    }}
+                    rowSelection={{
+                        selectedRowKeys: editSelectedRow,
+                        onChange: (selectedRowKeys: React.Key[], selectedRows: any[]) => {
+                            console.log(selectedRowKeys, selectedRows)
+                            setEditSelectedRow(selectedRowKeys)
+                        }
+                    }}
+                    onChange={(pagination, filters, sortData: any) => {
+                        let { current, pageSize } = pagination
+                        let newQueryForm = JSON.parse(JSON.stringify(queryFrom))
+                        newQueryForm.pageNum = current
+                        newQueryForm.pageSize = pageSize
+                        if (sortData && JSON.stringify('sortData') !== '{}') {
+                            let { field, order } = sortData   // descend 降序 大到小  ascend 升序 小到大
+                            if (order) {
+                                newQueryForm.sortField = field
+                                newQueryForm.sort = order === 'ascend' ? 'ASC' : 'DESC'
+                            } else {
+                                Object.keys(newQueryForm).forEach(key => {
+                                    if (key === 'sortField' || key === 'sort') {
+                                        delete newQueryForm[key]
+                                    }
+                                })
+                            }
+                        } else {
+                            Object.keys(newQueryForm).forEach(key => {
+                                if (key === 'sortField' || key === 'sort') {
+                                    delete newQueryForm[key]
+                                }
+                            })
+                        }
+                        setQueryForm({ ...newQueryForm })
+                    }}
+                />
+                {editSelectedRow?.length > 0 && <div className={style.bts}>
+                    <Button icon={<SearchOutlined />} type="primary" onClick={() => handleOk()} />
+                </div>}
+            </div>
+        </Draggable>}
+    </>
+}
+
+
+
+const columns: ColumnsType<any> = [
+    {
+        title: '广告ID',
+        dataIndex: 'adgroupId',
+        key: 'adgroupId',
+        align: 'center',
+        width: 90,
+        fixed: 'left',
+        ellipsis: true
+    },
+    {
+        title: '广告状态',
+        dataIndex: 'adStatus',
+        key: 'adStatus',
+        align: 'center',
+        width: 90,
+        ellipsis: true,
+        render: (a: any) => {
+            return GGStateData[a] || '--'
+        }
+    },
+    {
+        title: '广告总消耗',
+        dataIndex: 'cost',
+        key: 'cost',
+        align: 'center',
+        width: 100,
+        ellipsis: true,
+        sorter: true,
+        render: (a: any) => {
+            return <div style={{ height: 26, position: 'relative' }}>
+                <Progress
+                    strokeColor={{
+                        from: '#10c1e9',
+                        to: '#6892d0',
+                    }}
+                    status="active"
+                    showInfo={false}
+                    percent={a ? a / 3000 * 100 : 0}
+                />
+                <span style={{ position: 'absolute', left: 0, top: 2, bottom: 0, right: 0 }}><Statistic value={a || 0} valueStyle={a >= 30000 ? { color: '#000', fontWeight: 500 } : { fontWeight: 500 }} /></span>
+            </div>
+        }
+    },
+    {
+        title: '曝光量',
+        dataIndex: 'viewCount',
+        key: 'viewCount',
+        align: 'center',
+        width: 75,
+        sorter: true,
+        ellipsis: true,
+        render: (a: number) => {
+            return <span style={a <= 8 ? { color: '#0f990f', fontWeight: 600 } : a >= 100 ? { color: 'red', fontWeight: 600 } : {}}> {a || '--'}</span >
+        },
+    },
+    {
+        title: '下单量',
+        dataIndex: 'orderCount',
+        key: 'orderCount',
+        align: 'center',
+        width: 75,
+        sorter: true,
+        ellipsis: true,
+        render: (a: any) => {
+            return <Statistic value={a || 0} />
+        }
+    },
+    {
+        title: '千次曝光成本',
+        dataIndex: 'thousandDisplayPrice',
+        key: 'thousandDisplayPrice',
+        align: 'center',
+        width: 95,
+        // sorter: true,
+        ellipsis: true,
+        render: (a: any) => {
+            return <Statistic value={a ? a?.toFixed(2) : 0} />
+        }
+    },
+    {
+        title: '点击量',
+        dataIndex: 'clickCount',
+        key: 'clickCount',
+        align: 'center',
+        width: 70,
+        sorter: true,
+        ellipsis: true,
+        render: (a: number) => {
+            return <span style={a <= 8 ? { color: '#0f990f', fontWeight: 600 } : a >= 100 ? { color: 'red', fontWeight: 600 } : {}}> {a || '--'}</span >
+        },
+    },
+];
+
+export default React.memo(AdIdSearch)

+ 72 - 1
src/pages/launchSystemNew/adq/ad/index.less

@@ -1,4 +1,75 @@
-
 .clearCheckbox .ant-checkbox-inner {
     border-color: #FFF;
+}
+
+
+.searchModal {
+    position: fixed;
+    top: 148px;
+    right: 470px;
+    z-index: 200;
+    border-radius: 6px;
+    min-width: 200px;
+    max-width: 550px;
+    min-height: 50px;
+    max-height: 320px;
+    background-color: #FFF;
+    border: 1px solid #d19999;
+    padding: 6px;
+    box-sizing: border-box;
+    cursor: pointer;
+
+    .close {
+        position: absolute;
+        top: -18px;
+        right: -24px;
+        padding: 4px;
+        font-size: 18px;
+        color: red;
+    }
+
+    .bts {
+        position: absolute;
+        bottom: 0;
+        right: -33px;
+        background-color: #FFF;
+    }
+}
+
+.MYtable {
+    tbody {
+        td {
+            padding: 0px !important;
+
+            .ant-progress-bg {
+                border-radius: 0 !important;
+                height: 100% !important;
+            }
+
+            .ant-progress-inner {
+                border-radius: 0 !important;
+                height: 100%;
+                background-color: #fff;
+            }
+
+            .ant-progress-line,
+            .ant-progress-outer {
+                height: 100%;
+            }
+        }
+
+        tr:hover {
+            background-color: #d6d0d0 !important;
+        }
+
+        tr:active {
+            background-color: #d6d0d0 !important;
+        }
+    }
+}
+
+
+.more {
+    width: 500px;
+    max-height: 200px;
 }

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

@@ -16,6 +16,7 @@ import EarlyWarning from '@/components/EarlyWarning'
 import SetEarlyWarning from '@/components/EarlyWarning/setEarlyWarning'
 import CrowdPackModal from '../../components/crowdPackModal'
 import './index.less'
+import AdIdSearch from './adIdSearch'
 
 type Props = {
     accountId?: string,
@@ -584,6 +585,11 @@ const Ad: React.FC<Props> = (props) => {
                     <Col>
                         <EarlyWarning />
                     </Col>
+                    <Col>
+                        <AdIdSearch userId={userId} onChange={(e) => {
+                            getList({ ...queryFrom, pageNum: 1, adgroupIdList: e })
+                        }}/>
+                    </Col>
                 </Row>
             </Space>}
             rowSelection={{

+ 45 - 0
src/pages/launchSystemNew/adq/ad/searchSelect.tsx

@@ -0,0 +1,45 @@
+import { allPlanProps } from "@/services/adMonitor/adMonitor"
+import { DownOutlined } from "@ant-design/icons"
+import { DatePicker, Input, Popover, Space } from "antd"
+import React from "react"
+import style from './index.less'
+import moment from "moment"
+
+
+interface Props {
+    queryFrom: allPlanProps,
+    setQueryForm: React.Dispatch<React.SetStateAction<allPlanProps>>
+}
+
+const SearchSelect: React.FC<Props> = ({ queryFrom, setQueryForm }) => {
+
+    /****************************************/
+
+    /****************************************/
+    // 设置创建时间
+    const setUnix = ([str, end]: string[]) => {
+        if (str && end) {
+            setQueryForm({ ...queryFrom, pageNum: 1, createStartTime: moment(str).format('YYYY-MM-DD'), createEndTime: moment(end).format('YYYY-MM-DD') })
+        } else {
+            const { createStartTime, createEndTime, ...newQueyFor } = queryFrom
+            setQueryForm({ ...newQueyFor, pageNum: 1 })
+        }
+    }
+
+    return <div>
+        <Popover placement="topRight" trigger={['click']} content={<Space wrap className={style.more}>
+            <Input style={{ width: 160 }} placeholder="请输入计划名称或ID" allowClear value={queryFrom?.campaign} onChange={(e) => { setQueryForm({ ...queryFrom, pageNum: 1, campaign: e.target.value }) }} />
+            <Input style={{ width: 160 }} placeholder="请输入广告名称或ID" allowClear value={queryFrom?.adgroup} onChange={(e) => { setQueryForm({ ...queryFrom, pageNum: 1, adgroup: e.target.value }) }} />
+            <Input style={{ width: 160 }} placeholder="请输入创意ID" allowClear value={queryFrom?.creativeId} onChange={(e) => { setQueryForm({ ...queryFrom, pageNum: 1, creativeId: e.target.value }) }} />
+            <DatePicker.RangePicker style={{ width: 245 }} placeholder={['数据开始日期', '数据结束日期']} onChange={(mo: any, str: string[]) => { setQueryForm({ ...queryFrom, pageNum: 1, dataStartTime: str[0], dataEndTime: str[1] }) }} value={(queryFrom?.dataStartTime && queryFrom?.dataEndTime ? [moment(queryFrom?.dataStartTime), moment(queryFrom?.dataEndTime)] : null) as any} />
+            <DatePicker.RangePicker style={{ width: 245 }} placeholder={['创建开始日期', '创建结束日期']} onChange={(mo: any, str: string[]) => { setUnix(str) }} value={(queryFrom?.createStartTime && queryFrom?.createEndTime ? [moment(queryFrom?.createStartTime), moment(queryFrom?.createEndTime)] : null) as any} />
+        </Space>}>
+            <a onClick={(e) => e.preventDefault()}>
+                <Space>更多<DownOutlined /></Space>
+            </a>
+        </Popover>
+    </div>
+}
+
+
+export default React.memo(SearchSelect)