diff --git a/config/config.ts b/config/config.ts index 8a8f9f61b92b8267dcf8d55219e077a5c32b0f80..e060403ccacb0a297fa4463b921856da8ed95360 100644 --- a/config/config.ts +++ b/config/config.ts @@ -4,12 +4,10 @@ import slash from 'slash2'; import { IPlugin, IConfig } from 'umi-types'; import defaultSettings from './defaultSettings'; import webpackPlugin from './plugin.config'; - -const { pwa, primaryColor } = defaultSettings; -// preview.pro.ant.design only do not use in your production ; +const { pwa, primaryColor } = defaultSettings; // preview.pro.ant.design only do not use in your production ; // preview.pro.ant.design 专用环境变量,请不要在你的项目中使用它。 -const { ANT_DESIGN_PRO_ONLY_DO_NOT_USE_IN_YOUR_PRODUCTION, TEST, NODE_ENV } = process.env; +const { ANT_DESIGN_PRO_ONLY_DO_NOT_USE_IN_YOUR_PRODUCTION, TEST, NODE_ENV } = process.env; const plugins: IPlugin[] = [ [ 'umi-plugin-react', @@ -59,10 +57,9 @@ const plugins: IPlugin[] = [ autoAddMenu: true, }, ], -]; - -// 针对 preview.pro.ant.design 的 GA 统计代码 +]; // 针对 preview.pro.ant.design 的 GA 统计代码 // preview.pro.ant.design only do not use in your production ; preview.pro.ant.design 专用环境变量,请不要在你的项目中使用它。 + if (ANT_DESIGN_PRO_ONLY_DO_NOT_USE_IN_YOUR_PRODUCTION === 'site') { plugins.push([ 'umi-plugin-ga', @@ -84,7 +81,6 @@ const uglifyJSOptions = }, } : {}; - export default { // add for transfer to umi plugins, @@ -107,9 +103,9 @@ export default { routes: [ { path: '/', - name: 'Analysis', - icon: 'dashboard', - component: './analysis', + name: 'welcome', + icon: 'smile', + component: './Welcome', }, ], }, @@ -147,7 +143,9 @@ export default { ) { return localName; } + const match = context.resourcePath.match(/src(.*)/); + if (match && match[1]) { const antdProPath = match[1].replace('.less', ''); const arr = slash(antdProPath) @@ -156,6 +154,7 @@ export default { .map((a: string) => a.toLowerCase()); return `antd-pro${arr.join('-')}-${localName}`.replace(/--/g, '-'); } + return localName; }, }, diff --git a/package.json b/package.json index 7a2d04d3232d81d0e6b332afe520743277bc717f..e6da2ccc19f0bba85be200b0397dee2801113f78 100644 --- a/package.json +++ b/package.json @@ -61,6 +61,7 @@ "bizcharts-plugin-slider": "^2.1.1-beta.1", "classnames": "^2.2.6", "dva": "^2.4.0", + "hash.js": "^1.1.5", "lodash": "^4.17.10", "lodash-decorators": "^6.0.0", "memoize-one": "^5.0.0", @@ -77,7 +78,8 @@ "react-dom": "^16.7.0", "react-fittext": "^1.0.0", "react-media": "^1.9.2", - "react-media-hook2": "^1.0.2" + "react-media-hook2": "^1.0.2", + "umi": "^2.7.0-beta.2" }, "devDependencies": { "@types/classnames": "^2.2.7", diff --git a/src/pages/analysis/_mock.ts b/src/pages/analysis/_mock.ts deleted file mode 100644 index 29100ede39df287ae10b52429d7d4b588d5126ef..0000000000000000000000000000000000000000 --- a/src/pages/analysis/_mock.ts +++ /dev/null @@ -1,197 +0,0 @@ -import moment from 'moment'; -import { IVisitData, IRadarData, IAnalysisData } from './data'; - -// mock data -const visitData: IVisitData[] = []; -const beginDay = new Date().getTime(); - -const fakeY = [7, 5, 4, 2, 4, 7, 5, 6, 5, 9, 6, 3, 1, 5, 3, 6, 5]; -for (let i = 0; i < fakeY.length; i += 1) { - visitData.push({ - x: moment(new Date(beginDay + 1000 * 60 * 60 * 24 * i)).format('YYYY-MM-DD'), - y: fakeY[i], - }); -} - -const visitData2 = []; -const fakeY2 = [1, 6, 4, 8, 3, 7, 2]; -for (let i = 0; i < fakeY2.length; i += 1) { - visitData2.push({ - x: moment(new Date(beginDay + 1000 * 60 * 60 * 24 * i)).format('YYYY-MM-DD'), - y: fakeY2[i], - }); -} - -const salesData = []; -for (let i = 0; i < 12; i += 1) { - salesData.push({ - x: `${i + 1}月`, - y: Math.floor(Math.random() * 1000) + 200, - }); -} -const searchData = []; -for (let i = 0; i < 50; i += 1) { - searchData.push({ - index: i + 1, - keyword: `搜索关键词-${i}`, - count: Math.floor(Math.random() * 1000), - range: Math.floor(Math.random() * 100), - status: Math.floor((Math.random() * 10) % 2), - }); -} -const salesTypeData = [ - { - x: '家用电器', - y: 4544, - }, - { - x: '食用酒水', - y: 3321, - }, - { - x: '个护健康', - y: 3113, - }, - { - x: '服饰箱包', - y: 2341, - }, - { - x: '母婴产品', - y: 1231, - }, - { - x: '其他', - y: 1231, - }, -]; - -const salesTypeDataOnline = [ - { - x: '家用电器', - y: 244, - }, - { - x: '食用酒水', - y: 321, - }, - { - x: '个护健康', - y: 311, - }, - { - x: '服饰箱包', - y: 41, - }, - { - x: '母婴产品', - y: 121, - }, - { - x: '其他', - y: 111, - }, -]; - -const salesTypeDataOffline = [ - { - x: '家用电器', - y: 99, - }, - { - x: '食用酒水', - y: 188, - }, - { - x: '个护健康', - y: 344, - }, - { - x: '服饰箱包', - y: 255, - }, - { - x: '其他', - y: 65, - }, -]; - -const offlineData = []; -for (let i = 0; i < 10; i += 1) { - offlineData.push({ - name: `Stores ${i}`, - cvr: Math.ceil(Math.random() * 9) / 10, - }); -} -const offlineChartData = []; -for (let i = 0; i < 20; i += 1) { - offlineChartData.push({ - x: new Date().getTime() + 1000 * 60 * 30 * i, - y1: Math.floor(Math.random() * 100) + 10, - y2: Math.floor(Math.random() * 100) + 10, - }); -} - -const radarOriginData = [ - { - name: '个人', - ref: 10, - koubei: 8, - output: 4, - contribute: 5, - hot: 7, - }, - { - name: '团队', - ref: 3, - koubei: 9, - output: 6, - contribute: 3, - hot: 1, - }, - { - name: '部门', - ref: 4, - koubei: 1, - output: 6, - contribute: 5, - hot: 7, - }, -]; - -const radarData: IRadarData[] = []; -const radarTitleMap = { - ref: '引用', - koubei: '口碑', - output: '产量', - contribute: '贡献', - hot: '热度', -}; -radarOriginData.forEach(item => { - Object.keys(item).forEach(key => { - if (key !== 'name') { - radarData.push({ - name: item.name, - label: radarTitleMap[key], - value: item[key], - }); - } - }); -}); - -const getFakeChartData: IAnalysisData = { - visitData, - visitData2, - salesData, - searchData, - offlineData, - offlineChartData, - salesTypeData, - salesTypeDataOnline, - salesTypeDataOffline, - radarData, -}; - -export default { - 'GET /api/analysis/fake_chart_data': getFakeChartData, -}; diff --git a/src/pages/analysis/components/Charts/Bar/index.tsx b/src/pages/analysis/components/Charts/Bar/index.tsx deleted file mode 100644 index b5507fe6ad898a2f19b8f5a5ae45b932db94ae86..0000000000000000000000000000000000000000 --- a/src/pages/analysis/components/Charts/Bar/index.tsx +++ /dev/null @@ -1,135 +0,0 @@ -import React, { Component } from 'react'; -import { Chart, Axis, Tooltip, Geom } from 'bizcharts'; -import Debounce from 'lodash-decorators/debounce'; -import Bind from 'lodash-decorators/bind'; -import styles from '../index.less'; -import autoHeight from '../autoHeight'; - -export interface IBarProps { - title: React.ReactNode; - color?: string; - padding?: [number, number, number, number]; - height?: number; - data: Array<{ - x: string; - y: number; - }>; - forceFit?: boolean; - autoLabel?: boolean; - style?: React.CSSProperties; -} - -class Bar extends Component< - IBarProps, - { - autoHideXLabels: boolean; - } -> { - root: HTMLDivElement | undefined; - node: HTMLDivElement | undefined; - - state = { - height: 0, - autoHideXLabels: false, - }; - - componentDidMount() { - window.addEventListener('resize', this.resize, { passive: true }); - } - - componentWillUnmount() { - window.removeEventListener('resize', this.resize); - } - - handleRoot = (n: HTMLDivElement) => { - this.root = n; - }; - handleRef = (n: HTMLDivElement) => { - this.node = n; - }; - - @Bind() - @Debounce(400) - resize() { - if (!this.node || !this.node.parentNode) { - return; - } - const canvasWidth = (this.node.parentNode as HTMLDivElement).clientWidth; - const { data = [], autoLabel = true } = this.props; - if (!autoLabel) { - return; - } - const minWidth = data.length * 30; - const { autoHideXLabels } = this.state; - - if (canvasWidth <= minWidth) { - if (!autoHideXLabels) { - this.setState({ - autoHideXLabels: true, - }); - } - } else if (autoHideXLabels) { - this.setState({ - autoHideXLabels: false, - }); - } - } - - render() { - const { - height: propsHeight = 1, - title, - forceFit = true, - data, - color = 'rgba(24, 144, 255, 0.85)', - padding, - } = this.props; - - const { autoHideXLabels } = this.state; - - const scale = { - x: { - type: 'cat', - }, - y: { - min: 0, - }, - }; - - const tooltip: [string, (...args: any[]) => { name?: string; value: string }] = [ - 'x*y', - (x: string, y: string) => ({ - name: x, - value: y, - }), - ]; - const { height: stateHeight } = this.state; - const height = propsHeight || stateHeight; - return ( -
-
- {title &&

{title}

} - - - - - - -
-
- ); - } -} - -export default autoHeight()(Bar); diff --git a/src/pages/analysis/components/Charts/ChartCard/index.less b/src/pages/analysis/components/Charts/ChartCard/index.less deleted file mode 100644 index 282f17d9cf32af486e1c13d8d55bec1a9e5076f1..0000000000000000000000000000000000000000 --- a/src/pages/analysis/components/Charts/ChartCard/index.less +++ /dev/null @@ -1,75 +0,0 @@ -@import '~antd/lib/style/themes/default.less'; - -.chartCard { - position: relative; - .chartTop { - position: relative; - width: 100%; - overflow: hidden; - } - .chartTopMargin { - margin-bottom: 12px; - } - .chartTopHasMargin { - margin-bottom: 20px; - } - .metaWrap { - float: left; - } - .avatar { - position: relative; - top: 4px; - float: left; - margin-right: 20px; - img { - border-radius: 100%; - } - } - .meta { - height: 22px; - color: @text-color-secondary; - font-size: @font-size-base; - line-height: 22px; - } - .action { - position: absolute; - top: 4px; - right: 0; - line-height: 1; - cursor: pointer; - } - .total { - height: 38px; - margin-top: 4px; - margin-bottom: 0; - overflow: hidden; - color: @heading-color; - font-size: 30px; - line-height: 38px; - white-space: nowrap; - text-overflow: ellipsis; - word-break: break-all; - } - .content { - position: relative; - width: 100%; - margin-bottom: 12px; - } - .contentFixed { - position: absolute; - bottom: 0; - left: 0; - width: 100%; - } - .footer { - margin-top: 8px; - padding-top: 9px; - border-top: 1px solid @border-color-split; - & > * { - position: relative; - } - } - .footerMargin { - margin-top: 20px; - } -} diff --git a/src/pages/analysis/components/Charts/ChartCard/index.tsx b/src/pages/analysis/components/Charts/ChartCard/index.tsx deleted file mode 100644 index 11f5f2052c176f10269fb29efd312714c5957c3a..0000000000000000000000000000000000000000 --- a/src/pages/analysis/components/Charts/ChartCard/index.tsx +++ /dev/null @@ -1,98 +0,0 @@ -import React from 'react'; -import { Card } from 'antd'; -import classNames from 'classnames'; -import { CardProps } from 'antd/lib/card'; - -import styles from './index.less'; - -type totalType = () => React.ReactNode; - -const renderTotal = (total?: number | totalType | React.ReactNode) => { - if (!total) { - return; - } - let totalDom; - switch (typeof total) { - case 'undefined': - totalDom = null; - break; - case 'function': - totalDom =
{total()}
; - break; - default: - totalDom =
{total}
; - } - return totalDom; -}; - -export interface IChartCardProps extends CardProps { - title: React.ReactNode; - action?: React.ReactNode; - total?: React.ReactNode | number | (() => React.ReactNode | number); - footer?: React.ReactNode; - contentHeight?: number; - avatar?: React.ReactNode; - style?: React.CSSProperties; -} - -class ChartCard extends React.Component { - renderContent = () => { - const { contentHeight, title, avatar, action, total, footer, children, loading } = this.props; - if (loading) { - return false; - } - return ( -
-
-
{avatar}
-
-
- {title} - {action} -
- {renderTotal(total)} -
-
- {children && ( -
-
{children}
-
- )} - {footer && ( -
- {footer} -
- )} -
- ); - }; - - render() { - const { - loading = false, - contentHeight, - title, - avatar, - action, - total, - footer, - children, - ...rest - } = this.props; - return ( - - {this.renderContent()} - - ); - } -} - -export default ChartCard; diff --git a/src/pages/analysis/components/Charts/Field/index.less b/src/pages/analysis/components/Charts/Field/index.less deleted file mode 100644 index 4124471cb522bf18fb7963675ddeeb3dc217b9e7..0000000000000000000000000000000000000000 --- a/src/pages/analysis/components/Charts/Field/index.less +++ /dev/null @@ -1,17 +0,0 @@ -@import '~antd/lib/style/themes/default.less'; - -.field { - margin: 0; - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; - .label, - .number { - font-size: @font-size-base; - line-height: 22px; - } - .number { - margin-left: 8px; - color: @heading-color; - } -} diff --git a/src/pages/analysis/components/Charts/Field/index.tsx b/src/pages/analysis/components/Charts/Field/index.tsx deleted file mode 100644 index ee3c12454ead9e275a7ed71dba1a20c79b083cf8..0000000000000000000000000000000000000000 --- a/src/pages/analysis/components/Charts/Field/index.tsx +++ /dev/null @@ -1,18 +0,0 @@ -import React from 'react'; - -import styles from './index.less'; - -export interface IFieldProps { - label: React.ReactNode; - value: React.ReactNode; - style?: React.CSSProperties; -} - -const Field: React.SFC = ({ label, value, ...rest }) => ( -
- {label} - {value} -
-); - -export default Field; diff --git a/src/pages/analysis/components/Charts/Gauge/index.tsx b/src/pages/analysis/components/Charts/Gauge/index.tsx deleted file mode 100644 index b5d33c60421e690358310fa418b909dbe2e30aca..0000000000000000000000000000000000000000 --- a/src/pages/analysis/components/Charts/Gauge/index.tsx +++ /dev/null @@ -1,177 +0,0 @@ -import React from 'react'; -import { Chart, Geom, Axis, Coord, Guide, Shape } from 'bizcharts'; -import autoHeight from '../autoHeight'; - -const { Arc, Html, Line } = Guide; - -export interface IGaugeProps { - title: React.ReactNode; - color?: string; - height?: number; - bgColor?: number; - percent: number; - forceFit?: boolean; - style?: React.CSSProperties; - formatter: (value: string) => string; -} - -const defaultFormatter = (val: string): string => { - switch (val) { - case '2': - return '差'; - case '4': - return '中'; - case '6': - return '良'; - case '8': - return '优'; - default: - return ''; - } -}; - -Shape.registerShape!('point', 'pointer', { - drawShape(cfg: any, group: any) { - let point = cfg.points[0]; - point = (this as any).parsePoint(point); - const center = (this as any).parsePoint({ - x: 0, - y: 0, - }); - group.addShape('line', { - attrs: { - x1: center.x, - y1: center.y, - x2: point.x, - y2: point.y, - stroke: cfg.color, - lineWidth: 2, - lineCap: 'round', - }, - }); - return group.addShape('circle', { - attrs: { - x: center.x, - y: center.y, - r: 6, - stroke: cfg.color, - lineWidth: 3, - fill: '#fff', - }, - }); - }, -}); - -class Gauge extends React.Component { - render() { - const { - title, - height = 1, - percent, - forceFit = true, - formatter = defaultFormatter, - color = '#2F9CFF', - bgColor = '#F0F2F5', - } = this.props; - const cols = { - value: { - type: 'linear', - min: 0, - max: 10, - tickCount: 6, - nice: true, - }, - }; - const renderHtml = () => ` -
-

${title}

-

- ${(data[0].value * 10).toFixed(2)}% -

-
`; - const data = [{ value: percent / 10 }]; - const textStyle: { - fontSize: number; - fill: string; - textAlign: 'center'; - } = { - fontSize: 12, - fill: 'rgba(0, 0, 0, 0.65)', - textAlign: 'center', - }; - return ( - - - - - - - - - - - - - - - ); - } -} - -export default autoHeight()(Gauge); diff --git a/src/pages/analysis/components/Charts/MiniArea/index.tsx b/src/pages/analysis/components/Charts/MiniArea/index.tsx deleted file mode 100644 index 5684aa51fb6c8cf3bbe5457c38a2dbe0168ef3c0..0000000000000000000000000000000000000000 --- a/src/pages/analysis/components/Charts/MiniArea/index.tsx +++ /dev/null @@ -1,133 +0,0 @@ -import React from 'react'; -import { Chart, Axis, Tooltip, Geom } from 'bizcharts'; -import autoHeight from '../autoHeight'; -import styles from '../index.less'; - -export interface IAxis { - title: any; - line: any; - gridAlign: any; - labels: any; - tickLine: any; - grid: any; -} - -export interface IMiniAreaProps { - color?: string; - height?: number; - borderColor?: string; - line?: boolean; - animate?: boolean; - xAxis?: IAxis; - forceFit?: boolean; - scale?: { x: any; y: any }; - yAxis?: IAxis; - borderWidth?: number; - data: Array<{ - x: number | string; - y: number; - }>; -} - -class MiniArea extends React.Component { - render() { - const { - height = 1, - data = [], - forceFit = true, - color = 'rgba(24, 144, 255, 0.2)', - borderColor = '#1089ff', - scale = { x: {}, y: {} }, - borderWidth = 2, - line, - xAxis, - yAxis, - animate = true, - } = this.props; - - const padding: [number, number, number, number] = [36, 5, 30, 5]; - - const scaleProps = { - x: { - type: 'cat', - range: [0, 1], - ...scale!.x, - }, - y: { - min: 0, - ...scale!.y, - }, - }; - - const tooltip: [string, (...args: any[]) => { name?: string; value: string }] = [ - 'x*y', - (x: string, y: string) => ({ - name: x, - value: y, - }), - ]; - - const chartHeight = height + 54; - - return ( -
-
- {height > 0 && ( - - - - - - {line ? ( - - ) : ( - - )} - - )} -
-
- ); - } -} - -export default autoHeight()(MiniArea); diff --git a/src/pages/analysis/components/Charts/MiniBar/index.tsx b/src/pages/analysis/components/Charts/MiniBar/index.tsx deleted file mode 100644 index d0fe9d4c160ddac885cf1246d455f675ba1822be..0000000000000000000000000000000000000000 --- a/src/pages/analysis/components/Charts/MiniBar/index.tsx +++ /dev/null @@ -1,61 +0,0 @@ -import React from 'react'; -import { Chart, Tooltip, Geom } from 'bizcharts'; -import autoHeight from '../autoHeight'; -import styles from '../index.less'; - -export interface IMiniBarProps { - color?: string; - height?: number; - data: Array<{ - x: number | string; - y: number; - }>; - forceFit?: boolean; - style?: React.CSSProperties; -} - -class MiniBar extends React.Component { - render() { - const { height = 0, forceFit = true, color = '#1890FF', data = [] } = this.props; - - const scale = { - x: { - type: 'cat', - }, - y: { - min: 0, - }, - }; - - const padding: [number, number, number, number] = [36, 5, 30, 5]; - - const tooltip: [string, (...args: any[]) => { name?: string; value: string }] = [ - 'x*y', - (x: string, y: string) => ({ - name: x, - value: y, - }), - ]; - - // for tooltip not to be hide - const chartHeight = height + 54; - - return ( -
-
- - - - -
-
- ); - } -} -export default autoHeight()(MiniBar); diff --git a/src/pages/analysis/components/Charts/MiniProgress/index.less b/src/pages/analysis/components/Charts/MiniProgress/index.less deleted file mode 100644 index e1e0b4fc5169615814efe60821f39dc3e1bc58b9..0000000000000000000000000000000000000000 --- a/src/pages/analysis/components/Charts/MiniProgress/index.less +++ /dev/null @@ -1,37 +0,0 @@ -@import '~antd/lib/style/themes/default.less'; - -.miniProgress { - position: relative; - width: 100%; - padding: 5px 0; - .progressWrap { - position: relative; - background-color: @background-color-base; - } - .progress { - width: 0; - height: 100%; - background-color: @primary-color; - border-radius: 1px 0 0 1px; - transition: all 0.4s cubic-bezier(0.08, 0.82, 0.17, 1) 0s; - } - .target { - position: absolute; - top: 0; - bottom: 0; - z-index: 9; - width: 20px; - span { - position: absolute; - top: 0; - left: 0; - width: 2px; - height: 4px; - border-radius: 100px; - } - span:last-child { - top: auto; - bottom: 0; - } - } -} diff --git a/src/pages/analysis/components/Charts/MiniProgress/index.tsx b/src/pages/analysis/components/Charts/MiniProgress/index.tsx deleted file mode 100644 index c0d1507dd4c5ff0d6d36f40897a910910df7a737..0000000000000000000000000000000000000000 --- a/src/pages/analysis/components/Charts/MiniProgress/index.tsx +++ /dev/null @@ -1,43 +0,0 @@ -import React from 'react'; -import { Tooltip } from 'antd'; -import styles from './index.less'; - -export interface IMiniProgressProps { - target: number; - targetLabel?: string; - color?: string; - strokeWidth?: number; - percent?: number; - style?: React.CSSProperties; -} - -const MiniProgress: React.SFC = ({ - targetLabel, - target, - color = 'rgb(19, 194, 194)', - strokeWidth, - percent, -}) => { - return ( -
- -
- - -
-
-
-
-
-
- ); -}; - -export default MiniProgress; diff --git a/src/pages/analysis/components/Charts/Pie/index.less b/src/pages/analysis/components/Charts/Pie/index.less deleted file mode 100644 index fc961b41df8831d2da6e7cf987b89e3624133fbc..0000000000000000000000000000000000000000 --- a/src/pages/analysis/components/Charts/Pie/index.less +++ /dev/null @@ -1,94 +0,0 @@ -@import '~antd/lib/style/themes/default.less'; - -.pie { - position: relative; - .chart { - position: relative; - } - &.hasLegend .chart { - width: ~'calc(100% - 240px)'; - } - .legend { - position: absolute; - top: 50%; - right: 0; - min-width: 200px; - margin: 0 20px; - padding: 0; - list-style: none; - transform: translateY(-50%); - li { - height: 22px; - margin-bottom: 16px; - line-height: 22px; - cursor: pointer; - &:last-child { - margin-bottom: 0; - } - } - } - .dot { - position: relative; - top: -1px; - display: inline-block; - width: 8px; - height: 8px; - margin-right: 8px; - border-radius: 8px; - } - .line { - display: inline-block; - width: 1px; - height: 16px; - margin-right: 8px; - background-color: @border-color-split; - } - .legendTitle { - color: @text-color; - } - .percent { - color: @text-color-secondary; - } - .value { - position: absolute; - right: 0; - } - .title { - margin-bottom: 8px; - } - .total { - position: absolute; - top: 50%; - left: 50%; - max-height: 62px; - text-align: center; - transform: translate(-50%, -50%); - & > h4 { - height: 22px; - margin-bottom: 8px; - color: @text-color-secondary; - font-weight: normal; - font-size: 14px; - line-height: 22px; - } - & > p { - display: block; - height: 32px; - color: @heading-color; - font-size: 1.2em; - line-height: 32px; - white-space: nowrap; - } - } -} - -.legendBlock { - &.hasLegend .chart { - width: 100%; - margin: 0 0 32px 0; - } - .legend { - position: relative; - transform: none; - } -} diff --git a/src/pages/analysis/components/Charts/Pie/index.tsx b/src/pages/analysis/components/Charts/Pie/index.tsx deleted file mode 100644 index 1b18f8a24900823147467bbb830c54c76d7df102..0000000000000000000000000000000000000000 --- a/src/pages/analysis/components/Charts/Pie/index.tsx +++ /dev/null @@ -1,306 +0,0 @@ -import React, { Component } from 'react'; -import { Chart, Tooltip, Geom, Coord } from 'bizcharts'; -import { DataView } from '@antv/data-set'; -import { Divider } from 'antd'; -import classNames from 'classnames'; -import ReactFitText from 'react-fittext'; -import Debounce from 'lodash-decorators/debounce'; -import Bind from 'lodash-decorators/bind'; -import styles from './index.less'; -import autoHeight from '../autoHeight'; -export interface IPieProps { - animate?: boolean; - color?: string; - colors?: string[]; - selected?: boolean; - height?: number; - margin?: [number, number, number, number]; - hasLegend?: boolean; - padding?: [number, number, number, number]; - percent?: number; - data?: Array<{ - x: string | string; - y: number; - }>; - inner?: number; - lineWidth?: number; - forceFit?: boolean; - style?: React.CSSProperties; - className?: string; - total?: React.ReactNode | number | (() => React.ReactNode | number); - title?: React.ReactNode; - tooltip?: boolean; - valueFormat?: (value: string) => string | React.ReactNode; - subTitle?: React.ReactNode; -} -interface IPieState { - legendData: Array<{ checked: boolean; x: string; color: string; percent: number; y: string }>; - legendBlock: boolean; -} -class Pie extends Component { - state: IPieState = { - legendData: [], - legendBlock: false, - }; - - requestRef: number | undefined; - root!: HTMLDivElement; - chart: G2.Chart | undefined; - - componentDidMount() { - window.addEventListener( - 'resize', - () => { - this.requestRef = requestAnimationFrame(() => this.resize()); - }, - { passive: true }, - ); - } - - componentDidUpdate(preProps: IPieProps) { - const { data } = this.props; - if (data !== preProps.data) { - // because of charts data create when rendered - // so there is a trick for get rendered time - this.getLegendData(); - } - } - - componentWillUnmount() { - if (this.requestRef) { - window.cancelAnimationFrame(this.requestRef); - } - window.removeEventListener('resize', this.resize); - if (this.resize) { - (this.resize as any).cancel(); - } - } - - getG2Instance = (chart: G2.Chart) => { - this.chart = chart; - requestAnimationFrame(() => { - this.getLegendData(); - this.resize(); - }); - }; - - // for custom lengend view - getLegendData = () => { - if (!this.chart) return; - const geom = this.chart.getAllGeoms()[0]; // 获取所有的图形 - if (!geom) return; - const items = geom.get('dataArray') || []; // 获取图形对应的 - - const legendData = items.map((item: { color: any; _origin: any }[]) => { - /* eslint no-underscore-dangle:0 */ - const origin = item[0]._origin; - origin.color = item[0].color; - origin.checked = true; - return origin; - }); - - this.setState({ - legendData, - }); - }; - handleRoot = (n: HTMLDivElement) => { - this.root = n; - }; - - handleLegendClick = (item: any, i: string | number) => { - const newItem = item; - newItem.checked = !newItem.checked; - - const { legendData } = this.state; - legendData[i] = newItem; - - const filteredLegendData = legendData.filter(l => l.checked).map(l => l.x); - - if (this.chart) { - this.chart.filter('x', val => filteredLegendData.indexOf(val + '') > -1); - } - - this.setState({ - legendData, - }); - }; - - // for window resize auto responsive legend - @Bind() - @Debounce(300) - resize() { - const { hasLegend } = this.props; - const { legendBlock } = this.state; - if (!hasLegend || !this.root) { - window.removeEventListener('resize', this.resize); - return; - } - if ( - this.root && - this.root.parentNode && - (this.root.parentNode as HTMLElement).clientWidth <= 380 - ) { - if (!legendBlock) { - this.setState({ - legendBlock: true, - }); - } - } else if (legendBlock) { - this.setState({ - legendBlock: false, - }); - } - } - - render() { - const { - valueFormat, - subTitle, - total, - hasLegend = false, - className, - style, - height = 0, - forceFit = true, - percent, - color, - inner = 0.75, - animate = true, - colors, - lineWidth = 1, - } = this.props; - - const { legendData, legendBlock } = this.state; - const pieClassName = classNames(styles.pie, className, { - [styles.hasLegend]: !!hasLegend, - [styles.legendBlock]: legendBlock, - }); - - const { - data: propsData, - selected: propsSelected = true, - tooltip: propsTooltip = true, - } = this.props; - - let data = propsData || []; - let selected = propsSelected; - let tooltip = propsTooltip; - - const defaultColors = colors; - data = data || []; - selected = selected || true; - tooltip = tooltip || true; - let formatColor; - - const scale = { - x: { - type: 'cat', - range: [0, 1], - }, - y: { - min: 0, - }, - }; - - if (percent || percent === 0) { - selected = false; - tooltip = false; - formatColor = (value: string) => { - if (value === '占比') { - return color || 'rgba(24, 144, 255, 0.85)'; - } - return '#F0F2F5'; - }; - - data = [ - { - x: '占比', - y: parseFloat(percent + ''), - }, - { - x: '反比', - y: 100 - parseFloat(percent + ''), - }, - ]; - } - - const tooltipFormat: [string, (...args: any[]) => { name?: string; value: string }] = [ - 'x*percent', - (x: string, p: number) => ({ - name: x, - value: `${(p * 100).toFixed(2)}%`, - }), - ]; - - const padding = [12, 0, 12, 0] as [number, number, number, number]; - - const dv = new DataView(); - dv.source(data).transform({ - type: 'percent', - field: 'y', - dimension: 'x', - as: 'percent', - }); - - return ( -
- -
- - {!!tooltip && } - - - - - {(subTitle || total) && ( -
- {subTitle &&

{subTitle}

} - {/* eslint-disable-next-line */} - {total && ( -
{typeof total === 'function' ? total() : total}
- )} -
- )} -
-
- {hasLegend && ( -
    - {legendData.map((item, i) => ( -
  • this.handleLegendClick(item, i)}> - - {item.x} - - - {`${(Number.isNaN(item.percent) ? 0 : item.percent * 100).toFixed(2)}%`} - - {valueFormat ? valueFormat(item.y) : item.y} -
  • - ))} -
- )} -
- ); - } -} - -export default autoHeight()(Pie); diff --git a/src/pages/analysis/components/Charts/TagCloud/index.less b/src/pages/analysis/components/Charts/TagCloud/index.less deleted file mode 100644 index db8e4dabfdd3f1fd4566ff22f55962648c369c49..0000000000000000000000000000000000000000 --- a/src/pages/analysis/components/Charts/TagCloud/index.less +++ /dev/null @@ -1,6 +0,0 @@ -.tagCloud { - overflow: hidden; - canvas { - transform-origin: 0 0; - } -} diff --git a/src/pages/analysis/components/Charts/TagCloud/index.tsx b/src/pages/analysis/components/Charts/TagCloud/index.tsx deleted file mode 100644 index fc809826df3e4d1f607ec83bb812d63f41fcbdd3..0000000000000000000000000000000000000000 --- a/src/pages/analysis/components/Charts/TagCloud/index.tsx +++ /dev/null @@ -1,206 +0,0 @@ -import React, { Component } from 'react'; -import { Chart, Geom, Coord, Shape, Tooltip } from 'bizcharts'; -import DataSet from '@antv/data-set'; -import Debounce from 'lodash-decorators/debounce'; -import Bind from 'lodash-decorators/bind'; -import classNames from 'classnames'; -import autoHeight from '../autoHeight'; -import styles from './index.less'; - -/* eslint no-underscore-dangle: 0 */ -/* eslint no-param-reassign: 0 */ - -const imgUrl = 'https://gw.alipayobjects.com/zos/rmsportal/gWyeGLCdFFRavBGIDzWk.png'; - -export interface ITagCloudProps { - data: Array<{ - name: string; - value: number; - }>; - height?: number; - className?: string; - style?: React.CSSProperties; -} - -interface ITagCloudState { - dv: any; - height?: number; - width: number; -} - -class TagCloud extends Component { - state = { - dv: null, - height: 0, - width: 0, - }; - isUnmount!: boolean; - requestRef!: number; - - root: HTMLDivElement | undefined; - imageMask: HTMLImageElement | undefined; - - componentDidMount() { - requestAnimationFrame(() => { - this.initTagCloud(); - this.renderChart(this.props); - }); - window.addEventListener('resize', this.resize, { passive: true }); - } - - componentDidUpdate(preProps?: ITagCloudProps) { - const { data } = this.props; - if (preProps && JSON.stringify(preProps.data) !== JSON.stringify(data)) { - this.renderChart(this.props); - } - } - componentWillUnmount() { - this.isUnmount = true; - window.cancelAnimationFrame(this.requestRef); - window.removeEventListener('resize', this.resize); - } - resize = () => { - this.requestRef = requestAnimationFrame(() => { - this.renderChart(this.props); - }); - }; - saveRootRef = (node: HTMLDivElement) => { - this.root = node; - }; - - initTagCloud = () => { - function getTextAttrs(cfg: { - x?: any; - y?: any; - style?: any; - opacity?: any; - origin?: any; - color?: any; - }) { - return Object.assign({}, cfg.style, { - fillOpacity: cfg.opacity, - fontSize: cfg.origin._origin.size, - rotate: cfg.origin._origin.rotate, - text: cfg.origin._origin.text, - textAlign: 'center', - fontFamily: cfg.origin._origin.font, - fill: cfg.color, - textBaseline: 'Alphabetic', - }); - } - - (Shape as any).registerShape('point', 'cloud', { - drawShape( - cfg: { x: any; y: any }, - container: { addShape: (arg0: string, arg1: { attrs: any }) => void }, - ) { - const attrs = getTextAttrs(cfg); - return container.addShape('text', { - attrs: Object.assign(attrs, { - x: cfg.x, - y: cfg.y, - }), - }); - }, - }); - }; - - @Bind() - @Debounce(500) - renderChart(nextProps: ITagCloudProps) { - // const colors = ['#1890FF', '#41D9C7', '#2FC25B', '#FACC14', '#9AE65C']; - const { data, height } = nextProps || this.props; - - if (data.length < 1 || !this.root) { - return; - } - - const h = height; - const w = this.root.offsetWidth; - - const onload = () => { - const dv = new DataSet.View().source(data); - const range = dv.range('value'); - const [min, max] = range; - dv.transform({ - type: 'tag-cloud', - fields: ['name', 'value'], - imageMask: this.imageMask, - font: 'Verdana', - size: [w, h], // 宽高设置最好根据 imageMask 做调整 - padding: 0, - timeInterval: 5000, // max execute time - rotate() { - return 0; - }, - fontSize(d: { value: number }) { - // eslint-disable-next-line - return Math.pow((d.value - min) / (max - min), 2) * (17.5 - 5) + 5; - }, - }); - - if (this.isUnmount) { - return; - } - - this.setState({ - dv, - width: w, - height: h, - }); - }; - - if (!this.imageMask) { - this.imageMask = new Image(); - this.imageMask.crossOrigin = ''; - this.imageMask.src = imgUrl; - - this.imageMask.onload = onload; - } else { - onload(); - } - } - - render() { - const { className, height } = this.props; - const { dv, width, height: stateHeight } = this.state; - - return ( -
- {dv && ( - - - - - - )} -
- ); - } -} - -export default autoHeight()(TagCloud); diff --git a/src/pages/analysis/components/Charts/TimelineChart/index.less b/src/pages/analysis/components/Charts/TimelineChart/index.less deleted file mode 100644 index 1751975692135769eebdcaf89ffafcf6b3037cb8..0000000000000000000000000000000000000000 --- a/src/pages/analysis/components/Charts/TimelineChart/index.less +++ /dev/null @@ -1,3 +0,0 @@ -.timelineChart { - background: #fff; -} diff --git a/src/pages/analysis/components/Charts/TimelineChart/index.tsx b/src/pages/analysis/components/Charts/TimelineChart/index.tsx deleted file mode 100644 index 2ccc37283623e27ff1cd48e7c569a683b1199684..0000000000000000000000000000000000000000 --- a/src/pages/analysis/components/Charts/TimelineChart/index.tsx +++ /dev/null @@ -1,133 +0,0 @@ -import React from 'react'; -import { Chart, Tooltip, Geom, Legend, Axis } from 'bizcharts'; -import DataSet from '@antv/data-set'; -import Slider from 'bizcharts-plugin-slider'; -import autoHeight from '../autoHeight'; -import styles from './index.less'; - -export interface ITimelineChartProps { - data: Array<{ - x: number; - y1: number; - y2: number; - }>; - title?: string; - titleMap: { y1: string; y2: string }; - padding?: [number, number, number, number]; - height?: number; - style?: React.CSSProperties; - borderWidth?: number; -} - -class TimelineChart extends React.Component { - render() { - const { - title, - height = 400, - padding = [60, 20, 40, 40] as [number, number, number, number], - titleMap = { - y1: 'y1', - y2: 'y2', - }, - borderWidth = 2, - data: sourceData, - } = this.props; - - const data = Array.isArray(sourceData) ? sourceData : [{ x: 0, y1: 0, y2: 0 }]; - - data.sort((a, b) => a.x - b.x); - - let max; - if (data[0] && data[0].y1 && data[0].y2) { - max = Math.max( - [...data].sort((a, b) => b.y1 - a.y1)[0].y1, - [...data].sort((a, b) => b.y2 - a.y2)[0].y2, - ); - } - - const ds = new DataSet({ - state: { - start: data[0].x, - end: data[data.length - 1].x, - }, - }); - - const dv = ds.createView(); - dv.source(data) - .transform({ - type: 'filter', - callback: (obj: { x: string }) => { - const date = obj.x; - return date <= ds.state.end && date >= ds.state.start; - }, - }) - .transform({ - type: 'map', - callback(row: { y1: string; y2: string }) { - const newRow = { ...row }; - newRow[titleMap.y1] = row.y1; - newRow[titleMap.y2] = row.y2; - return newRow; - }, - }) - .transform({ - type: 'fold', - fields: [titleMap.y1, titleMap.y2], // 展开字段集 - key: 'key', // key字段 - value: 'value', // value字段 - }); - - const timeScale = { - type: 'time', - tickInterval: 60 * 60 * 1000, - mask: 'HH:mm', - range: [0, 1], - }; - - const cols = { - x: timeScale, - value: { - max, - min: 0, - }, - }; - - const SliderGen = () => ( - { - ds.setState('start', startValue); - ds.setState('end', endValue); - }} - /> - ); - - return ( -
-
- {title &&

{title}

} - - - - - - -
- -
-
-
- ); - } -} - -export default autoHeight()(TimelineChart); diff --git a/src/pages/analysis/components/Charts/WaterWave/index.less b/src/pages/analysis/components/Charts/WaterWave/index.less deleted file mode 100644 index 2e75f21464300dd1d443329943b363b16fee1e97..0000000000000000000000000000000000000000 --- a/src/pages/analysis/components/Charts/WaterWave/index.less +++ /dev/null @@ -1,28 +0,0 @@ -@import '~antd/lib/style/themes/default.less'; - -.waterWave { - position: relative; - display: inline-block; - transform-origin: left; - .text { - position: absolute; - top: 32px; - left: 0; - width: 100%; - text-align: center; - span { - color: @text-color-secondary; - font-size: 14px; - line-height: 22px; - } - h4 { - color: @heading-color; - font-size: 24px; - line-height: 32px; - } - } - .waterWaveCanvasWrapper { - transform: scale(0.5); - transform-origin: 0 0; - } -} diff --git a/src/pages/analysis/components/Charts/WaterWave/index.tsx b/src/pages/analysis/components/Charts/WaterWave/index.tsx deleted file mode 100644 index 9dba82160b99756506399cfac2416c08206bf78e..0000000000000000000000000000000000000000 --- a/src/pages/analysis/components/Charts/WaterWave/index.tsx +++ /dev/null @@ -1,230 +0,0 @@ -import React, { Component } from 'react'; -import autoHeight from '../autoHeight'; -import styles from './index.less'; - -/* eslint no-return-assign: 0 */ -/* eslint no-mixed-operators: 0 */ -// riddle: https://riddle.alibaba-inc.com/riddles/2d9a4b90 - -export interface IWaterWaveProps { - title: React.ReactNode; - color?: string; - height?: number; - percent: number; - style?: React.CSSProperties; -} - -class WaterWave extends Component { - state = { - radio: 1, - }; - timer: number = 0; - root: HTMLDivElement | undefined | null; - node: HTMLCanvasElement | undefined | null; - - componentDidMount() { - this.renderChart(); - this.resize(); - window.addEventListener( - 'resize', - () => { - requestAnimationFrame(() => this.resize()); - }, - { passive: true }, - ); - } - - componentDidUpdate(props: IWaterWaveProps) { - const { percent } = this.props; - if (props.percent !== percent) { - // 不加这个会造成绘制缓慢 - this.renderChart('update'); - } - } - - componentWillUnmount() { - cancelAnimationFrame(this.timer); - if (this.node) { - this.node.innerHTML = ''; - } - window.removeEventListener('resize', this.resize); - } - - resize = () => { - if (this.root) { - const { height = 1 } = this.props; - const { offsetWidth } = this.root.parentNode as HTMLElement; - this.setState({ - radio: offsetWidth < height ? offsetWidth / height : 1, - }); - } - }; - renderChart(type?: string) { - const { percent, color = '#1890FF' } = this.props; - const data = percent / 100; - const self = this; - cancelAnimationFrame(this.timer); - - if (!this.node || (data !== 0 && !data)) { - return; - } - - const canvas = this.node; - const ctx = canvas.getContext('2d'); - if (!ctx) { - return; - } - const canvasWidth = canvas.width; - const canvasHeight = canvas.height; - const radius = canvasWidth / 2; - const lineWidth = 2; - const cR = radius - lineWidth; - - ctx.beginPath(); - ctx.lineWidth = lineWidth * 2; - - const axisLength = canvasWidth - lineWidth; - const unit = axisLength / 8; - const range = 0.2; // 振幅 - let currRange = range; - const xOffset = lineWidth; - let sp = 0; // 周期偏移量 - let currData = 0; - const waveupsp = 0.005; // 水波上涨速度 - - let arcStack: number[][] = []; - const bR = radius - lineWidth; - const circleOffset = -(Math.PI / 2); - let circleLock = true; - - for (let i = circleOffset; i < circleOffset + 2 * Math.PI; i += 1 / (8 * Math.PI)) { - arcStack.push([radius + bR * Math.cos(i), radius + bR * Math.sin(i)]); - } - - const cStartPoint = arcStack.shift() as number[]; - ctx.strokeStyle = color; - ctx.moveTo(cStartPoint[0], cStartPoint[1]); - - function drawSin() { - if (!ctx) { - return; - } - ctx.beginPath(); - ctx.save(); - - const sinStack = []; - for (let i = xOffset; i <= xOffset + axisLength; i += 20 / axisLength) { - const x = sp + (xOffset + i) / unit; - const y = Math.sin(x) * currRange; - const dx = i; - const dy = 2 * cR * (1 - currData) + (radius - cR) - unit * y; - - ctx.lineTo(dx, dy); - sinStack.push([dx, dy]); - } - - const startPoint = sinStack.shift() as number[]; - - ctx.lineTo(xOffset + axisLength, canvasHeight); - ctx.lineTo(xOffset, canvasHeight); - ctx.lineTo(startPoint[0], startPoint[1]); - - const gradient = ctx.createLinearGradient(0, 0, 0, canvasHeight); - gradient.addColorStop(0, '#ffffff'); - gradient.addColorStop(1, color); - ctx.fillStyle = gradient; - ctx.fill(); - ctx.restore(); - } - - function render() { - if (!ctx) { - return; - } - ctx.clearRect(0, 0, canvasWidth, canvasHeight); - if (circleLock && type !== 'update') { - if (arcStack.length) { - const temp = arcStack.shift() as number[]; - ctx.lineTo(temp[0], temp[1]); - ctx.stroke(); - } else { - circleLock = false; - ctx.lineTo(cStartPoint[0], cStartPoint[1]); - ctx.stroke(); - arcStack = []; - - ctx.globalCompositeOperation = 'destination-over'; - ctx.beginPath(); - ctx.lineWidth = lineWidth; - ctx.arc(radius, radius, bR, 0, 2 * Math.PI, true); - - ctx.beginPath(); - ctx.save(); - ctx.arc(radius, radius, radius - 3 * lineWidth, 0, 2 * Math.PI, true); - - ctx.restore(); - ctx.clip(); - ctx.fillStyle = color; - } - } else { - if (data >= 0.85) { - if (currRange > range / 4) { - const t = range * 0.01; - currRange -= t; - } - } else if (data <= 0.1) { - if (currRange < range * 1.5) { - const t = range * 0.01; - currRange += t; - } - } else { - if (currRange <= range) { - const t = range * 0.01; - currRange += t; - } - if (currRange >= range) { - const t = range * 0.01; - currRange -= t; - } - } - if (data - currData > 0) { - currData += waveupsp; - } - if (data - currData < 0) { - currData -= waveupsp; - } - - sp += 0.07; - drawSin(); - } - self.timer = requestAnimationFrame(render); - } - render(); - } - render() { - const { radio } = this.state; - const { percent, title, height = 1 } = this.props; - return ( -
(this.root = n)} - style={{ transform: `scale(${radio})` }} - > -
- (this.node = n)} - width={height * 2} - height={height * 2} - /> -
-
- {title && {title}} -

{percent}%

-
-
- ); - } -} - -export default autoHeight()(WaterWave); diff --git a/src/pages/analysis/components/Charts/autoHeight.tsx b/src/pages/analysis/components/Charts/autoHeight.tsx deleted file mode 100644 index e7d14e07a6be59b9125bcc910c07ba9b162b5409..0000000000000000000000000000000000000000 --- a/src/pages/analysis/components/Charts/autoHeight.tsx +++ /dev/null @@ -1,75 +0,0 @@ -import React from 'react'; - -export type IReactComponent

= - | React.StatelessComponent

- | React.ComponentClass

- | React.ClassicComponentClass

; - -function computeHeight(node: HTMLDivElement) { - node.style.height = '100%'; - const totalHeight = parseInt(getComputedStyle(node).height + '', 10); - const padding = - parseInt(getComputedStyle(node).paddingTop + '', 10) + - parseInt(getComputedStyle(node).paddingBottom + '', 10); - return totalHeight - padding; -} - -function getAutoHeight(n: HTMLDivElement) { - if (!n) { - return 0; - } - - const node = n; - - let height = computeHeight(node); - const parentNode = node.parentNode as HTMLDivElement; - if (parentNode) { - height = computeHeight(parentNode); - } - - return height; -} - -interface IAutoHeightProps { - height?: number; -} - -function autoHeight() { - return function

( - WrappedComponent: React.ComponentClass

| React.SFC

, - ): React.ComponentClass

{ - class AutoHeightComponent extends React.Component

{ - state = { - computedHeight: 0, - }; - root!: HTMLDivElement; - componentDidMount() { - const { height } = this.props; - if (!height) { - let h = getAutoHeight(this.root); - // eslint-disable-next-line - this.setState({ computedHeight: h }); - if (h < 1) { - h = getAutoHeight(this.root); - this.setState({ computedHeight: h }); - } - } - } - handleRoot = (node: HTMLDivElement) => { - this.root = node; - }; - render() { - const { height } = this.props; - const { computedHeight } = this.state; - const h = height || computedHeight; - return ( -

- {h > 0 && } -
- ); - } - } - return AutoHeightComponent; - }; -} -export default autoHeight; diff --git a/src/pages/analysis/components/Charts/bizcharts.d.ts b/src/pages/analysis/components/Charts/bizcharts.d.ts deleted file mode 100644 index 0815ffeeffcacd0ac9710977ab3d4419d078491c..0000000000000000000000000000000000000000 --- a/src/pages/analysis/components/Charts/bizcharts.d.ts +++ /dev/null @@ -1,3 +0,0 @@ -import * as BizChart from 'bizcharts'; - -export = BizChart; diff --git a/src/pages/analysis/components/Charts/bizcharts.tsx b/src/pages/analysis/components/Charts/bizcharts.tsx deleted file mode 100644 index e08db8d6d2dca240451bdf6ab8a30be077a3fd9d..0000000000000000000000000000000000000000 --- a/src/pages/analysis/components/Charts/bizcharts.tsx +++ /dev/null @@ -1,3 +0,0 @@ -import * as BizChart from 'bizcharts'; - -export default BizChart; diff --git a/src/pages/analysis/components/Charts/index.less b/src/pages/analysis/components/Charts/index.less deleted file mode 100644 index 190428bc80d7cd7f6f22d51fd48fa37b2d44eb10..0000000000000000000000000000000000000000 --- a/src/pages/analysis/components/Charts/index.less +++ /dev/null @@ -1,19 +0,0 @@ -.miniChart { - position: relative; - width: 100%; - .chartContent { - position: absolute; - bottom: -28px; - width: 100%; - > div { - margin: 0 -5px; - overflow: hidden; - } - } - .chartLoading { - position: absolute; - top: 16px; - left: 50%; - margin-left: -7px; - } -} diff --git a/src/pages/analysis/components/Charts/index.tsx b/src/pages/analysis/components/Charts/index.tsx deleted file mode 100644 index 5e0815f18ef573549dfc4c13de317568d02db80c..0000000000000000000000000000000000000000 --- a/src/pages/analysis/components/Charts/index.tsx +++ /dev/null @@ -1,45 +0,0 @@ -import numeral from 'numeral'; -import ChartCard from './ChartCard'; -import Field from './Field'; -import Bar from './Bar'; -import Pie from './Pie'; -import Gauge from './Gauge'; -import MiniArea from './MiniArea'; -import MiniBar from './MiniBar'; -import MiniProgress from './MiniProgress'; -import WaterWave from './WaterWave'; -import TagCloud from './TagCloud'; -import TimelineChart from './TimelineChart'; - -const yuan = (val: number | string) => `¥ ${numeral(val).format('0,0')}`; - -const Charts = { - yuan, - Bar, - Pie, - Gauge, - MiniBar, - MiniArea, - MiniProgress, - ChartCard, - Field, - WaterWave, - TagCloud, - TimelineChart, -}; - -export { - Charts as default, - yuan, - Bar, - Pie, - Gauge, - MiniBar, - MiniArea, - MiniProgress, - ChartCard, - Field, - WaterWave, - TagCloud, - TimelineChart, -}; diff --git a/src/pages/analysis/components/IntroduceRow.tsx b/src/pages/analysis/components/IntroduceRow.tsx deleted file mode 100755 index ee2cf44dc016a8e3d89bdcee4b79296cdbd8ee4b..0000000000000000000000000000000000000000 --- a/src/pages/analysis/components/IntroduceRow.tsx +++ /dev/null @@ -1,162 +0,0 @@ -import React from 'react'; -import { Row, Col, Icon, Tooltip } from 'antd'; -import { FormattedMessage } from 'umi-plugin-react/locale'; -import Charts from './Charts'; -import numeral from 'numeral'; -import styles from '../style.less'; -import Yuan from '../utils/Yuan'; -import Trend from './Trend'; -import { IVisitData } from '../data.d'; -const { ChartCard, MiniArea, MiniBar, MiniProgress, Field } = Charts; - -const topColResponsiveProps = { - xs: 24, - sm: 12, - md: 12, - lg: 12, - xl: 6, - style: { marginBottom: 24 }, -}; - -const IntroduceRow = ({ loading, visitData }: { loading: boolean; visitData: IVisitData[] }) => { - return ( - - - - } - action={ - - } - > - - - } - loading={loading} - total={() => 126560} - footer={ - - } - value={`¥${numeral(12423).format('0,0')}`} - /> - } - contentHeight={46} - > - - - 12% - - - - 11% - - - - - - } - action={ - - } - > - - - } - total={numeral(8846).format('0,0')} - footer={ - - } - value={numeral(1234).format('0,0')} - /> - } - contentHeight={46} - > - - - - - } - action={ - - } - > - - - } - total={numeral(6560).format('0,0')} - footer={ - - } - value="60%" - /> - } - contentHeight={46} - > - - - - - - } - action={ - - } - > - - - } - total="78%" - footer={ -
- - - 12% - - - - 11% - -
- } - contentHeight={46} - > - -
- -
- ); -}; - -export default IntroduceRow; diff --git a/src/pages/analysis/components/NumberInfo/index.less b/src/pages/analysis/components/NumberInfo/index.less deleted file mode 100644 index 4a77288cc29d4bc24aa9ee660461bd44cb049897..0000000000000000000000000000000000000000 --- a/src/pages/analysis/components/NumberInfo/index.less +++ /dev/null @@ -1,68 +0,0 @@ -@import '~antd/lib/style/themes/default.less'; - -.numberInfo { - .suffix { - margin-left: 4px; - color: @text-color; - font-size: 16px; - font-style: normal; - } - .numberInfoTitle { - margin-bottom: 16px; - color: @text-color; - font-size: @font-size-lg; - transition: all 0.3s; - } - .numberInfoSubTitle { - height: 22px; - overflow: hidden; - color: @text-color-secondary; - font-size: @font-size-base; - line-height: 22px; - white-space: nowrap; - text-overflow: ellipsis; - word-break: break-all; - } - .numberInfoValue { - margin-top: 4px; - overflow: hidden; - font-size: 0; - white-space: nowrap; - text-overflow: ellipsis; - word-break: break-all; - & > span { - display: inline-block; - height: 32px; - margin-right: 32px; - color: @heading-color; - font-size: 24px; - line-height: 32px; - } - .subTotal { - margin-right: 0; - color: @text-color-secondary; - font-size: @font-size-lg; - vertical-align: top; - i { - margin-left: 4px; - font-size: 12px; - transform: scale(0.82); - } - :global { - .anticon-caret-up { - color: @red-6; - } - .anticon-caret-down { - color: @green-6; - } - } - } - } -} -.numberInfolight { - .numberInfoValue { - & > span { - color: @text-color; - } - } -} diff --git a/src/pages/analysis/components/NumberInfo/index.tsx b/src/pages/analysis/components/NumberInfo/index.tsx deleted file mode 100644 index a8df6e6d94efbd2dc579d315b28ba64cb4d20859..0000000000000000000000000000000000000000 --- a/src/pages/analysis/components/NumberInfo/index.tsx +++ /dev/null @@ -1,61 +0,0 @@ -import React from 'react'; -import { Icon } from 'antd'; -import classNames from 'classnames'; -import styles from './index.less'; -export interface NumberInfoProps { - title?: React.ReactNode | string; - subTitle?: React.ReactNode | string; - total?: React.ReactNode | string; - status?: 'up' | 'down'; - theme?: string; - gap?: number; - subTotal?: number; - suffix?: string; - style?: React.CSSProperties; -} -const NumberInfo: React.SFC = ({ - theme, - title, - subTitle, - total, - subTotal, - status, - suffix, - gap, - ...rest -}) => ( -
- {title && ( -
- {title} -
- )} - {subTitle && ( -
- {subTitle} -
- )} -
- - {total} - {suffix && {suffix}} - - {(status || subTotal) && ( - - {subTotal} - {status && } - - )} -
-
-); - -export default NumberInfo; diff --git a/src/pages/analysis/components/OfflineData.tsx b/src/pages/analysis/components/OfflineData.tsx deleted file mode 100755 index 64864bdc20955cfb39083cbdccb68c1b532ca613..0000000000000000000000000000000000000000 --- a/src/pages/analysis/components/OfflineData.tsx +++ /dev/null @@ -1,82 +0,0 @@ -import React from 'react'; -import { Card, Tabs, Row, Col } from 'antd'; -import { formatMessage, FormattedMessage } from 'umi-plugin-react/locale'; -import Charts from './Charts'; -import styles from '../style.less'; -import NumberInfo from './NumberInfo'; -import { IOfflineData, IOfflineChartData } from '../data'; -const { TimelineChart, Pie } = Charts; - -const CustomTab = ({ - data, - currentTabKey: currentKey, -}: { - data: IOfflineData; - currentTabKey: string; -}) => { - return ( - - - - } - gap={2} - total={`${data.cvr * 100}%`} - theme={currentKey !== data.name ? 'light' : undefined} - /> - - - - - - ); -}; - -const { TabPane } = Tabs; - -const OfflineData = ({ - activeKey, - loading, - offlineData, - offlineChartData, - handleTabChange, -}: { - activeKey: string; - loading: boolean; - offlineData: IOfflineData[]; - offlineChartData: IOfflineChartData[]; - handleTabChange: (activeKey: string) => void; -}) => ( - - - {offlineData.map(shop => ( - } key={shop.name}> -
- -
-
- ))} -
-
-); - -export default OfflineData; diff --git a/src/pages/analysis/components/PageLoading/index.tsx b/src/pages/analysis/components/PageLoading/index.tsx deleted file mode 100644 index 77c0f165f9d20b4f974e754efb9cf08606c41a49..0000000000000000000000000000000000000000 --- a/src/pages/analysis/components/PageLoading/index.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import React from 'react'; -import { Spin } from 'antd'; - -// loading components from code split -// https://umijs.org/plugin/umi-plugin-react.html#dynamicimport -export default () => ( -
- -
-); diff --git a/src/pages/analysis/components/ProportionSales.tsx b/src/pages/analysis/components/ProportionSales.tsx deleted file mode 100755 index b82888ef23fe2a1b29eafc6302bb25af9c436412..0000000000000000000000000000000000000000 --- a/src/pages/analysis/components/ProportionSales.tsx +++ /dev/null @@ -1,79 +0,0 @@ -import React from 'react'; -import { Card, Radio } from 'antd'; -import Charts from './Charts'; -import { FormattedMessage } from 'umi-plugin-react/locale'; -import styles from '../style.less'; -import Yuan from '../utils/Yuan'; -import { RadioChangeEvent } from 'antd/lib/radio'; -import { ISalesData } from '../data'; - -const { Pie } = Charts; - -const ProportionSales = ({ - dropdownGroup, - salesType, - loading, - salesPieData, - handleChangeSalesType, -}: { - loading: boolean; - dropdownGroup: React.ReactNode; - salesType: 'all' | 'online' | 'stores'; - salesPieData: ISalesData[]; - handleChangeSalesType?: (e: RadioChangeEvent) => void; -}) => { - return ( - - } - bodyStyle={{ padding: 24 }} - extra={ -
- {dropdownGroup} -
- - - - - - - - - - - -
-
- } - style={{ marginTop: 24 }} - > -
-

- -

- } - total={() => {salesPieData.reduce((pre, now) => now.y + pre, 0)}} - data={salesPieData} - valueFormat={value => {value}} - height={248} - lineWidth={4} - /> -
-
- ); -}; - -export default ProportionSales; diff --git a/src/pages/analysis/components/SalesCard.tsx b/src/pages/analysis/components/SalesCard.tsx deleted file mode 100755 index 05be982318ecf6df1b8483617ed881f7772712f8..0000000000000000000000000000000000000000 --- a/src/pages/analysis/components/SalesCard.tsx +++ /dev/null @@ -1,162 +0,0 @@ -import React from 'react'; -import { Row, Col, Card, Tabs, DatePicker } from 'antd'; -import { FormattedMessage, formatMessage } from 'umi-plugin-react/locale'; -import numeral from 'numeral'; -import Charts from './Charts'; -import { RangePickerValue } from 'antd/lib/date-picker/interface'; -import { ISalesData } from '../data'; -import styles from '../style.less'; - -const { Bar } = Charts; - -const { RangePicker } = DatePicker; -const { TabPane } = Tabs; - -const rankingListData: { title: string; total: number }[] = []; -for (let i = 0; i < 7; i += 1) { - rankingListData.push({ - title: formatMessage({ id: 'analysis.analysis.test' }, { no: i }), - total: 323234, - }); -} - -const SalesCard = ({ - rangePickerValue, - salesData, - isActive, - handleRangePickerChange, - loading, - selectDate, -}: { - rangePickerValue: RangePickerValue; - isActive: (key: 'today' | 'week' | 'month' | 'year') => string; - salesData: ISalesData[]; - loading: boolean; - handleRangePickerChange: (dates: RangePickerValue, dateStrings: [string, string]) => void; - selectDate: (key: 'today' | 'week' | 'month' | 'year') => void; -}) => ( - - - } - size="large" - tabBarStyle={{ marginBottom: 24 }} - > - } - key="sales" - > - - -
- - } - data={salesData} - /> -
- - -
-

