update SearchMonitor

This commit is contained in:
shiyang 2020-11-25 01:06:19 +08:00
parent c45f58e49a
commit 688005a8a7
5 changed files with 518 additions and 25 deletions

View File

@ -42,6 +42,16 @@ export default [
name: 'search',
component: './Dashboard/SearchMonitor',
},
// {
// path: '/platform/analysis',
// name: 'analysis',
// component: './Dashboard/Analysis',
// },
// {
// path: '/platform/monitor',
// name: 'monitor',
// component: './Dashboard/Monitor',
// },
]
},

View File

@ -38,6 +38,132 @@ for (let i = 0; i < 50; i += 1) {
status: Math.floor((Math.random() * 10) % 2),
});
}
const searchDataBaseTerms = [{
"name": "北京",
"value": Math.floor((Math.random() * 1000)),
"category": "城市"
}, {
"name": "广州",
"value": Math.floor((Math.random() * 1000)),
"category": "城市"
}, {
"name": "深圳",
"value": Math.floor((Math.random() * 1000)),
"category": "城市"
}, {
"name": "长沙",
"value": Math.floor((Math.random() * 1000)),
"category": "城市"
}, {
"name": "上海",
"value": Math.floor((Math.random() * 1000)),
"category": "城市"
}, {
"name": "成都",
"value": Math.floor((Math.random() * 1000)),
"category": "城市"
}, {
"name": "哈尔滨",
"value": Math.floor((Math.random() * 1000)),
"category": "城市"
}, {
"name": "海口",
"value": Math.floor((Math.random() * 1000)),
"category": "城市"
}, {
"name": "青岛",
"value": Math.floor((Math.random() * 1000)),
"category": "城市"
}, {
"name": "G71",
"value": Math.floor((Math.random() * 1000)),
"category": "车次"
}, {
"name": "G121",
"value": Math.floor((Math.random() * 1000)),
"category": "车次"
}, {
"name": "T109",
"value": Math.floor((Math.random() * 1000)),
"category": "车次"
}, {
"name": "K81",
"value": Math.floor((Math.random() * 1000)),
"category": "车次"
}, {
"name": "Z13",
"value": Math.floor((Math.random() * 1000)),
"category": "车次"
}, {
"name": "Z121",
"value": Math.floor((Math.random() * 1000)),
"category": "车次"
}, {
"name": "G431",
"value": Math.floor((Math.random() * 1000)),
"category": "车次"
}, {
"name": "退票",
"value": Math.floor((Math.random() * 1000)),
"category": "票务"
}, {
"name": "春运",
"value": Math.floor((Math.random() * 1000)),
"category": "票务"
}, {
"name": "学生票",
"value": Math.floor((Math.random() * 1000)),
"category": "票务"
}, {
"name": "二等座",
"value": Math.floor((Math.random() * 1000)),
"category": "其他"
}, {
"name": "订餐",
"value": Math.floor((Math.random() * 1000)),
"category": "其他"
}];
const searchDataInfini = [];
for (let i = 0; i < searchDataBaseTerms.length; i += 1) {
searchDataInfini.push({
index: i + 1,
keyword: `${searchDataBaseTerms[i].name}`,
count: Math.floor(Math.random() * 1000),
range: Math.floor(Math.random() * 100),
status: Math.floor((Math.random() * 10) % 2),
});
}
const docTypeDataInfini = [
{
x: 'user',
y: 39274,
},
{
x: 'city',
y: 31008,
},
{
x: 'train',
y: 27610,
},
{
x: 'news',
y: 19302,
},
{
x: 'order',
y: 17624,
},
{
x: 'other',
y: 12900,
},
];
const salesTypeData = [
{
x: '家用电器',
@ -189,6 +315,8 @@ const getFakeChartData = {
salesTypeDataOnline,
salesTypeDataOffline,
radarData,
searchDataInfini,
docTypeDataInfini,
};
export default {

View File

@ -112,7 +112,7 @@ class GatewayMonitor extends PureComponent {
bodyStyle={{ padding: '30px 0 10px' }}
style={{ marginTop: 32 }}
>
<Chart height={400} data={chartDataIndex} scale={cols} forceFit>
<Chart height={300} data={chartDataIndex} scale={cols} forceFit>
<h3 className='main-title' style={styles.mainTitle}>
索引QPS
</h3>
@ -146,7 +146,7 @@ class GatewayMonitor extends PureComponent {
style={{ marginTop: 32 }}
>
<div style={{ padding: '0 24px' }}>
<Chart height={400} data={chartDataQuery} scale={cols} forceFit>
<Chart height={300} data={chartDataQuery} scale={cols} forceFit>
<h3 className='main-title' style={styles.mainTitle}>
查询QPS
</h3>
@ -183,7 +183,7 @@ class GatewayMonitor extends PureComponent {
bodyStyle={{ padding: '30px 0 10px' }}
style={{ marginTop: 32 }}
>
<Chart height={400} data={chartDataGateway} scale={cols} forceFit>
<Chart height={300} data={chartDataGateway} scale={cols} forceFit>
<h3 className='main-title' style={styles.mainTitle}>
网关写入QPS
</h3>
@ -217,7 +217,7 @@ class GatewayMonitor extends PureComponent {
style={{ marginTop: 32 }}
>
<div style={{ padding: '0 24px' }}>
<Chart height={400} data={chartDataTop} scale={cols} forceFit>
<Chart height={300} data={chartDataTop} scale={cols} forceFit>
<h3 className='main-title' style={styles.mainTitle}>
Top用户统计
</h3>

View File

@ -143,7 +143,7 @@ class TagCloud extends PureComponent {
dv.transform({
type: "tag-cloud",
fields: ["name", "value"],
size: [300, 200],
size: [400, 300],
font: "Verdana",
padding: 0,
timeInterval: 5000,// max execute time
@ -176,7 +176,7 @@ class TagCloud extends PureComponent {
<Chart
// height={window.innerHeight}
width={window.innerWidth}
height={200}
height={248}
data={dv}
scale={scale}
padding={0}

View File

@ -1,6 +1,7 @@
import React, { PureComponent } from 'react';
import GridContent from '@/components/PageHeaderWrapper/GridContent';
import React, { Component } from 'react';
import { connect } from 'dva';
import { formatMessage, FormattedMessage } from 'umi/locale';
import numeral from 'numeral';
import {
Row,
Col,
@ -10,16 +11,32 @@ import {
Table,
Radio,
DatePicker,
Tooltip,
Menu,
Dropdown,
} from 'antd';
import NumberInfo from '@/components/NumberInfo';
import {
ChartCard,
MiniArea,
MiniBar,
MiniProgress,
Field,
Bar,
Pie,
TimelineChart,
} from '@/components/Charts';
import Trend from '@/components/Trend';
import GridContent from '@/components/PageHeaderWrapper/GridContent';
import Yuan from '@/utils/Yuan';
import { getTimeDistance } from '@/utils/utils';
import _ from 'lodash';
import {
G2,
Chart,
Geom,
Axis,
Tooltip,
Coord,
Label,
Legend,
@ -34,17 +51,333 @@ import Slider from 'bizcharts-plugin-slider';
import UserStat from './Search/UserStat';
import TagCloud from './Search/TagCloud';
import styles from "./Monitor.less";
import styles from './Analysis.less';
const { TabPane } = Tabs;
const { RangePicker } = DatePicker;
class SearchMonitor extends PureComponent {
const rankingListData = [];
for (let i = 0; i < 7; i += 1) {
rankingListData.push({
title: `工专路 ${i} 号店`,
total: 323234,
});
}
@connect(({ chart, loading }) => ({
chart,
loading: loading.effects['chart/fetch'],
}))
class SearchMonitor extends Component {
constructor(props) {
super(props);
this.rankingListData = [];
for (let i = 0; i < 7; i += 1) {
this.rankingListData.push({
title: formatMessage({ id: 'app.analysis.test' }, { no: i }),
total: 323234,
});
}
}
state = {
salesType: 'all',
currentTabKey: '',
rangePickerValue: getTimeDistance('year'),
loading: true,
};
componentDidMount() {
const { dispatch } = this.props;
this.reqRef = requestAnimationFrame(() => {
dispatch({
type: 'chart/fetch',
});
this.timeoutId = setTimeout(() => {
this.setState({
loading: false,
});
}, 600);
});
}
componentWillUnmount() {
const { dispatch } = this.props;
dispatch({
type: 'chart/clear',
});
cancelAnimationFrame(this.reqRef);
clearTimeout(this.timeoutId);
}
handleChangeSalesType = e => {
this.setState({
salesType: e.target.value,
});
};
handleTabChange = key => {
this.setState({
currentTabKey: key,
});
};
handleRangePickerChange = rangePickerValue => {
const { dispatch } = this.props;
this.setState({
rangePickerValue,
});
dispatch({
type: 'chart/fetchSalesData',
});
};
selectDate = type => {
const { dispatch } = this.props;
this.setState({
rangePickerValue: getTimeDistance(type),
});
dispatch({
type: 'chart/fetchSalesData',
});
};
isActive(type) {
const { rangePickerValue } = this.state;
const value = getTimeDistance(type);
if (!rangePickerValue[0] || !rangePickerValue[1]) {
return '';
}
if (
rangePickerValue[0].isSame(value[0], 'day') &&
rangePickerValue[1].isSame(value[1], 'day')
) {
return styles.currentDate;
}
return '';
}
render() {
const { rangePickerValue, salesType, loading: propsLoding, currentTabKey } = this.state;
const { chart, loading: stateLoading } = this.props;
const {
visitData,
visitData2,
salesData,
searchData,
searchDataInfini,
offlineData,
offlineChartData,
salesTypeData,
docTypeDataInfini,
salesTypeDataOnline,
salesTypeDataOffline,
} = chart;
const loading = propsLoding || stateLoading;
let salesPieData = docTypeDataInfini;
const menu = (
<Menu>
<Menu.Item>操作一</Menu.Item>
<Menu.Item>操作二</Menu.Item>
</Menu>
);
const iconGroup = (
<span className={styles.iconGroup}>
<Dropdown overlay={menu} placement="bottomRight">
<Icon type="ellipsis" />
</Dropdown>
</span>
);
const salesExtra = (
<div className={styles.salesExtraWrap}>
<div className={styles.salesExtra}>
<a className={this.isActive('today')} onClick={() => this.selectDate('today')}>
<FormattedMessage id="app.analysis.all-day" defaultMessage="All Day" />
</a>
<a className={this.isActive('week')} onClick={() => this.selectDate('week')}>
<FormattedMessage id="app.analysis.all-week" defaultMessage="All Week" />
</a>
<a className={this.isActive('month')} onClick={() => this.selectDate('month')}>
<FormattedMessage id="app.analysis.all-month" defaultMessage="All Month" />
</a>
<a className={this.isActive('year')} onClick={() => this.selectDate('year')}>
<FormattedMessage id="app.analysis.all-year" defaultMessage="All Year" />
</a>
</div>
<RangePicker
value={rangePickerValue}
onChange={this.handleRangePickerChange}
style={{ width: 256 }}
/>
</div>
);
const columns = [
{
title: <FormattedMessage id="app.analysis.table.rank" defaultMessage="Rank" />,
dataIndex: 'index',
key: 'index',
},
{
title: (
<FormattedMessage
id="app.analysis.table.search-keyword"
defaultMessage="Search keyword"
/>
),
dataIndex: 'keyword',
key: 'keyword',
render: text => <a href="/">{text}</a>,
},
{
title: <FormattedMessage id="app.analysis.table.users" defaultMessage="Users" />,
dataIndex: 'count',
key: 'count',
sorter: (a, b) => a.count - b.count,
className: styles.alignRight,
},
{
title: (
<FormattedMessage id="app.analysis.table.weekly-range" defaultMessage="Weekly Range" />
),
dataIndex: 'range',
key: 'range',
sorter: (a, b) => a.range - b.range,
render: (text, record) => (
<Trend flag={record.status === 1 ? 'down' : 'up'}>
<span style={{ marginRight: 4 }}>{text}%</span>
</Trend>
),
align: 'right',
},
];
const activeKey = currentTabKey || (offlineData[0] && offlineData[0].name);
const CustomTab = ({ data, currentTabKey: currentKey }) => (
<Row gutter={8} style={{ width: 138, margin: '8px 0' }}>
<Col span={12}>
<NumberInfo
title={data.name}
subTitle={
<FormattedMessage
id="app.analysis.conversion-rate"
defaultMessage="Conversion Rate"
/>
}
gap={2}
total={`${data.cvr * 100}%`}
theme={currentKey !== data.name && 'light'}
/>
</Col>
<Col span={12} style={{ paddingTop: 36 }}>
<Pie
animate={false}
color={currentKey !== data.name && '#BDE4FF'}
inner={0.55}
tooltip={false}
margin={[0, 0, 0, 0]}
percent={data.cvr * 100}
height={64}
/>
</Col>
</Row>
);
const topColResponsiveProps = {
xs: 24,
sm: 12,
md: 12,
lg: 12,
xl: 6,
style: { marginBottom: 24 },
};
return (
<GridContent>
<Row gutter={24}>
<Col xl={8} lg={12} md={24} sm={24} xs={24}>
<Col xl={12} lg={24} md={24} sm={24} xs={24}>
<Card
loading={loading}
bordered={false}
title="热词搜索"
style={{ marginTop: 0 }}
>
<Row gutter={68}>
<Col sm={12} xs={24} style={{ marginBottom: 24 }}>
<NumberInfo
subTitle={
<span>
<FormattedMessage
id="app.analysis.search-users"
defaultMessage="search users"
/>
<Tooltip
title={
<FormattedMessage
id="app.analysis.introduce"
defaultMessage="introduce"
/>
}
>
<Icon style={{ marginLeft: 8 }} type="info-circle-o" />
</Tooltip>
</span>
}
gap={8}
total={numeral(8371).format('0,0')}
status="up"
subTotal={17.1}
/>
<MiniArea line height={45} data={visitData2} />
</Col>
<Col sm={12} xs={24} style={{ marginBottom: 24 }}>
<NumberInfo
subTitle={
<span>
<FormattedMessage
id="app.analysis.per-capita-search"
defaultMessage="Per Capita Search"
/>
<Tooltip
title={
<FormattedMessage
id="app.analysis.introduce"
defaultMessage="introduce"
/>
}
>
<Icon style={{ marginLeft: 8 }} type="info-circle-o" />
</Tooltip>
</span>
}
total={2.7}
status="down"
subTotal={26.2}
gap={8}
/>
<MiniArea line height={45} data={visitData2} />
</Col>
</Row>
<Table
rowKey={record => record.index}
size="small"
columns={columns}
dataSource={searchDataInfini}
pagination={{
style: { marginBottom: 0 },
pageSize: 5,
}}
/>
</Card>
</Col>
<Col xl={12} lg={24} md={24} sm={24} xs={24}>
<Card
title="用户统计"
loading={false}
@ -54,31 +387,53 @@ class SearchMonitor extends PureComponent {
<UserStat></UserStat>
</Card>
</Col>
<Col xl={8} lg={12} md={24} sm={24} xs={24}>
<Card
title="热门搜索"
loading={false}
bordered={false}
bodyStyle={{ overflow: 'hidden' }}
>
<TagCloud>
</Row>
<Row gutter={24}>
{/*<Col xl={8} lg={12} md={24} sm={24} xs={24}>*/}
{/* <Card*/}
{/* title="热门搜索"*/}
{/* loading={false}*/}
{/* bordered={false}*/}
{/* bodyStyle={{ overflow: 'hidden' }}*/}
{/* >*/}
{/* <TagCloud>*/}
</TagCloud>
</Card>
</Col>
<Col xl={8} lg={12} md={24} sm={24} xs={24}>
{/* </TagCloud>*/}
{/* </Card>*/}
{/*</Col>*/}
<Col xl={12} lg={24} md={24} sm={24} xs={24}>
<Card
title="新词"
loading={false}
bordered={false}
bodyStyle={{ overflow: 'hidden' }}
style={{ marginTop: 24 }}
>
<TagCloud>
</TagCloud>
</Card>
</Col>
<Col xl={12} lg={24} md={24} sm={24} xs={24}>
<Card
loading={loading}
bordered={false}
title="TOP索引占比"
style={{ marginTop: 24 }}
>
<Pie
hasLegend
subTitle="TOP INDEX"
total={() => {salesPieData.reduce((pre, now) => now.y + pre, 0)}}
data={salesPieData}
valueFormat={value => {value}}
height={248}
lineWidth={4}
/>
</Card>
</Col>
</Row>
</GridContent>
);
}