Commit c9a09d85 authored by 陈帅's avatar 陈帅

add analysis locale

parent 4caebc00
......@@ -40,77 +40,77 @@ for (let i = 0; i < 50; i += 1) {
}
const salesTypeData = [
{
x: '家用电器',
x: 'House appliances',
y: 4544,
},
{
x: '食用酒水',
x: 'Drink & wine',
y: 3321,
},
{
x: '个护健康',
x: 'Health & care',
y: 3113,
},
{
x: '服饰箱包',
x: 'Clothing & bags',
y: 2341,
},
{
x: '母婴产品',
x: 'Mother-baby',
y: 1231,
},
{
x: '其他',
x: 'Other',
y: 1231,
},
];
const salesTypeDataOnline = [
{
x: '家用电器',
x: 'House appliances',
y: 244,
},
{
x: '食用酒水',
x: 'Drink & wine',
y: 321,
},
{
x: '个护健康',
x: 'Health & care',
y: 311,
},
{
x: '服饰箱包',
x: 'Clothing & bags',
y: 41,
},
{
x: '母婴产品',
x: 'Mother-baby',
y: 121,
},
{
x: '其他',
x: 'Other',
y: 111,
},
];
const salesTypeDataOffline = [
{
x: '家用电器',
x: 'House appliances',
y: 99,
},
{
x: '个护健康',
x: 'Drink & wine',
y: 188,
},
{
x: '服饰箱包',
x: 'Health & care',
y: 344,
},
{
x: '母婴产品',
x: 'Clothing & bags',
y: 255,
},
{
x: '其他',
x: 'Other',
y: 65,
},
];
......@@ -118,7 +118,7 @@ const salesTypeDataOffline = [
const offlineData = [];
for (let i = 0; i < 10; i += 1) {
offlineData.push({
name: `门店${i}`,
name: `Stores ${i}`,
cvr: Math.ceil(Math.random() * 9) / 10,
});
}
......
import React, { PureComponent } from 'react';
import { FormattedMessage } from 'react-intl';
import { Spin, Tag, Menu, Icon, Dropdown, Avatar, Tooltip } from 'antd';
import moment from 'moment';
import groupBy from 'lodash/groupBy';
......@@ -51,13 +52,16 @@ export default class GlobalHeaderRight extends PureComponent {
const menu = (
<Menu className={styles.menu} selectedKeys={[]} onClick={onMenuClick}>
<Menu.Item key="userCenter">
<Icon type="user" />个人中心
<Icon type="user" />
<FormattedMessage id="menu.account.center" defaultMessage="account center" />
</Menu.Item>
<Menu.Item key="userinfo">
<Icon type="setting" />设置
<Icon type="setting" />
<FormattedMessage id="menu.account.settings" defaultMessage="account settings" />
</Menu.Item>
<Menu.Item key="triggerError">
<Icon type="close-circle" />触发报错
<Icon type="close-circle" />
<FormattedMessage id="menu.account.trigger" defaultMessage="Trigger Error" />
</Menu.Item>
<Menu.Divider />
<Menu.Item key="logout">
......
......@@ -15,6 +15,7 @@ export interface IPageHeaderProps {
tabBarExtraContent?: React.ReactNode;
linkElement?: React.ReactNode;
style?: React.CSSProperties;
home?: React.ReactNode;
}
export default class PageHeader extends React.Component<IPageHeaderProps, any> {}
......@@ -105,7 +105,7 @@ export default class PageHeader extends PureComponent {
{
[linkElement === 'a' ? 'href' : 'to']: '/',
},
'首页'
this.props.home || 'Home'
)}
</Breadcrumb.Item>
);
......
......@@ -16,6 +16,7 @@ order: 11
| title | title 区域 | ReactNode | - |
| logo | logo区域 | ReactNode | - |
| action | 操作区,位于 title 行的行尾 | ReactNode | - |
| home | 默认的主页说明文字 | ReactNode | - |
| content | 内容区 | ReactNode | - |
| extraContent | 额外内容区,位于content的右侧 | ReactNode | - |
| breadcrumbList | 面包屑数据,配置了此属性时 `routes` `params` `location` `breadcrumbNameMap` 无效 | array<{title: ReactNode, href?: string}> | - |
......
......@@ -7,9 +7,70 @@ export default {
data: appLocaleData,
antd: antdEn,
messages: {
'menu.home': 'home',
'menu.dashboard': 'Dashboard',
'menu.dashboard.analysis': 'Analysis',
'menu.dashboard.monitor': 'Monitor',
'menu.dashboard.workplace': 'Workplace',
'menu.form': 'Form',
'menu.form.basicform': 'Basic Form',
'menu.form.stepform': 'Step Form',
'menu.form.advancedform': 'Advanced Form',
'menu.list': 'List',
'menu.list.searchlist': 'Search List',
'menu.list.basiclist': 'Basic List',
'menu.list.cardlist': 'Card List',
'menu.list.searchlist.articles': 'Search List(articles)',
'menu.list.searchlist.projects': 'Search List(projects)',
'menu.list.searchlist.applications': 'Search List(applications)',
'menu.profile': 'Profile',
'menu.profile.basic': 'Basic',
'menu.profile.advanced': 'Advanced',
'menu.result': 'Result',
'menu.result.success': 'Success',
'menu.result.fail': 'Fail',
'menu.exception': 'Exception',
'menu.exception.not-permission': '403',
'menu.exception.not-find': '404',
'menu.exception.server-error': '500',
'menu.exception.trigger': 'Trigger',
'menu.account': 'Account',
'menu.account.center': 'Account Center',
'menu.account.settings': 'Account Settings',
'menu.account.trigger': 'Trigger Error',
'app.home.introduce': 'introduce',
'app.analysis.test': 'Gongzhuan road No.{no} shop',
'app.analysis.introduce': 'Introduce',
'app.analysis.total-sales': 'total sales',
'app.analysis.day-sales': 'Day Sales',
'app.analysis.visits': 'Visits',
'app.analysis.visits-trend': 'Visits Trend',
'app.analysis.visits-ranking': 'Visits Ranking',
'app.analysis.day-visits': 'Day Visits',
'app.analysis.week': 'week ratio',
'app.analysis.day': 'day ratio',
'app.analysis.payments': 'Payments',
'app.analysis.conversion-rate': 'Conversion Rate',
'app.analysis.operational-effect': 'Operational Effect',
'app.analysis.sales-trend': 'Stores Sales Trend',
'app.analysis.sales-ranking': 'sales ranking',
'app.analysis.all-year': 'All Year',
'app.analysis.all-month': 'All Month',
'app.analysis.all-week': 'All Week',
'app.analysis.all-day': 'All day',
'app.analysis.search-users': 'Search Users',
'app.analysis.per-capita-search': 'Per Capita Search',
'app.analysis.online-top-search': 'Online Top Search',
'app.analysis.the-proportion-of-sales': 'The Proportion Of Sales',
'app.analysis.channel.all': 'ALL',
'app.analysis.channel.online': 'Online',
'app.analysis.channel.stores': 'Stores',
'app.analysis.sales': 'Sales',
'app.analysis.traffic': 'Traffic',
'app.analysis.table.rank': 'Rank',
'app.analysis.table.search-keyword': 'Keyword',
'app.analysis.table.users': 'Users',
'app.analysis.table.weekly-range': 'Weekly Range',
// ...enMessages,
},
};
......@@ -7,9 +7,8 @@ export default {
data: appLocaleData,
antd: antdZh,
messages: {
'app.home.introduce': '介绍',
'app.analysis.test': '工专路 {no} 号店',
'menu.dashboard': '仪表盘',
'menu.home': '首页',
'menu.dashboard': 'Dashboard',
'menu.dashboard.analysis': '分析页',
'menu.dashboard.monitor': '监控页',
'menu.dashboard.workplace': '工作台',
......@@ -23,13 +22,13 @@ export default {
'menu.list.cardlist': '卡片列表',
'menu.list.searchlist.articles': '搜索列表(文章)',
'menu.list.searchlist.projects': '搜索列表(项目)',
'menu.list.searchlist.applications': '搜索列表(列表',
'menu.list.searchlist.applications': '搜索列表(应用',
'menu.profile': '详情页',
'menu.profile.basic': '详情页',
'menu.profile.advanced': '详情页',
'menu.result': '结果页',
'menu.result.success': '成功页',
'menu.result.fail': '成功',
'menu.result.fail': '失败',
'menu.exception': '异常页',
'menu.exception.not-permission': '403',
'menu.exception.not-find': '404',
......@@ -38,6 +37,40 @@ export default {
'menu.account': '个人页',
'menu.account.center': '个人中心',
'menu.account.settings': '个人设置',
'menu.account.trigger': '触发报错',
'app.home.introduce': '介绍',
'app.analysis.test': '工专路 {no} 号店',
'app.analysis.introduce': '指标说明',
'app.analysis.total-sales': '总销售额',
'app.analysis.day-sales': '日销售额',
'app.analysis.visits': '访问量',
'app.analysis.visits-trend': '访问量趋势',
'app.analysis.visits-ranking': '门店访问量排名',
'app.analysis.day-visits': '日访问量',
'app.analysis.week': '周同比',
'app.analysis.day': '日同比',
'app.analysis.payments': '支付笔数',
'app.analysis.conversion-rate': '转化率',
'app.analysis.operational-effect': '运营活动效果',
'app.analysis.sales-trend': '销售趋势',
'app.analysis.sales-ranking': '门店销售额排名',
'app.analysis.all-year': '全年',
'app.analysis.all-month': '本月',
'app.analysis.all-week': '本周',
'app.analysis.all-day': '今日',
'app.analysis.search-users': '搜索用户数',
'app.analysis.per-capita-search': '人均搜索次数',
'app.analysis.online-top-search': '线上热门搜索',
'app.analysis.the-proportion-of-sales': '销售额类别占比',
'app.analysis.channel.all': '全部渠道',
'app.analysis.channel.online': '线上',
'app.analysis.channel.stores': '门店',
'app.analysis.sales': '销售额',
'app.analysis.traffic': '客流量',
'app.analysis.table.rank': '排名',
'app.analysis.table.search-keyword': '搜索关键词',
'app.analysis.table.users': '用户数',
'app.analysis.table.weekly-range': '周涨幅',
// ...zhMessages,
},
};
import React, { Component } from 'react';
import { connect } from 'dva';
import { injectIntl } from 'react-intl';
import { injectIntl, FormattedMessage } from 'react-intl';
import {
Row,
Col,
......@@ -65,6 +65,7 @@ class Analysis extends Component {
rangePickerValue: getTimeDistance('year'),
};
}
state = {
salesType: 'all',
currentTabKey: '',
......@@ -174,16 +175,16 @@ class Analysis extends Component {
<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
......@@ -196,25 +197,32 @@ class Analysis extends Component {
const columns = [
{
title: '排名',
title: <FormattedMessage id="app.analysis.table.rank" defaultMessage="Rank" />,
dataIndex: 'index',
key: 'index',
},
{
title: '搜索关键词',
title: (
<FormattedMessage
id="app.analysis.table.search-keyword"
defaultMessage="Search keyword"
/>
),
dataIndex: 'keyword',
key: 'keyword',
render: text => <a href="/">{text}</a>,
},
{
title: '用户数',
title: <FormattedMessage id="app.analysis.table.users" defaultMessage="Users" />,
dataIndex: 'count',
key: 'count',
sorter: (a, b) => a.count - b.count,
className: styles.alignRight,
},
{
title: '周涨幅',
title: (
<FormattedMessage id="app.analysis.table.weekly-range" defaultMessage="Weekly Range" />
),
dataIndex: 'range',
key: 'range',
sorter: (a, b) => a.range - b.range,
......@@ -237,7 +245,12 @@ class Analysis extends Component {
<Col span={12}>
<NumberInfo
title={data.name}
subTitle="转化率"
subTitle={
<FormattedMessage
id="app.analysis.conversion-rate"
defaultMessage="Conversion Rate"
/>
}
gap={2}
total={`${data.cvr * 100}%`}
theme={currentKey !== data.name && 'light'}
......@@ -272,23 +285,36 @@ class Analysis extends Component {
<Col {...topColResponsiveProps}>
<ChartCard
bordered={false}
title="总销售额"
title={
<FormattedMessage id="app.analysis.total-sales" defaultMessage="Total Sales" />
}
action={
<Tooltip title="指标说明">
<Tooltip
title={
<FormattedMessage id="app.analysis.introduce" defaultMessage="introduce" />
}
>
<Icon type="info-circle-o" />
</Tooltip>
}
loading={loading}
total={() => <Yuan>126560</Yuan>}
footer={<Field label="日均销售额" value={`¥${numeral(12423).format('0,0')}`} />}
footer={
<Field
label={
<FormattedMessage id="app.analysis.day-sales" defaultMessage="Day 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>
......@@ -296,15 +322,25 @@ class Analysis extends Component {
<Col {...topColResponsiveProps}>
<ChartCard
bordered={false}
loading={loading}
title="访问量"
title={<FormattedMessage id="app.analysis.visits" defaultMessage="visits" />}
action={
<Tooltip title="指标说明">
<Tooltip
title={
<FormattedMessage id="app.analysis.introduce" defaultMessage="introduce" />
}
>
<Icon type="info-circle-o" />
</Tooltip>
}
total={numeral(8846).format('0,0')}
footer={<Field label="日访问量" value={numeral(1234).format('0,0')} />}
footer={
<Field
label={
<FormattedMessage id="app.analysis.day-visits" defaultMessage="Day Visits" />
}
value={numeral(1234).format('0,0')}
/>
}
contentHeight={46}
>
<MiniArea color="#975FE4" data={visitData} />
......@@ -313,15 +349,28 @@ class Analysis extends Component {
<Col {...topColResponsiveProps}>
<ChartCard
bordered={false}
loading={loading}
title="支付笔数"
title={<FormattedMessage id="app.analysis.payments" defaultMessage="Payments" />}
action={
<Tooltip title="指标说明">
<Tooltip
title={
<FormattedMessage id="app.analysis.introduce" defaultMessage="Introduce" />
}
>
<Icon type="info-circle-o" />
</Tooltip>
}
total={numeral(6560).format('0,0')}
footer={<Field label="转化率" value="60%" />}
footer={
<Field
label={
<FormattedMessage
id="app.analysis.conversion-rate"
defaultMessage="Conversion Rate"
/>
}
value="60%"
/>
}
contentHeight={46}
>
<MiniBar data={visitData} />
......@@ -331,9 +380,18 @@ class Analysis extends Component {
<ChartCard
loading={loading}
bordered={false}
title="运营活动效果"
title={
<FormattedMessage
id="app.analysis.operational-effect"
defaultMessage="Operational Effect"
/>
}
action={
<Tooltip title="指标说明">
<Tooltip
title={
<FormattedMessage id="app.analysis.introduce" defaultMessage="introduce" />
}
>
<Icon type="info-circle-o" />
</Tooltip>
}
......@@ -341,11 +399,11 @@ class Analysis extends Component {
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>
......@@ -360,16 +418,33 @@ class Analysis extends Component {
<Card loading={loading} bordered={false} bodyStyle={{ padding: 0 }}>
<div className={styles.salesCard}>
<Tabs tabBarExtraContent={salesExtra} size="large" tabBarStyle={{ marginBottom: 24 }}>
<TabPane tab="销售额" key="sales">
<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="销售额趋势" data={salesData} />
<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}>门店销售额排名</h4>
<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}>
......@@ -383,16 +458,33 @@ class Analysis extends Component {
</Col>
</Row>
</TabPane>
<TabPane tab="访问量" key="views">
<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="访问量趋势" data={salesData} />
<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}>门店访问量排名</h4>
<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}>
......@@ -415,7 +507,12 @@ class Analysis extends Component {
<Card
loading={loading}
bordered={false}
title="线上热门搜索"
title={
<FormattedMessage
id="app.analysis.online-top-search"
defaultMessage="Online Top Search"
/>
}
extra={iconGroup}
style={{ marginTop: 24 }}
>
......@@ -424,8 +521,18 @@ class Analysis extends Component {
<NumberInfo
subTitle={
<span>
搜索用户数
<Tooltip title="指标文案">
<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>
......@@ -439,7 +546,12 @@ class Analysis extends Component {
</Col>
<Col sm={12} xs={24} style={{ marginBottom: 24 }}>
<NumberInfo
subTitle="人均搜索次数"
subTitle={
<FormattedMessage
id="app.analysis.per-capita-search"
defaultMessage="Per Capita Search"
/>
}
total={2.7}
status="down"
subTotal={26.2}
......@@ -465,26 +577,45 @@ class Analysis extends Component {
loading={loading}
className={styles.salesCard}
bordered={false}
title="销售额类别占比"
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">全部渠道</Radio.Button>
<Radio.Button value="online">线上</Radio.Button>
<Radio.Button value="offline">门店</Radio.Button>
<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 }}>销售额</h4>
<h4 style={{ marginTop: 8, marginBottom: 32 }}>
<FormattedMessage id="app.analysis.sales" defaultMessage="Sales" />
</h4>
<Pie
hasLegend
subTitle="销售额"
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>}
......@@ -509,7 +640,10 @@ class Analysis extends Component {
<TimelineChart
height={400}
data={offlineChartData}
titleMap={{ y1: '客流量', y2: '支付笔数' }}
titleMap={{
y1: <FormattedMessage id="app.analysis.traffic" defaultMessage="Traffic" />,
y2: <FormattedMessage id="app.analysis.payments" defaultMessage="Payments" />,
}}
/>
</div>
</TabPane>
......
import React from 'react';
import { FormattedMessage } from 'react-intl';
import { Link } from 'dva/router';
import PageHeader from '../../components/PageHeader';
import GridContent from './GridContent';
......@@ -10,7 +11,15 @@ const PageHeaderLayout = ({ children, wrapperClassName, top, ...restProps }) =>
{top}
<MenuContext.Consumer>
{value => {
return <PageHeader {...value} key="pageheader" {...restProps} linkElement={Link} />;
return (
<PageHeader
home={<FormattedMessage id="menu.home" defaultMessage="Home" />}
{...value}
key="pageheader"
{...restProps}
linkElement={Link}
/>
);
}}
</MenuContext.Consumer>
{children ? (
......
......@@ -18,6 +18,9 @@ dynamic.setDefaultLoadingComponent(() => {
});
function getLang() {
if (window) {
return 'en-US';
}
return (window.localStorage && localStorage.getItem('locale')) ||
(navigator.language || navigator.browserLanguage).toLowerCase() === 'en-us'
? 'en-US'
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment