|
|
|
@ -1,70 +1,28 @@ |
|
|
|
import React, { Component } from 'react'; |
|
|
|
import React, { Component, Suspense } from 'react'; |
|
|
|
import { connect } from 'dva'; |
|
|
|
import { formatMessage, FormattedMessage } from 'umi/locale'; |
|
|
|
import { |
|
|
|
Row, |
|
|
|
Col, |
|
|
|
Icon, |
|
|
|
Card, |
|
|
|
Tabs, |
|
|
|
Table, |
|
|
|
Radio, |
|
|
|
DatePicker, |
|
|
|
Tooltip, |
|
|
|
Menu, |
|
|
|
Dropdown, |
|
|
|
} from 'antd'; |
|
|
|
import { |
|
|
|
ChartCard, |
|
|
|
MiniArea, |
|
|
|
MiniBar, |
|
|
|
MiniProgress, |
|
|
|
Field, |
|
|
|
Bar, |
|
|
|
Pie, |
|
|
|
TimelineChart, |
|
|
|
} from '@/components/Charts'; |
|
|
|
import Trend from '@/components/Trend'; |
|
|
|
import NumberInfo from '@/components/NumberInfo'; |
|
|
|
import numeral from 'numeral'; |
|
|
|
import { Row, Col, Icon, Menu, Dropdown } from 'antd'; |
|
|
|
|
|
|
|
import GridContent from '@/components/PageHeaderWrapper/GridContent'; |
|
|
|
import Yuan from '@/utils/Yuan'; |
|
|
|
import { getTimeDistance } from '@/utils/utils'; |
|
|
|
|
|
|
|
import styles from './Analysis.less'; |
|
|
|
import PageLoading from '@/components/PageLoading'; |
|
|
|
|
|
|
|
const { TabPane } = Tabs; |
|
|
|
const { RangePicker } = DatePicker; |
|
|
|
|
|
|
|
const rankingListData = []; |
|
|
|
for (let i = 0; i < 7; i += 1) { |
|
|
|
rankingListData.push({ |
|
|
|
title: `工专路 ${i} 号店`, |
|
|
|
total: 323234, |
|
|
|
}); |
|
|
|
} |
|
|
|
const IntroduceRow = React.lazy(() => import('./IntroduceRow')); |
|
|
|
const SalesCard = React.lazy(() => import('./SalesCard')); |
|
|
|
const TopSearch = React.lazy(() => import('./TopSearch')); |
|
|
|
const ProportionSales = React.lazy(() => import('./ProportionSales')); |
|
|
|
const OfflineData = React.lazy(() => import('./OfflineData')); |
|
|
|
|
|
|
|
@connect(({ chart, loading }) => ({ |
|
|
|
chart, |
|
|
|
loading: loading.effects['chart/fetch'], |
|
|
|
})) |
|
|
|
class Analysis 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() { |
|
|
|
@ -73,11 +31,6 @@ class Analysis extends Component { |
|
|
|
dispatch({ |
|
|
|
type: 'chart/fetch', |
|
|
|
}); |
|
|
|
this.timeoutId = setTimeout(() => { |
|
|
|
this.setState({ |
|
|
|
loading: false, |
|
|
|
}); |
|
|
|
}, 600); |
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
|
@ -124,7 +77,7 @@ class Analysis extends Component { |
|
|
|
}); |
|
|
|
}; |
|
|
|
|
|
|
|
isActive(type) { |
|
|
|
isActive = type => { |
|
|
|
const { rangePickerValue } = this.state; |
|
|
|
const value = getTimeDistance(type); |
|
|
|
if (!rangePickerValue[0] || !rangePickerValue[1]) { |
|
|
|
@ -137,11 +90,11 @@ class Analysis extends Component { |
|
|
|
return styles.currentDate; |
|
|
|
} |
|
|
|
return ''; |
|
|
|
} |
|
|
|
}; |
|
|
|
|
|
|
|
render() { |
|
|
|
const { rangePickerValue, salesType, loading: stateLoading, currentTabKey } = this.state; |
|
|
|
const { chart, loading: propsLoading } = this.props; |
|
|
|
const { rangePickerValue, salesType, currentTabKey } = this.state; |
|
|
|
const { chart, loading } = this.props; |
|
|
|
const { |
|
|
|
visitData, |
|
|
|
visitData2, |
|
|
|
@ -153,7 +106,6 @@ class Analysis extends Component { |
|
|
|
salesTypeDataOnline, |
|
|
|
salesTypeDataOffline, |
|
|
|
} = chart; |
|
|
|
const loading = propsLoading || stateLoading; |
|
|
|
let salesPieData; |
|
|
|
if (salesType === 'all') { |
|
|
|
salesPieData = salesTypeData; |
|
|
|
@ -167,7 +119,7 @@ class Analysis extends Component { |
|
|
|
</Menu> |
|
|
|
); |
|
|
|
|
|
|
|
const iconGroup = ( |
|
|
|
const dropdownGroup = ( |
|
|
|
<span className={styles.iconGroup}> |
|
|
|
<Dropdown overlay={menu} placement="bottomRight"> |
|
|
|
<Icon type="ellipsis" /> |
|
|
|
@ -175,515 +127,56 @@ class Analysis extends Component { |
|
|
|
</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 {...topColResponsiveProps}> |
|
|
|
<ChartCard |
|
|
|
bordered={false} |
|
|
|
title={ |
|
|
|
<FormattedMessage id="app.analysis.total-sales" defaultMessage="Total Sales" /> |
|
|
|
} |
|
|
|
action={ |
|
|
|
<Tooltip |
|
|
|
title={ |
|
|
|
<FormattedMessage id="app.analysis.introduce" defaultMessage="Introduce" /> |
|
|
|
} |
|
|
|
> |
|
|
|
<Icon type="info-circle-o" /> |
|
|
|
</Tooltip> |
|
|
|
} |
|
|
|
loading={loading} |
|
|
|
total={() => <Yuan>126560</Yuan>} |
|
|
|
footer={ |
|
|
|
<Field |
|
|
|
label={ |
|
|
|
<FormattedMessage id="app.analysis.day-sales" defaultMessage="Daily Sales" /> |
|
|
|
} |
|
|
|
value={`¥${numeral(12423).format('0,0')}`} |
|
|
|
/> |
|
|
|
} |
|
|
|
contentHeight={46} |
|
|
|
> |
|
|
|
<Trend flag="up" style={{ marginRight: 16 }}> |
|
|
|
<FormattedMessage id="app.analysis.week" defaultMessage="Weekly Changes" /> |
|
|
|
<span className={styles.trendText}>12%</span> |
|
|
|
</Trend> |
|
|
|
<Trend flag="down"> |
|
|
|
<FormattedMessage id="app.analysis.day" defaultMessage="Daily Changes" /> |
|
|
|
<span className={styles.trendText}>11%</span> |
|
|
|
</Trend> |
|
|
|
</ChartCard> |
|
|
|
</Col> |
|
|
|
|
|
|
|
<Col {...topColResponsiveProps}> |
|
|
|
<ChartCard |
|
|
|
bordered={false} |
|
|
|
loading={loading} |
|
|
|
title={<FormattedMessage id="app.analysis.visits" defaultMessage="Visits" />} |
|
|
|
action={ |
|
|
|
<Tooltip |
|
|
|
title={ |
|
|
|
<FormattedMessage id="app.analysis.introduce" defaultMessage="Introduce" /> |
|
|
|
} |
|
|
|
> |
|
|
|
<Icon type="info-circle-o" /> |
|
|
|
</Tooltip> |
|
|
|
} |
|
|
|
total={numeral(8846).format('0,0')} |
|
|
|
footer={ |
|
|
|
<Field |
|
|
|
label={ |
|
|
|
<FormattedMessage id="app.analysis.day-visits" defaultMessage="Daily Visits" /> |
|
|
|
} |
|
|
|
value={numeral(1234).format('0,0')} |
|
|
|
/> |
|
|
|
} |
|
|
|
contentHeight={46} |
|
|
|
> |
|
|
|
<MiniArea color="#975FE4" data={visitData} /> |
|
|
|
</ChartCard> |
|
|
|
</Col> |
|
|
|
<Col {...topColResponsiveProps}> |
|
|
|
<ChartCard |
|
|
|
bordered={false} |
|
|
|
loading={loading} |
|
|
|
title={<FormattedMessage id="app.analysis.payments" defaultMessage="Payments" />} |
|
|
|
action={ |
|
|
|
<Tooltip |
|
|
|
title={ |
|
|
|
<FormattedMessage id="app.analysis.introduce" defaultMessage="Introduce" /> |
|
|
|
} |
|
|
|
> |
|
|
|
<Icon type="info-circle-o" /> |
|
|
|
</Tooltip> |
|
|
|
} |
|
|
|
total={numeral(6560).format('0,0')} |
|
|
|
footer={ |
|
|
|
<Field |
|
|
|
label={ |
|
|
|
<FormattedMessage |
|
|
|
id="app.analysis.conversion-rate" |
|
|
|
defaultMessage="Conversion Rate" |
|
|
|
/> |
|
|
|
} |
|
|
|
value="60%" |
|
|
|
/> |
|
|
|
} |
|
|
|
contentHeight={46} |
|
|
|
> |
|
|
|
<MiniBar data={visitData} /> |
|
|
|
</ChartCard> |
|
|
|
</Col> |
|
|
|
<Col {...topColResponsiveProps}> |
|
|
|
<ChartCard |
|
|
|
loading={loading} |
|
|
|
bordered={false} |
|
|
|
title={ |
|
|
|
<FormattedMessage |
|
|
|
id="app.analysis.operational-effect" |
|
|
|
defaultMessage="Operational Effect" |
|
|
|
/> |
|
|
|
} |
|
|
|
action={ |
|
|
|
<Tooltip |
|
|
|
title={ |
|
|
|
<FormattedMessage id="app.analysis.introduce" defaultMessage="Introduce" /> |
|
|
|
} |
|
|
|
> |
|
|
|
<Icon type="info-circle-o" /> |
|
|
|
</Tooltip> |
|
|
|
} |
|
|
|
total="78%" |
|
|
|
footer={ |
|
|
|
<div style={{ whiteSpace: 'nowrap', overflow: 'hidden' }}> |
|
|
|
<Trend flag="up" style={{ marginRight: 16 }}> |
|
|
|
<FormattedMessage id="app.analysis.week" defaultMessage="Weekly Changes" /> |
|
|
|
<span className={styles.trendText}>12%</span> |
|
|
|
</Trend> |
|
|
|
<Trend flag="down"> |
|
|
|
<FormattedMessage id="app.analysis.day" defaultMessage="Weekly Changes" /> |
|
|
|
<span className={styles.trendText}>11%</span> |
|
|
|
</Trend> |
|
|
|
</div> |
|
|
|
} |
|
|
|
contentHeight={46} |
|
|
|
> |
|
|
|
<MiniProgress percent={78} strokeWidth={8} target={80} color="#13C2C2" /> |
|
|
|
</ChartCard> |
|
|
|
</Col> |
|
|
|
</Row> |
|
|
|
|
|
|
|
<Card loading={loading} bordered={false} bodyStyle={{ padding: 0 }}> |
|
|
|
<div className={styles.salesCard}> |
|
|
|
<Tabs tabBarExtraContent={salesExtra} size="large" tabBarStyle={{ marginBottom: 24 }}> |
|
|
|
<TabPane |
|
|
|
tab={<FormattedMessage id="app.analysis.sales" defaultMessage="Sales" />} |
|
|
|
key="sales" |
|
|
|
> |
|
|
|
<Row> |
|
|
|
<Col xl={16} lg={12} md={12} sm={24} xs={24}> |
|
|
|
<div className={styles.salesBar}> |
|
|
|
<Bar |
|
|
|
height={295} |
|
|
|
title={ |
|
|
|
<FormattedMessage |
|
|
|
id="app.analysis.sales-trend" |
|
|
|
defaultMessage="Sales Trend" |
|
|
|
/> |
|
|
|
} |
|
|
|
data={salesData} |
|
|
|
/> |
|
|
|
</div> |
|
|
|
</Col> |
|
|
|
<Col xl={8} lg={12} md={12} sm={24} xs={24}> |
|
|
|
<div className={styles.salesRank}> |
|
|
|
<h4 className={styles.rankingTitle}> |
|
|
|
<FormattedMessage |
|
|
|
id="app.analysis.sales-ranking" |
|
|
|
defaultMessage="Sales Ranking" |
|
|
|
/> |
|
|
|
</h4> |
|
|
|
<ul className={styles.rankingList}> |
|
|
|
{this.rankingListData.map((item, i) => ( |
|
|
|
<li key={item.title}> |
|
|
|
<span |
|
|
|
className={`${styles.rankingItemNumber} ${ |
|
|
|
i < 3 ? styles.active : '' |
|
|
|
}`}
|
|
|
|
> |
|
|
|
{i + 1} |
|
|
|
</span> |
|
|
|
<span className={styles.rankingItemTitle} title={item.title}> |
|
|
|
{item.title} |
|
|
|
</span> |
|
|
|
<span className={styles.rankingItemValue}> |
|
|
|
{numeral(item.total).format('0,0')} |
|
|
|
</span> |
|
|
|
</li> |
|
|
|
))} |
|
|
|
</ul> |
|
|
|
</div> |
|
|
|
</Col> |
|
|
|
</Row> |
|
|
|
</TabPane> |
|
|
|
<TabPane |
|
|
|
tab={<FormattedMessage id="app.analysis.visits" defaultMessage="Visits" />} |
|
|
|
key="views" |
|
|
|
> |
|
|
|
<Row> |
|
|
|
<Col xl={16} lg={12} md={12} sm={24} xs={24}> |
|
|
|
<div className={styles.salesBar}> |
|
|
|
<Bar |
|
|
|
height={292} |
|
|
|
title={ |
|
|
|
<FormattedMessage |
|
|
|
id="app.analysis.visits-trend" |
|
|
|
defaultMessage="Visits Trend" |
|
|
|
/> |
|
|
|
} |
|
|
|
data={salesData} |
|
|
|
/> |
|
|
|
</div> |
|
|
|
</Col> |
|
|
|
<Col xl={8} lg={12} md={12} sm={24} xs={24}> |
|
|
|
<div className={styles.salesRank}> |
|
|
|
<h4 className={styles.rankingTitle}> |
|
|
|
<FormattedMessage |
|
|
|
id="app.analysis.visits-ranking" |
|
|
|
defaultMessage="Visits Ranking" |
|
|
|
/> |
|
|
|
</h4> |
|
|
|
<ul className={styles.rankingList}> |
|
|
|
{this.rankingListData.map((item, i) => ( |
|
|
|
<li key={item.title}> |
|
|
|
<span |
|
|
|
className={`${styles.rankingItemNumber} ${ |
|
|
|
i < 3 ? styles.active : '' |
|
|
|
}`}
|
|
|
|
> |
|
|
|
{i + 1} |
|
|
|
</span> |
|
|
|
<span className={styles.rankingItemTitle} title={item.title}> |
|
|
|
{item.title} |
|
|
|
</span> |
|
|
|
<span>{numeral(item.total).format('0,0')}</span> |
|
|
|
</li> |
|
|
|
))} |
|
|
|
</ul> |
|
|
|
</div> |
|
|
|
</Col> |
|
|
|
</Row> |
|
|
|
</TabPane> |
|
|
|
</Tabs> |
|
|
|
</div> |
|
|
|
</Card> |
|
|
|
|
|
|
|
<Suspense fallback={<PageLoading />}> |
|
|
|
<IntroduceRow loading={loading} visitData={visitData} /> |
|
|
|
</Suspense> |
|
|
|
<Suspense fallback={null}> |
|
|
|
<SalesCard |
|
|
|
rangePickerValue={rangePickerValue} |
|
|
|
salesData={salesData} |
|
|
|
isActive={this.isActive} |
|
|
|
handleRangePickerChange={this.handleRangePickerChange} |
|
|
|
loading={loading} |
|
|
|
selectDate={this.selectDate} |
|
|
|
/> |
|
|
|
</Suspense> |
|
|
|
<Row gutter={24}> |
|
|
|
<Col xl={12} lg={24} md={24} sm={24} xs={24}> |
|
|
|
<Card |
|
|
|
loading={loading} |
|
|
|
bordered={false} |
|
|
|
title={ |
|
|
|
<FormattedMessage |
|
|
|
id="app.analysis.online-top-search" |
|
|
|
defaultMessage="Online Top Search" |
|
|
|
/> |
|
|
|
} |
|
|
|
extra={iconGroup} |
|
|
|
style={{ marginTop: 24 }} |
|
|
|
> |
|
|
|
<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(12321).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={searchData} |
|
|
|
pagination={{ |
|
|
|
style: { marginBottom: 0 }, |
|
|
|
pageSize: 5, |
|
|
|
}} |
|
|
|
<Suspense fallback={null}> |
|
|
|
<TopSearch |
|
|
|
loading={loading} |
|
|
|
visitData2={visitData2} |
|
|
|
selectDate={this.selectDate} |
|
|
|
searchData={searchData} |
|
|
|
dropdownGroup={dropdownGroup} |
|
|
|
/> |
|
|
|
</Card> |
|
|
|
</Suspense> |
|
|
|
</Col> |
|
|
|
<Col xl={12} lg={24} md={24} sm={24} xs={24}> |
|
|
|
<Card |
|
|
|
loading={loading} |
|
|
|
className={styles.salesCard} |
|
|
|
bordered={false} |
|
|
|
title={ |
|
|
|
<FormattedMessage |
|
|
|
id="app.analysis.the-proportion-of-sales" |
|
|
|
defaultMessage="The Proportion of Sales" |
|
|
|
/> |
|
|
|
} |
|
|
|
bodyStyle={{ padding: 24 }} |
|
|
|
extra={ |
|
|
|
<div className={styles.salesCardExtra}> |
|
|
|
{iconGroup} |
|
|
|
<div className={styles.salesTypeRadio}> |
|
|
|
<Radio.Group value={salesType} onChange={this.handleChangeSalesType}> |
|
|
|
<Radio.Button value="all"> |
|
|
|
<FormattedMessage id="app.analysis.channel.all" defaultMessage="ALL" /> |
|
|
|
</Radio.Button> |
|
|
|
<Radio.Button value="online"> |
|
|
|
<FormattedMessage |
|
|
|
id="app.analysis.channel.online" |
|
|
|
defaultMessage="Online" |
|
|
|
/> |
|
|
|
</Radio.Button> |
|
|
|
<Radio.Button value="stores"> |
|
|
|
<FormattedMessage |
|
|
|
id="app.analysis.channel.stores" |
|
|
|
defaultMessage="Stores" |
|
|
|
/> |
|
|
|
</Radio.Button> |
|
|
|
</Radio.Group> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
} |
|
|
|
style={{ marginTop: 24, minHeight: 509 }} |
|
|
|
> |
|
|
|
<h4 style={{ marginTop: 8, marginBottom: 32 }}> |
|
|
|
<FormattedMessage id="app.analysis.sales" defaultMessage="Sales" /> |
|
|
|
</h4> |
|
|
|
<Pie |
|
|
|
hasLegend |
|
|
|
subTitle={<FormattedMessage id="app.analysis.sales" defaultMessage="Sales" />} |
|
|
|
total={() => <Yuan>{salesPieData.reduce((pre, now) => now.y + pre, 0)}</Yuan>} |
|
|
|
data={salesPieData} |
|
|
|
valueFormat={value => <Yuan>{value}</Yuan>} |
|
|
|
height={248} |
|
|
|
lineWidth={4} |
|
|
|
<Suspense fallback={null}> |
|
|
|
<ProportionSales |
|
|
|
dropdownGroup={dropdownGroup} |
|
|
|
salesType={salesType} |
|
|
|
loading={loading} |
|
|
|
salesPieData={salesPieData} |
|
|
|
handleChangeSalesType={this.handleChangeSalesType} |
|
|
|
/> |
|
|
|
</Card> |
|
|
|
</Suspense> |
|
|
|
</Col> |
|
|
|
</Row> |
|
|
|
|
|
|
|
<Card |
|
|
|
loading={loading} |
|
|
|
className={styles.offlineCard} |
|
|
|
bordered={false} |
|
|
|
bodyStyle={{ padding: '0 0 32px 0' }} |
|
|
|
style={{ marginTop: 32 }} |
|
|
|
> |
|
|
|
<Tabs activeKey={activeKey} onChange={this.handleTabChange}> |
|
|
|
{offlineData.map(shop => ( |
|
|
|
<TabPane tab={<CustomTab data={shop} currentTabKey={activeKey} />} key={shop.name}> |
|
|
|
<div style={{ padding: '0 24px' }}> |
|
|
|
<TimelineChart |
|
|
|
height={400} |
|
|
|
data={offlineChartData} |
|
|
|
titleMap={{ |
|
|
|
y1: formatMessage({ id: 'app.analysis.traffic' }), |
|
|
|
y2: formatMessage({ id: 'app.analysis.payments' }), |
|
|
|
}} |
|
|
|
/> |
|
|
|
</div> |
|
|
|
</TabPane> |
|
|
|
))} |
|
|
|
</Tabs> |
|
|
|
</Card> |
|
|
|
<Suspense fallback={null}> |
|
|
|
<OfflineData |
|
|
|
activeKey={activeKey} |
|
|
|
loading={loading} |
|
|
|
offlineData={offlineData} |
|
|
|
offlineChartData={offlineChartData} |
|
|
|
handleTabChange={this.handleTabChange} |
|
|
|
/> |
|
|
|
</Suspense> |
|
|
|
</GridContent> |
|
|
|
); |
|
|
|
} |
|
|
|
|