123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474 |
- import { Button, Card, Input, Radio, RadioChangeEvent, Select, Space, Spin, Tag, TimePicker, Tooltip } from "antd";
- import React, { useCallback, useEffect, useState } from "react";
- import { CloudDownloadOutlined, ColumnHeightOutlined, ColumnWidthOutlined, EyeInvisibleOutlined, EyeOutlined, RedoOutlined } from "@ant-design/icons";
- import useEcharts from '@/Hook/useEcharts'
- import columnsMonitor from './tableMonitorConfig'
- import { useModel } from 'umi'
- import { ListType, downLoadUpAdApi, downLoadDetailApi, downLoadDetailMinuteApi } from '@/services/adMonitor/adMonitor'
- import { qiliangpaihang, qiliangpaihanghour, qiliangpaihangminute } from './config'
- import { compare } from '@/utils/utils'
- import PlanDetail from './components/planDetail'
- import { formatDate, downloadFile1 } from '@/utils/downloadFile'
- import './table.less'
- import moment from "moment";
- import TableData from "@/pages/launchSystemNew/components/TableData";
- interface newListType extends ListType {
- totalTimeUnit: 'minute' | 'hour' | 'day',
- planTimeUnit: 'minute' | 'hour' | 'day'
- }
- /**
- * 今日起量监控
- * @param props
- * @returns
- */
- function Monitor(props: { onChange: () => void }) {
- const { onChange } = props
- const { getPlanList, getTotalCost, getPlanCost, getPlanDetailList, getMinuteList, getAdqAccountList } = useModel('useAdMonitor.useMonitor')
- const { getPicherList } = useModel('useOperating.useWxGroupList')
- // 变量开始
- const [queryForm, setQueryForm] = useState<newListType>({ totalTimeUnit: 'day', planTimeUnit: 'hour', sysUserId: JSON.parse(sessionStorage.getItem('SYSUSERID') || '[]'), pageNum: 1, pageSize: 20 }) // 搜索变量//startTime: moment().format('YYYY-MM-DD'), endTime: moment().format('YYYY-MM-DD'),
- const { BarMonitor, LineMonitor } = useEcharts()
- const [barDis, setBarDis] = useState<any[]>([])
- const [lineDis, setLineDis] = useState<any[]>([])
- const [lineTitle, setLineTitle] = useState<string>('广告总消耗趋势')
- const [mode, setMode] = useState<string>('total') // 总/明细
- const [px, setPx] = useState<boolean>(false)//设置顶部图形的排列方式
- const [planDetailList, setPlanDetailList] = useState<any[]>([])
- const [minuteList, setMinuteList] = useState<any[]>([])
- const [visible, setVisible] = useState<boolean>(false) // 详情弹窗控制
- const [aId, setAId] = useState<any>()
- const [downLoadLoading, setDownLoadLoading] = useState<boolean>(false)
- const [hour, setHour] = useState<any>()
- const [clickAccountId, setClickAccountId] = useState<number[]>([])
- const [showEacharts, setShowEacharts] = useState<boolean>(true)
- const { totalTimeUnit, planTimeUnit, adgroup, accountId, sysUserId, pageNum, pageSize, campaign, sortField, sort } = queryForm
- // 变量结束
- // 获取投手
- useEffect(() => {
- !getPicherList.data && getPicherList.run()
- }, [])
- // 获取广告账号
- useEffect(() => {
- !getAdqAccountList.data && getAdqAccountList.run()
- }, [])
- // // 获取排行数据,柱图
- useEffect(() => {
- getPlanCostList()
- }, [totalTimeUnit, accountId, sysUserId])
- // 获取今日计划总消耗图谱,折线
- useEffect(() => {
- getTootalCostList()
- }, [planTimeUnit, adgroup, accountId, sysUserId])
- // 获取起量计划列表 底部table
- useEffect(() => {
- if (mode === 'total') {
- getList()
- }
- }, [accountId, sysUserId, pageNum, pageSize, campaign, adgroup, sortField, sort, mode, hour])
- // 获取起量明细表 点击
- useEffect(() => {
- if (!adgroup) {
- setMode('total')//切到总表
- }
- }, [adgroup])
- /** 获取折线图 */
- const getTootalCostList = useCallback(async () => {
- let { totalTimeUnit, planTimeUnit, pageNum, pageSize, adgroup, sysUserId, accountId, ...newQueryForm } = queryForm
- let params = adgroup ? { ...newQueryForm, adgroupId: adgroup } : newQueryForm
- let newPitcherIds = sysUserId?.join()
- let res = await getTotalCost.run({ ...params, timeUnit: planTimeUnit, sysUserId: newPitcherIds, accountId: accountId?.join() })
- let data: any[] = [{ legendName: '消耗' }]
- res?.data?.totalCostDtoList?.forEach((item: any) => {
- data[0][item.currTime] = item.totalCost
- })
- setLineDis(() => data)
- setLineTitle(() => res?.data?.adName ? res?.data?.adName + '_消耗趋势' : '广告总消耗趋势')
- }, [queryForm, lineDis])
- /** 获取柱状图 */
- const getPlanCostList = useCallback(async () => {
- let { totalTimeUnit, planTimeUnit, pageNum, pageSize, sysUserId, accountId, ...newQueryForm } = queryForm
- let { adgroup, ...planQueryFrom } = newQueryForm
- let newPitcherIds = sysUserId?.join()
- let res = await getPlanCost.run({ ...planQueryFrom, timeUnit: totalTimeUnit, sysUserId: newPitcherIds, accountId: accountId?.join() })
- let data = res?.data?.planCostDtoList?.map((item: { adId: number, cost: number, adName: string, accountId: number }) => {
- return { name: item.adId.toString(), value: item.cost, adName: item.adName, accountId: item.accountId }
- })
- data = data?.sort((a: any, b: any) => {
- var value1 = a['value'];
- var value2 = b['value'];
- return value2 - value1;
- })
- setBarDis(() => data)
- }, [queryForm, barDis])
- // 气量Table总表
- const getList = useCallback(() => {
- let { totalTimeUnit, planTimeUnit, timeUnit, sysUserId, accountId, ...newQueryForm } = queryForm
- getPlanList.run({ ...newQueryForm, sysUserId, accountId, hour })
- }, [queryForm, hour])
- // 起量明细表 点击
- const getDetailList = useCallback((adgroup: any, clickAccountId: any[]) => {
- setClickAccountId(clickAccountId)
- let { totalTimeUnit, planTimeUnit, timeUnit, pageNum, pageSize, adgroup: aa, sysUserId, accountId, ...newQueryForm } = queryForm
- if (adgroup) {
- setMode('detail')//切到明细
- getPlanDetailList.run({ ...newQueryForm, adgroupId: adgroup, sysUserId, accountId: accountId ? accountId : clickAccountId }).then((res: any) => {
- setPlanDetailList(res?.data ? [...res?.data] : [])
- if (adgroup != aa) {
- setQueryForm({ ...queryForm, adgroup })
- }
- })
- }
- }, [queryForm, getPlanList, planDetailList])
- // 详情
- const details = (data: any) => {
- setAId(data)
- setVisible(true)
- }
- // 起量5min表
- const getMinuList = useCallback((adgroup: any, clickAccountId: any[]) => {
- setClickAccountId(clickAccountId)
- let { totalTimeUnit, planTimeUnit, timeUnit, pageNum, pageSize, adgroup: aa, sysUserId, accountId, ...newQueryForm } = queryForm
- if (adgroup) {
- setMode('minute')
- getMinuteList.run({ ...newQueryForm, adgroupId: adgroup, sysUserId, accountId: accountId ? accountId : clickAccountId }).then((res: any) => {
- setMinuteList(res?.data ? [...res?.data] : [])
- if (adgroup != aa) {
- setQueryForm({ ...queryForm, adgroup })
- }
- })
- }
- }, [queryForm, getPlanList, minuteList, adgroup])
- // 计划详情
- const planDetail = (data: any) => {
- sessionStorage.setItem('ADIDORNAME', JSON.stringify(data))
- onChange && onChange()
- }
- //全部接口刷新
- const refresh = () => {
- getPlanList.refresh()
- getTotalCost.refresh()
- getPlanCost.refresh()
- getPlanDetailList.refresh()
- getMinuteList.refresh()
- }
- // 接口自动刷新10分钟一次
- useEffect(() => {
- let time = setInterval(() => {
- refresh()
- }, 1000 * 60 * 10)
- return () => {
- clearInterval(time)
- }
- }, [])
- //图形排列样式改变重新获取数据刷新图形
- const set = useCallback((b) => {
- setPx(b)
- getTotalCost.refresh()
- getPlanCost.refresh()
- }, [getPlanCost, getTotalCost])
- // 下载
- const downLoadExcel = useCallback(() => {
- let ajax: any = null
- let params: any = {}
- let { totalTimeUnit, planTimeUnit, timeUnit, sysUserId, accountId, adgroup, pageNum, pageSize, ...newQueryForm } = queryForm
- switch (mode) {
- case 'total':
- params = { ...newQueryForm, sysUserId, accountId, adgroupId: adgroup }
- ajax = downLoadUpAdApi
- break;
- case 'detail':
- params = { ...newQueryForm, adgroupId: adgroup, accountId }
- ajax = downLoadDetailApi
- break;
- case 'minute':
- params = { ...newQueryForm, adgroupId: adgroup, accountId }
- ajax = downLoadDetailMinuteApi
- break;
- }
- if (ajax) {
- setDownLoadLoading(true)
- ajax(params).then((res: any) => {
- setDownLoadLoading(false)
- downloadFile1(res, 'octet-stream', formatDate(new Date()) + ".xlsx")
- }).catch(() => setDownLoadLoading(false))
- }
- }, [queryForm, mode, downLoadLoading])
- // 处理折线图数据
- const timePickerHandle = async (values: any, formatString: [string, string]) => {
- let res = await getTotalCost.data
- let data: any[] = [{ legendName: '消耗' }]
- res?.data?.totalCostDtoList?.forEach((item: any) => {
- data[0][item.currTime] = item.totalCost
- })
- if (values) {
- let date = moment().format('YYYY-MM-DD')
- let strTime = formatString[0]
- let endTime = formatString[1]
- let dateTimeStr = `${date} ${strTime}:00`
- let dateTimeEnd = `${date} ${endTime}:00`
- let { legendName, ...otherData } = data[0]
- let newData: any = { legendName }
- for (const key in otherData) {
- if (Object.prototype.hasOwnProperty.call(otherData, key)) {
- const value = otherData[key];
- if (moment(dateTimeStr) <= moment(key) && moment(key) <= moment(dateTimeEnd)) {
- newData[key] = value
- }
- }
- }
- setLineDis(() => [newData])
- } else {
- setLineDis(() => data)
- }
- }
- const disabledTime = () => {
- let h = moment().format('H')
- let H: number[] = []
- for (let index = Number(h) + 1; index < 23; index++) {
- H.push(index)
- }
- return {
- disabledHours: () => H
- }
- }
- return <Space direction='vertical' style={{ width: '100%' }} className="monitor">
- <Card hoverable bodyStyle={{ padding: '12px 16px' }}>
- <div style={{ display: 'flex', justifyContent: 'space-between' }}>
- <Space>
- <Select
- showSearch
- value={queryForm.sysUserId}
- style={{ minWidth: 180, maxWidth: 250 }}
- mode='multiple'
- maxTagCount={1}
- allowClear
- placeholder="请选择投手"
- disabled={queryForm?.adgroup || queryForm?.accountId?.length > 0}
- onChange={(value: number[]) => {
- setQueryForm({ ...queryForm, sysUserId: value, pageNum: 1 })
- sessionStorage.setItem('SYSUSERID', value ? JSON.stringify(value) : '')
- if (mode === 'detail') {
- getDetailList(queryForm.adgroup, queryForm?.accountId)
- } else if (mode === 'minute') {
- getMinuList(queryForm.adgroup, queryForm?.accountId)
- }
- }}
- filterOption={(input, option) =>
- (option?.children as any).toLowerCase().indexOf(input.toLowerCase()) >= 0
- }
- >
- {getPicherList?.data?.map((item: { nickname: string, userId: number }, index: number) =>
- <Select.Option
- value={item.userId}
- key={item.userId + '' + index}
- >
- {item.nickname}
- </Select.Option>
- )}
- </Select>
- <Select
- showSearch
- mode='multiple'
- maxTagCount={1}
- value={queryForm.accountId}
- style={{ minWidth: 220, maxWidth: 250 }}
- allowClear
- placeholder="请选择广告账号"
- onChange={(value: number[]) => {
- setQueryForm({ ...queryForm, 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>
- <Input
- value={queryForm.campaign}
- placeholder="计划ID"
- onChange={(e) => {
- let value = e.target.value
- if (!isNaN(Number(value))) {
- setQueryForm({ ...queryForm, campaign: value })
- }
- if (mode === 'detail') {
- getDetailList(queryForm?.adgroup, queryForm?.accountId)
- } else if (mode === 'minute') {
- getMinuList(queryForm?.adgroup, queryForm?.accountId)
- }
- }}
- allowClear
- />
- <Input
- value={queryForm.adgroup}
- placeholder="广告ID"
- onChange={(e) => {
- let value = e.target.value
- if (!isNaN(Number(value))) {
- setQueryForm({ ...queryForm, adgroup: e.target.value })
- }
- if (!value) {
- setClickAccountId([])
- }
- if (mode === 'detail') {
- getDetailList(e.target.value, queryForm?.accountId)
- } else if (mode === 'minute') {
- getMinuList(e.target.value, queryForm?.accountId)
- }
- }}
- allowClear
- />
- </Space>
- <Space>
- <Tag onClick={() => setShowEacharts(!showEacharts)}>{showEacharts ? <><EyeInvisibleOutlined /> 隐藏</> : <><EyeOutlined /> 显示</>}</Tag>
- <Tag color="#2db7f5" onClick={refresh}><RedoOutlined /> 刷新</Tag>
- </Space>
- </div>
- </Card>
- {showEacharts && <Card hoverable bodyStyle={{ padding: '12px 16px' }}>
- <span style={{ position: 'absolute', top: 10, zIndex: 10 }}>
- {px ?
- <Tooltip title='左右排列'><Tag color='#f50' onClick={() => { set(false) }}><ColumnWidthOutlined /><span style={{ fontSize: 10 }}>左右排列</span></Tag></Tooltip>
- :
- <Tooltip title='上下排列'><Tag color='#f50' onClick={() => { set(true) }} ><ColumnHeightOutlined /><span style={{ fontSize: 10 }}>上下排列</span></Tag></Tooltip>
- }
- </span>
- <div className={!px ? 'charts' : 'charts charts100'}>
- <div>
- <div className="selectTime">
- <Space>
- <span style={{ fontSize: 10, color: '#999' }}>刷新时间:{getPlanCost?.data?.reqTime}</span>
- <Radio.Group value={queryForm.totalTimeUnit} buttonStyle="solid" size='small' onChange={(e) => { setQueryForm({ ...queryForm, totalTimeUnit: e.target.value }) }}>
- <Radio.Button value="day">天</Radio.Button>
- <Radio.Button value="hour">小时</Radio.Button>
- <Radio.Button value="minute">5min</Radio.Button>
- </Radio.Group>
- </Space>
- </div>
- {getPlanCost?.loading ? <Spin /> : <BarMonitor style={{ width: '100%', height: '100%' }} data={barDis} xName="今日消耗" yName="广告名称" onChange={(value: string, accountId) => { getDetailList(value, accountId) }} planID={queryForm?.adgroup} />}
- </div>
- <div>
- <div className="selectTime">
- <Space>
- <span style={{ fontSize: 10, color: '#999' }}>刷新时间:{getTotalCost?.data?.reqTime}</span>
- <Radio.Group value={queryForm.planTimeUnit} buttonStyle="solid" size='small' onChange={(e) => { setQueryForm({ ...queryForm, planTimeUnit: e.target.value }) }}>
- <Radio.Button value="hour">小时</Radio.Button>
- <Radio.Button value="minute">5min</Radio.Button>
- </Radio.Group>
- {queryForm.planTimeUnit === 'minute' && <TimePicker.RangePicker
- size="small"
- format='HH:mm'
- minuteStep={5}
- onChange={timePickerHandle}
- />}
- </Space>
- </div>
- {getTotalCost?.loading ? <Spin /> : <LineMonitor style={{ width: '100%', height: '100%' }} series smooth data={lineDis} title={lineTitle} />}
- </div>
- </div>
- </Card>}
- <div className={'MYtable'}>
- <TableData
- bodyStyle={{ padding: '12px 16px' }}
- gutter={[0, 12]}
- columns={columnsMonitor(planDetail, getDetailList, details, getMinuList, mode)}
- dataSource={mode === 'total' ? getPlanList?.data?.data?.records?.map((item: any, index: number) => ({ ...item, id: item.id + '_' + index })) : mode === 'detail' ? getPlanDetailList?.data?.data : getMinuteList?.data?.data}
- loading={mode === 'total' ? getPlanList?.loading : mode === 'detail' ? getPlanDetailList?.loading : getMinuteList?.loading}
- ajax={mode === 'total' ? getPlanList : mode === 'detail' ? getPlanDetailList : getMinuteList}
- leftChild={
- <Space>
- <Radio.Group onChange={(e: RadioChangeEvent) => {
- let value = e.target.value
- switch (value) {
- case 'total':
- setMode(value)
- break;
- case 'detail':
- getDetailList(queryForm.adgroup, clickAccountId)
- break
- case 'minute':
- getMinuList(queryForm.adgroup, clickAccountId)
- break
- }
- }} value={mode} size='small'>
- <Radio.Button value="total">总</Radio.Button>
- <Radio.Button value="detail" disabled={!adgroup}>小时</Radio.Button>
- <Radio.Button value="minute" disabled={!adgroup}>5min</Radio.Button>
- </Radio.Group>
- {mode === 'total' && <TimePicker disabledTime={disabledTime} size='small' style={{ width: 110 }} onChange={(e) => { setHour(e ? moment(e).format('H') : null) }} format="HH" />}
- <Button size="small" icon={<CloudDownloadOutlined />} loading={downLoadLoading} onClick={downLoadExcel}>{mode === 'total' ? '总表' : mode === 'detail' ? '小时表' : '5min表'}下载</Button>
- </Space>
- }
- fixed={{ left: 0, right: 2 }}
- total={mode === 'total' ? getPlanList?.data?.data?.total : mode === 'detail' ? getPlanDetailList?.data?.data?.length : getMinuteList?.data?.data?.length}
- onChange={mode === 'total' ? (props: any) => {
- let { sortData, pagination } = props
- let { current, pageSize } = pagination
- let newQueryForm = JSON.parse(JSON.stringify(queryForm))
- 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 })
- } : (props: any) => {
- let { sortData } = props
- if (sortData && JSON.stringify(sortData) !== '{}') {
- let { field, order } = sortData // descend 降序 大到小 ascend 升序 小到大 planDetailList
- if (mode === 'detail') {
- getPlanDetailList?.mutate({ data: order ? getPlanDetailList?.data?.data?.sort(compare(field, order)) : [...planDetailList] })
- } else if (mode === 'minute') {
- getMinuteList?.mutate({ data: order ? getMinuteList?.data?.data?.sort(compare(field, order)) : [...minuteList] })
- }
- }
- }}
- page={mode === 'total' ? queryForm.pageNum : undefined}
- pageSize={mode === 'total' ? queryForm.pageSize : undefined}
- scroll={{ y: 750 }}
- config={mode === 'minute' ? qiliangpaihangminute : mode === 'detail' ? qiliangpaihanghour : qiliangpaihang}
- configName={mode === 'total' ? '起量广告排行' : mode === 'detail' ? '起量广告排行明细' : '起量广告5min'}
- />
- </div>
- {visible && <PlanDetail visible={visible} onClose={() => { setVisible(false) }} data={aId} />}
- </Space>
- }
- export default React.memo(Monitor)
|