|
@ -1,19 +1,30 @@ |
|
|
import { advList } from '@/services/matrix/admin'; |
|
|
import { |
|
|
import { PageContainer, ProColumns, ProTable } from '@ant-design/pro-components'; |
|
|
PageContainer, |
|
|
|
|
|
ProColumns, |
|
|
|
|
|
ProFormDateRangePicker, |
|
|
|
|
|
ProFormSelect, |
|
|
|
|
|
ProTable, |
|
|
|
|
|
QueryFilter, |
|
|
|
|
|
StatisticCard, |
|
|
|
|
|
} from '@ant-design/pro-components'; |
|
|
import { useIntl, useModel } from '@umijs/max'; |
|
|
import { useIntl, useModel } from '@umijs/max'; |
|
|
import { Tabs } from 'antd'; |
|
|
import { Divider, Tabs } from 'antd'; |
|
|
import TabPane from 'antd/es/tabs/TabPane'; |
|
|
import TabPane from 'antd/es/tabs/TabPane'; |
|
|
|
|
|
import RcResizeObserver from 'rc-resize-observer'; |
|
|
import React, { useEffect, useRef, useState } from 'react'; |
|
|
import React, { useEffect, useRef, useState } from 'react'; |
|
|
import { useParams } from 'react-router-dom'; |
|
|
import { useParams } from 'react-router-dom'; |
|
|
|
|
|
import { advList } from '../services/matrix/admin'; |
|
|
// import { RequestOptionsType, ProFieldRequestData } from "@ant-design/pro-utils";
|
|
|
// import { RequestOptionsType, ProFieldRequestData } from "@ant-design/pro-utils";
|
|
|
|
|
|
|
|
|
import { deviceList, offline } from '@/services/matrix/device'; |
|
|
import { deviceList, incomeDaily1, incomeOverview1, offline } from '@/services/matrix/device'; |
|
|
|
|
|
import { Column } from '@ant-design/charts'; |
|
|
import type { ActionType } from '@ant-design/pro-components'; |
|
|
import type { ActionType } from '@ant-design/pro-components'; |
|
|
|
|
|
import moment from 'moment'; |
|
|
const DeviceOwnerApp: React.FC = () => { |
|
|
const DeviceOwnerApp: React.FC = () => { |
|
|
const actionRef = useRef<ActionType>(); |
|
|
const actionRef = useRef<ActionType>(); |
|
|
const deviceRef = useRef<ActionType>(); |
|
|
const deviceRef = useRef<ActionType>(); |
|
|
const [usedDeviceCnt, setUsedDeviceCnt] = useState(0); |
|
|
const [usedDeviceCnt, setUsedDeviceCnt] = useState(0); |
|
|
|
|
|
const [responsive, setResponsive] = useState(false); |
|
|
/** |
|
|
/** |
|
|
* @en-US International configuration |
|
|
* @en-US International configuration |
|
|
* @zh-CN 国际化配置 |
|
|
* @zh-CN 国际化配置 |
|
@ -23,6 +34,8 @@ const DeviceOwnerApp: React.FC = () => { |
|
|
|
|
|
|
|
|
const { initialState } = useModel('@@initialState'); |
|
|
const { initialState } = useModel('@@initialState'); |
|
|
const currentUser = initialState?.currentUser; |
|
|
const currentUser = initialState?.currentUser; |
|
|
|
|
|
const [overview, setOverview] = useState<API.OverviewBo>(); |
|
|
|
|
|
const [daily, setDaily] = useState<API.DateIncome[]>([]); |
|
|
|
|
|
|
|
|
const fetchDevice = async () => { |
|
|
const fetchDevice = async () => { |
|
|
const res = await deviceList({ appCode: code ? code : '' }); |
|
|
const res = await deviceList({ appCode: code ? code : '' }); |
|
@ -197,11 +210,70 @@ const DeviceOwnerApp: React.FC = () => { |
|
|
}; |
|
|
}; |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
const fetchOverview = async () => { |
|
|
|
|
|
const res = await incomeOverview1({ appCode: code }); |
|
|
|
|
|
if (res.data) { |
|
|
|
|
|
setOverview(res.data); |
|
|
|
|
|
} |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
const fetchDaily = async (params: API.IncomeQuery | undefined) => { |
|
|
|
|
|
const res = await incomeDaily1({ ...params, code: code }); |
|
|
|
|
|
if (res.data) { |
|
|
|
|
|
setDaily(res.data); |
|
|
|
|
|
} |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
useEffect(() => { |
|
|
useEffect(() => { |
|
|
actionRef.current?.reload(); |
|
|
actionRef.current?.reload(); |
|
|
deviceRef.current?.reload(); |
|
|
deviceRef.current?.reload(); |
|
|
|
|
|
fetchOverview(); |
|
|
|
|
|
fetchDaily(undefined); |
|
|
}, [code]); |
|
|
}, [code]); |
|
|
|
|
|
|
|
|
|
|
|
const formatIncome = (v: number | undefined) => { |
|
|
|
|
|
if (!v) { |
|
|
|
|
|
return 0; |
|
|
|
|
|
} |
|
|
|
|
|
return parseFloat((v / 1000_00).toFixed(2)); |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
const processedChartData: { date: string | number; income: number }[] = daily.map((item) => ({ |
|
|
|
|
|
date: (() => { |
|
|
|
|
|
const inputDateStr = item.date + ''; |
|
|
|
|
|
const year: string = inputDateStr.slice(0, 4); |
|
|
|
|
|
const month: string = inputDateStr.slice(4, 6); |
|
|
|
|
|
const day: string = inputDateStr.slice(6, 8); |
|
|
|
|
|
|
|
|
|
|
|
return `${year}-${month}-${day}`; |
|
|
|
|
|
})(), |
|
|
|
|
|
income: formatIncome(item.income), |
|
|
|
|
|
})); |
|
|
|
|
|
|
|
|
|
|
|
const config = { |
|
|
|
|
|
data: processedChartData, |
|
|
|
|
|
xField: 'date', |
|
|
|
|
|
yField: 'income', |
|
|
|
|
|
tooltip: { |
|
|
|
|
|
name: '收入', |
|
|
|
|
|
field: 'income', |
|
|
|
|
|
}, |
|
|
|
|
|
axis: { |
|
|
|
|
|
date: { |
|
|
|
|
|
title: '日期', |
|
|
|
|
|
}, |
|
|
|
|
|
}, |
|
|
|
|
|
title: |
|
|
|
|
|
'累计' + |
|
|
|
|
|
formatIncome(daily.reduce((acc, data) => acc + (data.income ? data.income : 0), 0)) + |
|
|
|
|
|
'元', |
|
|
|
|
|
height: 400, |
|
|
|
|
|
label: { |
|
|
|
|
|
text: (d: any) => (d.income > 0 ? d.income : ''), |
|
|
|
|
|
textBaseline: 'bottom', |
|
|
|
|
|
}, |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
return ( |
|
|
return ( |
|
|
<PageContainer> |
|
|
<PageContainer> |
|
|
<Tabs defaultActiveKey="1" centered style={{ backgroundColor: 'white', padding: '20px' }}> |
|
|
<Tabs defaultActiveKey="1" centered style={{ backgroundColor: 'white', padding: '20px' }}> |
|
@ -235,6 +307,72 @@ const DeviceOwnerApp: React.FC = () => { |
|
|
columns={columns} |
|
|
columns={columns} |
|
|
/> |
|
|
/> |
|
|
</TabPane> |
|
|
</TabPane> |
|
|
|
|
|
<TabPane tab="数据总览" key="3"> |
|
|
|
|
|
<RcResizeObserver |
|
|
|
|
|
key="resize-observer" |
|
|
|
|
|
onResize={(offset) => { |
|
|
|
|
|
setResponsive(offset.width < 596); |
|
|
|
|
|
}} |
|
|
|
|
|
> |
|
|
|
|
|
<StatisticCard> |
|
|
|
|
|
<StatisticCard.Group direction={responsive ? 'column' : 'row'}> |
|
|
|
|
|
<StatisticCard |
|
|
|
|
|
statistic={{ |
|
|
|
|
|
title: '上月收入(元)', |
|
|
|
|
|
value: formatIncome(overview?.lastMonthIncome), |
|
|
|
|
|
}} |
|
|
|
|
|
/> |
|
|
|
|
|
<Divider type={responsive ? 'horizontal' : 'vertical'} /> |
|
|
|
|
|
<StatisticCard |
|
|
|
|
|
statistic={{ |
|
|
|
|
|
title: '本月收入(元)', |
|
|
|
|
|
value: formatIncome(overview?.thisMonthIncome), |
|
|
|
|
|
}} |
|
|
|
|
|
/> |
|
|
|
|
|
<Divider type={responsive ? 'horizontal' : 'vertical'} /> |
|
|
|
|
|
<StatisticCard |
|
|
|
|
|
statistic={{ |
|
|
|
|
|
title: '今日收入(元)', |
|
|
|
|
|
value: formatIncome(overview?.todayIncome), |
|
|
|
|
|
}} |
|
|
|
|
|
/> |
|
|
|
|
|
<Divider type={responsive ? 'horizontal' : 'vertical'} /> |
|
|
|
|
|
<StatisticCard |
|
|
|
|
|
statistic={{ |
|
|
|
|
|
title: '昨日收入(元)', |
|
|
|
|
|
value: formatIncome(overview?.yesterdayIncome), |
|
|
|
|
|
}} |
|
|
|
|
|
/> |
|
|
|
|
|
</StatisticCard.Group> |
|
|
|
|
|
</StatisticCard> |
|
|
|
|
|
</RcResizeObserver> |
|
|
|
|
|
|
|
|
|
|
|
<QueryFilter defaultCollapsed split onFinish={fetchDaily}> |
|
|
|
|
|
<ProFormSelect |
|
|
|
|
|
label="平台" |
|
|
|
|
|
name="platform" |
|
|
|
|
|
valueEnum={{ |
|
|
|
|
|
1: '穿山甲', |
|
|
|
|
|
2: '腾讯', |
|
|
|
|
|
3: '百度联盟', |
|
|
|
|
|
4: 'Mintegral', |
|
|
|
|
|
5: '快手', |
|
|
|
|
|
6: '游可赢', |
|
|
|
|
|
7: 'Sigmob', |
|
|
|
|
|
8: 'Admob', |
|
|
|
|
|
}} |
|
|
|
|
|
/> |
|
|
|
|
|
<ProFormDateRangePicker |
|
|
|
|
|
fieldProps={{ |
|
|
|
|
|
disabledDate: (current: any) => current && current >= moment().startOf('day'), |
|
|
|
|
|
}} |
|
|
|
|
|
name="date" |
|
|
|
|
|
label="时间" |
|
|
|
|
|
/> |
|
|
|
|
|
</QueryFilter> |
|
|
|
|
|
{/* <Line {...config} /> */} |
|
|
|
|
|
<Column {...config} /> |
|
|
|
|
|
</TabPane> |
|
|
</Tabs> |
|
|
</Tabs> |
|
|
</PageContainer> |
|
|
</PageContainer> |
|
|
); |
|
|
); |
|
|