- -

-
    - {rankingListData.map((item, i) => ( -
  • - - {i + 1} - - - {item.title} - - - {numeral(item.total).format('0,0')} - -
  • - ))} -
-
- -
-
- } - key="views" - > - - -
- - } - data={salesData} - /> -
- - -
-

- -

-
    - {rankingListData.map((item, i) => ( -
  • - - {i + 1} - - - {item.title} - - {numeral(item.total).format('0,0')} -
  • - ))} -
-
- -
-
- -
- -); - -export default SalesCard; diff --git a/src/pages/analysis/components/TopSearch.tsx b/src/pages/analysis/components/TopSearch.tsx deleted file mode 100755 index 717b6e35345a63eb8eb757272480135c3091a00f..0000000000000000000000000000000000000000 --- a/src/pages/analysis/components/TopSearch.tsx +++ /dev/null @@ -1,128 +0,0 @@ -import React from 'react'; -import { Row, Col, Table, Tooltip, Card, Icon } from 'antd'; -import { FormattedMessage } from 'umi-plugin-react/locale'; -import Charts from './Charts'; -import Trend from './Trend'; -import NumberInfo from './NumberInfo'; -import numeral from 'numeral'; -import styles from '../style.less'; -import { ISearchData, IVisitData2 } from '../data'; - -const { MiniArea } = Charts; - -const columns = [ - { - title: , - dataIndex: 'index', - key: 'index', - }, - { - title: , - dataIndex: 'keyword', - key: 'keyword', - render: (text: React.ReactNode) => {text}, - }, - { - title: , - dataIndex: 'count', - key: 'count', - sorter: (a: { count: number }, b: { count: number }) => a.count - b.count, - className: styles.alignRight, - }, - { - title: , - dataIndex: 'range', - key: 'range', - sorter: (a: { range: number }, b: { range: number }) => a.range - b.range, - render: (text: React.ReactNode, record: { status: number }) => ( - - {text}% - - ), - }, -]; - -const TopSearch = ({ - loading, - visitData2, - searchData, - dropdownGroup, -}: { - loading: boolean; - visitData2: IVisitData2[]; - dropdownGroup: React.ReactNode; - searchData: ISearchData[]; -}) => ( - - } - extra={dropdownGroup} - style={{ marginTop: 24 }} - > - - - - - - } - > - - - - } - gap={8} - total={numeral(12321).format('0,0')} - status="up" - subTotal={17.1} - /> - - - - - - - } - > - - - - } - total={2.7} - status="down" - subTotal={26.2} - gap={8} - /> - - - - - rowKey={record => record.index} - size="small" - columns={columns} - dataSource={searchData} - pagination={{ - style: { marginBottom: 0 }, - pageSize: 5, - }} - /> - -); - -export default TopSearch; diff --git a/src/pages/analysis/components/Trend/index.less b/src/pages/analysis/components/Trend/index.less deleted file mode 100644 index 13618838afcd46f1fc0e724097a0af938ca6f7b3..0000000000000000000000000000000000000000 --- a/src/pages/analysis/components/Trend/index.less +++ /dev/null @@ -1,37 +0,0 @@ -@import '~antd/lib/style/themes/default.less'; - -.trendItem { - display: inline-block; - font-size: @font-size-base; - line-height: 22px; - - .up, - .down { - position: relative; - top: 1px; - margin-left: 4px; - i { - font-size: 12px; - transform: scale(0.83); - } - } - .up { - color: @red-6; - } - .down { - top: -1px; - color: @green-6; - } - - &.trendItemGrey .up, - &.trendItemGrey .down { - color: @text-color; - } - - &.reverseColor .up { - color: @green-6; - } - &.reverseColor .down { - color: @red-6; - } -} diff --git a/src/pages/analysis/components/Trend/index.tsx b/src/pages/analysis/components/Trend/index.tsx deleted file mode 100644 index ee8df20ea51db0e14fe78c12ecf622a6f2772b96..0000000000000000000000000000000000000000 --- a/src/pages/analysis/components/Trend/index.tsx +++ /dev/null @@ -1,42 +0,0 @@ -import React from 'react'; -import { Icon } from 'antd'; -import classNames from 'classnames'; -import styles from './index.less'; - -export interface ITrendProps { - colorful?: boolean; - flag: 'up' | 'down'; - style?: React.CSSProperties; - reverseColor?: boolean; - className?: string; -} - -const Trend: React.SFC = ({ - colorful = true, - reverseColor = false, - flag, - children, - className, - ...rest -}) => { - const classString = classNames( - styles.trendItem, - { - [styles.trendItemGrey]: !colorful, - [styles.reverseColor]: reverseColor && colorful, - }, - className, - ); - return ( -
- {children} - {flag && ( - - - - )} -
- ); -}; - -export default Trend; diff --git a/src/pages/analysis/data.d.ts b/src/pages/analysis/data.d.ts deleted file mode 100644 index 20df2e20dc6eeeff67414b3f6f50d8bfaeb7d62e..0000000000000000000000000000000000000000 --- a/src/pages/analysis/data.d.ts +++ /dev/null @@ -1,67 +0,0 @@ -export interface IVisitData { - x: string; - y: number; -} - -export interface IVisitData2 { - x: string; - y: number; -} - -export interface ISalesData { - x: string; - y: number; -} - -export interface ISearchData { - index: number; - keyword: string; - count: number; - range: number; - status: number; -} - -export interface IOfflineData { - name: string; - cvr: number; -} - -export interface IOfflineChartData { - x: any; - y1: number; - y2: number; -} - -export interface ISalesTypeData { - x: string; - y: number; -} - -export interface ISalesTypeDataOnline { - x: string; - y: number; -} - -export interface ISalesTypeDataOffline { - x: string; - y: number; -} - -export interface IRadarData { - name: string; - label: string; - value: number; -} - -export interface IAnalysisData { - visitData: IVisitData[]; - visitData2: IVisitData2[]; - salesData: ISalesData[]; - searchData: ISearchData[]; - offlineData: IOfflineData[]; - offlineChartData: IOfflineChartData[]; - salesTypeData: ISalesTypeData[]; - salesTypeDataOnline: ISalesTypeDataOnline[]; - salesTypeDataOffline: ISalesTypeDataOffline[]; - radarData: IRadarData[]; -} diff --git a/src/pages/analysis/index.tsx b/src/pages/analysis/index.tsx deleted file mode 100644 index 00d7e34c9e1b0d32c406b3c4a2a94e313621a3f6..0000000000000000000000000000000000000000 --- a/src/pages/analysis/index.tsx +++ /dev/null @@ -1,215 +0,0 @@ -import React, { Component, Suspense } from 'react'; -import { connect } from 'dva'; -import { Row, Col, Icon, Menu, Dropdown } from 'antd'; -import { RangePickerValue } from 'antd/lib/date-picker/interface'; -import { getTimeDistance } from './utils/utils'; -import styles from './style.less'; -import PageLoading from './components/PageLoading'; -import { Dispatch } from 'redux'; -import { IAnalysisData } from './data.d'; -import { RadioChangeEvent } from 'antd/lib/radio'; -import { GridContent } from '@ant-design/pro-layout'; - -const IntroduceRow = React.lazy(() => import('./components/IntroduceRow')); -const SalesCard = React.lazy(() => import('./components/SalesCard')); -const TopSearch = React.lazy(() => import('./components/TopSearch')); -const ProportionSales = React.lazy(() => import('./components/ProportionSales')); -const OfflineData = React.lazy(() => import('./components/OfflineData')); - -interface AnalysisProps { - analysis: IAnalysisData; - dispatch: Dispatch; - loading: boolean; -} - -interface AnalysisState { - salesType: 'all' | 'online' | 'stores'; - currentTabKey: string; - rangePickerValue: RangePickerValue; -} - -@connect( - ({ - analysis, - loading, - }: { - analysis: any; - loading: { - effects: { [key: string]: boolean }; - }; - }) => ({ - analysis, - loading: loading.effects['analysis/fetch'], - }), -) -class Analysis extends Component { - state: AnalysisState = { - salesType: 'all', - currentTabKey: '', - rangePickerValue: getTimeDistance('year'), - }; - reqRef!: number; - timeoutId!: number; - componentDidMount() { - const { dispatch } = this.props; - this.reqRef = requestAnimationFrame(() => { - dispatch({ - type: 'analysis/fetch', - }); - }); - setTimeout(() => { - this.setState({ - loading: false, - }); - }, 2000); - } - - componentWillUnmount() { - const { dispatch } = this.props; - dispatch({ - type: 'analysis/clear', - }); - cancelAnimationFrame(this.reqRef); - clearTimeout(this.timeoutId); - } - - handleChangeSalesType = (e: RadioChangeEvent) => { - this.setState({ - salesType: e.target.value, - }); - }; - - handleTabChange = (key: string) => { - this.setState({ - currentTabKey: key, - }); - }; - - handleRangePickerChange = (rangePickerValue: RangePickerValue) => { - const { dispatch } = this.props; - this.setState({ - rangePickerValue, - }); - - dispatch({ - type: 'analysis/fetchSalesData', - }); - }; - - selectDate = (type: 'today' | 'week' | 'month' | 'year') => { - const { dispatch } = this.props; - this.setState({ - rangePickerValue: getTimeDistance(type), - }); - - dispatch({ - type: 'analysis/fetchSalesData', - }); - }; - - isActive = (type: 'today' | 'week' | 'month' | 'year') => { - 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, currentTabKey } = this.state; - const { analysis, loading } = this.props; - const { - visitData, - visitData2, - salesData, - searchData, - offlineData, - offlineChartData, - salesTypeData, - salesTypeDataOnline, - salesTypeDataOffline, - } = analysis; - let salesPieData; - if (salesType === 'all') { - salesPieData = salesTypeData; - } else { - salesPieData = salesType === 'online' ? salesTypeDataOnline : salesTypeDataOffline; - } - const menu = ( - - 操作一 - 操作二 - - ); - - const dropdownGroup = ( - - - - - - ); - - const activeKey = currentTabKey || (offlineData[0] && offlineData[0].name); - return ( - - - }> - - - - - - - - - - - - - - - - - - - - - - - ); - } -} - -export default Analysis; diff --git a/src/pages/analysis/locales/en-US.ts b/src/pages/analysis/locales/en-US.ts deleted file mode 100644 index a0a03f22105a642ceea239c470fc72bd7b634687..0000000000000000000000000000000000000000 --- a/src/pages/analysis/locales/en-US.ts +++ /dev/null @@ -1,34 +0,0 @@ -export default { - 'analysis.analysis.test': 'Gongzhuan No.{no} shop', - 'analysis.analysis.introduce': 'Introduce', - 'analysis.analysis.total-sales': 'Total Sales', - 'analysis.analysis.day-sales': 'Daily Sales', - 'analysis.analysis.visits': 'Visits', - 'analysis.analysis.visits-trend': 'Visits Trend', - 'analysis.analysis.visits-ranking': 'Visits Ranking', - 'analysis.analysis.day-visits': 'Daily Visits', - 'analysis.analysis.week': 'WoW Change', - 'analysis.analysis.day': 'DoD Change', - 'analysis.analysis.payments': 'Payments', - 'analysis.analysis.conversion-rate': 'Conversion Rate', - 'analysis.analysis.operational-effect': 'Operational Effect', - 'analysis.analysis.sales-trend': 'Stores Sales Trend', - 'analysis.analysis.sales-ranking': 'Sales Ranking', - 'analysis.analysis.all-year': 'All Year', - 'analysis.analysis.all-month': 'All Month', - 'analysis.analysis.all-week': 'All Week', - 'analysis.analysis.all-day': 'All day', - 'analysis.analysis.search-users': 'Search Users', - 'analysis.analysis.per-capita-search': 'Per Capita Search', - 'analysis.analysis.online-top-search': 'Online Top Search', - 'analysis.analysis.the-proportion-of-sales': 'The Proportion Of Sales', - 'analysis.channel.all': 'ALL', - 'analysis.channel.online': 'Online', - 'analysis.channel.stores': 'Stores', - 'analysis.analysis.sales': 'Sales', - 'analysis.analysis.traffic': 'Traffic', - 'analysis.table.rank': 'Rank', - 'analysis.table.search-keyword': 'Keyword', - 'analysis.table.users': 'Users', - 'analysis.table.weekly-range': 'Weekly Range', -}; diff --git a/src/pages/analysis/locales/pt-BR.ts b/src/pages/analysis/locales/pt-BR.ts deleted file mode 100644 index 7be015713ba9fc34fc103a641ca5d5d8c89785ea..0000000000000000000000000000000000000000 --- a/src/pages/analysis/locales/pt-BR.ts +++ /dev/null @@ -1,34 +0,0 @@ -export default { - 'analysis.analysis.test': 'Gongzhuan No.{no} shop', - 'analysis.analysis.introduce': 'Introduzir', - 'analysis.analysis.total-sales': 'Vendas Totais', - 'analysis.analysis.day-sales': 'Vendas do Dia', - 'analysis.analysis.visits': 'Visitas', - 'analysis.analysis.visits-trend': 'Tendência de Visitas', - 'analysis.analysis.visits-ranking': 'Ranking de Visitas', - 'analysis.analysis.day-visits': 'Visitas do Dia', - 'analysis.analysis.week': 'Taxa Semanal', - 'analysis.analysis.day': 'Taxa Diária', - 'analysis.analysis.payments': 'Pagamentos', - 'analysis.analysis.conversion-rate': 'Taxa de Conversão', - 'analysis.analysis.operational-effect': 'Efeito Operacional', - 'analysis.analysis.sales-trend': 'Tendência de Vendas das Lojas', - 'analysis.analysis.sales-ranking': 'Ranking de Vendas', - 'analysis.$2': 'Todo ano', - 'analysis.analysis.all-month': 'Todo mês', - 'analysis.analysis.all-week': 'Toda semana', - 'analysis.analysis.all-day': 'Todo dia', - 'analysis.analysis.search-users': 'Pesquisa de Usuários', - 'analysis.analysis.per-capita-search': 'Busca Per Capta', - 'analysis.analysis.online-top-search': 'Mais Buscadas Online', - 'analysis.analysis.the-proportion-of-sales': 'The Proportion Of Sales', - 'analysis.channel.all': 'Tudo', - 'analysis.channel.online': 'Online', - 'analysis.channel.stores': 'Lojas', - 'analysis.analysis.sales': 'Vendas', - 'analysis.analysis.traffic': 'Tráfego', - 'analysis.table.rank': 'Rank', - 'analysis.table.search-keyword': 'Palavra chave', - 'analysis.table.users': 'Usuários', - 'analysis.table.weekly-range': 'Faixa Semanal', -}; diff --git a/src/pages/analysis/locales/zh-CN.ts b/src/pages/analysis/locales/zh-CN.ts deleted file mode 100644 index 9308f9d5564fb1e5e2a717e5d507e468a1ae62e1..0000000000000000000000000000000000000000 --- a/src/pages/analysis/locales/zh-CN.ts +++ /dev/null @@ -1,34 +0,0 @@ -export default { - 'analysis.analysis.test': '工专路 {no} 号店', - 'analysis.analysis.introduce': '指标说明', - 'analysis.analysis.total-sales': '总销售额', - 'analysis.analysis.day-sales': '日销售额', - 'analysis.analysis.visits': '访问量', - 'analysis.analysis.visits-trend': '访问量趋势', - 'analysis.analysis.visits-ranking': '门店访问量排名', - 'analysis.analysis.day-visits': '日访问量', - 'analysis.analysis.week': '周同比', - 'analysis.analysis.day': '日同比', - 'analysis.analysis.payments': '支付笔数', - 'analysis.analysis.conversion-rate': '转化率', - 'analysis.analysis.operational-effect': '运营活动效果', - 'analysis.analysis.sales-trend': '销售趋势', - 'analysis.analysis.sales-ranking': '门店销售额排名', - 'analysis.analysis.all-year': '全年', - 'analysis.analysis.all-month': '本月', - 'analysis.analysis.all-week': '本周', - 'analysis.analysis.all-day': '今日', - 'analysis.analysis.search-users': '搜索用户数', - 'analysis.analysis.per-capita-search': '人均搜索次数', - 'analysis.analysis.online-top-search': '线上热门搜索', - 'analysis.analysis.the-proportion-of-sales': '销售额类别占比', - 'analysis.channel.all': '全部渠道', - 'analysis.channel.online': '线上', - 'analysis.channel.stores': '门店', - 'analysis.analysis.sales': '销售额', - 'analysis.analysis.traffic': '客流量', - 'analysis.table.rank': '排名', - 'analysis.table.search-keyword': '搜索关键词', - 'analysis.table.users': '用户数', - 'analysis.table.weekly-range': '周涨幅', -}; diff --git a/src/pages/analysis/locales/zh-TW.ts b/src/pages/analysis/locales/zh-TW.ts deleted file mode 100644 index 82a4d428924199404fa5622aac2b674c89404707..0000000000000000000000000000000000000000 --- a/src/pages/analysis/locales/zh-TW.ts +++ /dev/null @@ -1,34 +0,0 @@ -export default { - 'analysis.analysis.test': '工專路 {no} 號店', - 'analysis.analysis.introduce': '指標說明', - 'analysis.analysis.total-sales': '總銷售額', - 'analysis.analysis.day-sales': '日銷售額', - 'analysis.analysis.visits': '訪問量', - 'analysis.analysis.visits-trend': '訪問量趨勢', - 'analysis.analysis.visits-ranking': '門店訪問量排名', - 'analysis.analysis.day-visits': '日訪問量', - 'analysis.analysis.week': '周同比', - 'analysis.analysis.day': '日同比', - 'analysis.analysis.payments': '支付筆數', - 'analysis.analysis.conversion-rate': '轉化率', - 'analysis.analysis.operational-effect': '運營活動效果', - 'analysis.analysis.sales-trend': '銷售趨勢', - 'analysis.analysis.sales-ranking': '門店銷售額排名', - 'analysis.analysis.all-year': '全年', - 'analysis.analysis.all-month': '本月', - 'analysis.analysis.all-week': '本周', - 'analysis.analysis.all-day': '今日', - 'analysis.analysis.search-users': '搜索用戶數', - 'analysis.analysis.per-capita-search': '人均搜索次數', - 'analysis.analysis.online-top-search': '線上熱門搜索', - 'analysis.analysis.the-proportion-of-sales': '銷售額類別占比', - 'analysis.channel.all': '全部渠道', - 'analysis.channel.online': '線上', - 'analysis.channel.stores': '門店', - 'analysis.analysis.sales': '銷售額', - 'analysis.analysis.traffic': '客流量', - 'analysis.table.rank': '排名', - 'analysis.table.search-keyword': '搜索關鍵詞', - 'analysis.table.users': '用戶數', - 'analysis.table.weekly-range': '周漲幅', -}; diff --git a/src/pages/analysis/model.tsx b/src/pages/analysis/model.tsx deleted file mode 100644 index 5706013c7e35aa8f685befcbed806e83f97e7dcc..0000000000000000000000000000000000000000 --- a/src/pages/analysis/model.tsx +++ /dev/null @@ -1,84 +0,0 @@ -import { fakeChartData } from './service'; -import { IAnalysisData } from './data'; -import { Reducer } from 'redux'; -import { EffectsCommandMap } from 'dva'; -import { AnyAction } from 'redux'; - -export type Effect = ( - action: AnyAction, - effects: EffectsCommandMap & { select: (func: (state: IAnalysisData) => T) => T }, -) => void; - -export interface ModelType { - namespace: string; - state: IAnalysisData; - effects: { - fetch: Effect; - fetchSalesData: Effect; - }; - reducers: { - save: Reducer; - clear: Reducer; - }; -} - -const Model: ModelType = { - namespace: 'analysis', - - state: { - visitData: [], - visitData2: [], - salesData: [], - searchData: [], - offlineData: [], - offlineChartData: [], - salesTypeData: [], - salesTypeDataOnline: [], - salesTypeDataOffline: [], - radarData: [], - }, - - effects: { - *fetch(_, { call, put }) { - const response = yield call(fakeChartData); - yield put({ - type: 'save', - payload: response, - }); - }, - *fetchSalesData(_, { call, put }) { - const response = yield call(fakeChartData); - yield put({ - type: 'save', - payload: { - salesData: response.salesData, - }, - }); - }, - }, - - reducers: { - save(state, { payload }) { - return { - ...state, - ...payload, - }; - }, - clear() { - return { - visitData: [], - visitData2: [], - salesData: [], - searchData: [], - offlineData: [], - offlineChartData: [], - salesTypeData: [], - salesTypeDataOnline: [], - salesTypeDataOffline: [], - radarData: [], - }; - }, - }, -}; - -export default Model; diff --git a/src/pages/analysis/service.tsx b/src/pages/analysis/service.tsx deleted file mode 100644 index 64744b9d05f57b1a81a174157dc7cacfbc0e285f..0000000000000000000000000000000000000000 --- a/src/pages/analysis/service.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import request from 'umi-request'; - -export async function fakeChartData() { - return request('/api/analysis/fake_chart_data'); -} diff --git a/src/pages/analysis/style.less b/src/pages/analysis/style.less deleted file mode 100644 index 2bace9a3bc85f17dde9c57754760d2fb37220c20..0000000000000000000000000000000000000000 --- a/src/pages/analysis/style.less +++ /dev/null @@ -1,185 +0,0 @@ -@import '~antd/lib/style/themes/default.less'; -@import './utils/utils.less'; - -.iconGroup { - i { - margin-left: 16px; - color: @text-color-secondary; - cursor: pointer; - transition: color 0.32s; - &:hover { - color: @text-color; - } - } -} - -.rankingList { - margin: 25px 0 0; - padding: 0; - list-style: none; - li { - .clearfix(); - - display: flex; - align-items: center; - margin-top: 16px; - span { - color: @text-color; - font-size: 14px; - line-height: 22px; - } - .rankingItemNumber { - display: inline-block; - width: 20px; - height: 20px; - margin-top: 1.5px; - margin-right: 16px; - font-weight: 600; - font-size: 12px; - line-height: 20px; - text-align: center; - background-color: @background-color-base; - border-radius: 20px; - &.active { - color: #fff; - background-color: #314659; - } - } - .rankingItemTitle { - flex: 1; - margin-right: 8px; - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; - } - } -} - -.salesExtra { - display: inline-block; - margin-right: 24px; - a { - margin-left: 24px; - color: @text-color; - &:hover { - color: @primary-color; - } - &.currentDate { - color: @primary-color; - } - } -} - -.salesCard { - .salesBar { - padding: 0 0 32px 32px; - } - .salesRank { - padding: 0 32px 32px 72px; - } - :global { - .ant-tabs-bar { - padding-left: 16px; - .ant-tabs-nav .ant-tabs-tab { - padding-top: 16px; - padding-bottom: 14px; - line-height: 24px; - } - } - .ant-tabs-extra-content { - padding-right: 24px; - line-height: 55px; - } - .ant-card-head { - position: relative; - } - .ant-card-head-title { - align-items: normal; - } - } -} - -.salesCardExtra { - height: inherit; -} - -.salesTypeRadio { - position: absolute; - right: 54px; - bottom: 12px; -} - -.offlineCard { - :global { - .ant-tabs-ink-bar { - bottom: auto; - } - .ant-tabs-bar { - border-bottom: none; - } - .ant-tabs-nav-container-scrolling { - padding-right: 40px; - padding-left: 40px; - } - .ant-tabs-tab-prev-icon::before { - position: relative; - left: 6px; - } - .ant-tabs-tab-next-icon::before { - position: relative; - right: 6px; - } - .ant-tabs-tab-active h4 { - color: @primary-color; - } - } -} - -.twoColLayout { - .salesCard { - height: calc(100% - 24px); - } -} - -.trendText { - margin-left: 8px; - color: @heading-color; -} - -@media screen and (max-width: @screen-lg) { - .salesExtra { - display: none; - } - - .rankingList { - li { - span:first-child { - margin-right: 8px; - } - } - } -} - -@media screen and (max-width: @screen-md) { - .rankingTitle { - margin-top: 16px; - } - - .salesCard .salesBar { - padding: 16px; - } -} - -@media screen and (max-width: @screen-sm) { - .salesExtraWrap { - display: none; - } - - .salesCard { - :global { - .ant-tabs-content { - padding-top: 30px; - } - } - } -} diff --git a/src/pages/analysis/utils/Yuan.tsx b/src/pages/analysis/utils/Yuan.tsx deleted file mode 100644 index eafefd41526f7313d6baea44faebafe2cb27f16b..0000000000000000000000000000000000000000 --- a/src/pages/analysis/utils/Yuan.tsx +++ /dev/null @@ -1,33 +0,0 @@ -import React from 'react'; -import { yuan } from '../components/Charts'; -/** - * 减少使用 dangerouslySetInnerHTML - */ -export default class Yuan extends React.Component<{ - children: React.ReactText; -}> { - main: HTMLSpanElement | undefined | null; - componentDidMount() { - this.renderToHtml(); - } - - componentDidUpdate() { - this.renderToHtml(); - } - renderToHtml = () => { - const { children } = this.props; - if (this.main) { - this.main.innerHTML = yuan(children); - } - }; - - render() { - return ( - { - this.main = ref; - }} - /> - ); - } -} diff --git a/src/pages/analysis/utils/utils.less b/src/pages/analysis/utils/utils.less deleted file mode 100644 index de1aa64222b6f14328d3a9e3c262ac5a31cce5af..0000000000000000000000000000000000000000 --- a/src/pages/analysis/utils/utils.less +++ /dev/null @@ -1,50 +0,0 @@ -.textOverflow() { - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; - word-break: break-all; -} - -.textOverflowMulti(@line: 3, @bg: #fff) { - position: relative; - max-height: @line * 1.5em; - margin-right: -1em; - padding-right: 1em; - overflow: hidden; - line-height: 1.5em; - text-align: justify; - &::before { - position: absolute; - right: 14px; - bottom: 0; - padding: 0 1px; - background: @bg; - content: '...'; - } - &::after { - position: absolute; - right: 14px; - width: 1em; - height: 1em; - margin-top: 0.2em; - background: white; - content: ''; - } -} - -// mixins for clearfix -// ------------------------ -.clearfix() { - zoom: 1; - &::before, - &::after { - display: table; - content: ' '; - } - &::after { - clear: both; - height: 0; - font-size: 0; - visibility: hidden; - } -} diff --git a/src/pages/analysis/utils/utils.ts b/src/pages/analysis/utils/utils.ts deleted file mode 100644 index 7cdc266a523fe1bce8592fa49a719dda57ca54a5..0000000000000000000000000000000000000000 --- a/src/pages/analysis/utils/utils.ts +++ /dev/null @@ -1,53 +0,0 @@ -import moment from 'moment'; -import { RangePickerValue } from 'antd/lib/date-picker/interface'; - -export function fixedZero(val: number) { - return val * 1 < 10 ? `0${val}` : val; -} - -export function getTimeDistance(type: 'today' | 'week' | 'month' | 'year'): RangePickerValue { - const now = new Date(); - const oneDay = 1000 * 60 * 60 * 24; - - if (type === 'today') { - now.setHours(0); - now.setMinutes(0); - now.setSeconds(0); - return [moment(now), moment(now.getTime() + (oneDay - 1000))]; - } - - if (type === 'week') { - let day = now.getDay(); - now.setHours(0); - now.setMinutes(0); - now.setSeconds(0); - - if (day === 0) { - day = 6; - } else { - day -= 1; - } - - const beginTime = now.getTime() - day * oneDay; - - return [moment(beginTime), moment(beginTime + (7 * oneDay - 1000))]; - } - - if (type === 'month') { - const year = now.getFullYear(); - const month = now.getMonth(); - const nextDate = moment(now).add(1, 'months'); - const nextYear = nextDate.year(); - const nextMonth = nextDate.month(); - - return [ - moment(`${year}-${fixedZero(month + 1)}-01 00:00:00`), - moment(moment(`${nextYear}-${fixedZero(nextMonth + 1)}-01 00:00:00`).valueOf() - 1000), - ]; - } - - return [ - moment(`${now.getFullYear()}-01-01 00:00:00`), - moment(`${now.getFullYear()}-12-31 23:59:59`), - ]; -}