Unverified Commit 6ef0c23f authored by 陈帅's avatar 陈帅 Committed by GitHub

fix all eslint-error (#28)

* run eslint fix

* import sorted

* fix some warning

* fix all eslint-error

* fix all eslint-error

* fix all eslint error

* remove .eslintcache
parent 8ae5c0b9
/functions/mock/** /functions/mock/**
/scripts /scripts
/config /config
\ No newline at end of file **/node_modules/**
_scripts
\ No newline at end of file
const fabric = require('@umijs/fabric');
module.exports = { module.exports = {
parser: 'babel-eslint', ...fabric.default,
extends: ['airbnb', 'prettier', 'plugin:compat/recommended'], rules: {
env: { ...fabric.default.rules,
browser: true, '@typescript-eslint/camelcase': 0,
node: true, '@typescript-eslint/class-name-casing': 0,
es6: true,
mocha: true,
jest: true,
jasmine: true,
}, },
globals: { globals: {
APP_TYPE: true, ANT_DESIGN_PRO_ONLY_DO_NOT_USE_IN_YOUR_PRODUCTION: true,
page: true, page: true,
}, },
rules: {
'react/jsx-filename-extension': [1, { extensions: ['.js'] }],
'react/jsx-wrap-multilines': 0,
'react/prop-types': 0,
'react/forbid-prop-types': 0,
'react/jsx-one-expression-per-line': 0,
'import/no-unresolved': [2, { ignore: ['^@/', '^umi/'] }],
'import/no-extraneous-dependencies': [
2,
{
optionalDependencies: true,
devDependencies: ['**/tests/**.js', '/mock/**.js', '**/**.test.js'],
},
],
'jsx-a11y/no-noninteractive-element-interactions': 0,
'jsx-a11y/click-events-have-key-events': 0,
'jsx-a11y/no-static-element-interactions': 0,
'jsx-a11y/anchor-is-valid': 0,
'linebreak-style': 0,
},
settings: {
polyfills: ['fetch', 'promises', 'url'],
},
}; };
...@@ -35,4 +35,6 @@ functions/mock ...@@ -35,4 +35,6 @@ functions/mock
# screenshot # screenshot
screenshot screenshot
.firebase .firebase
\ No newline at end of file
.eslintcache
{
"singleQuote": true,
"trailingComma": "all",
"printWidth": 100,
"proseWrap": "never",
"overrides": [
{
"files": ".prettierrc",
"options": {
"parser": "json"
}
}
]
}
\ No newline at end of file
const fabric = require('@umijs/fabric');
module.exports = {
...fabric.prettier,
};
const fabric = require('@umijs/fabric');
module.exports = {
...fabric.stylelint,
};
{
"extends": [
"stylelint-config-standard",
"stylelint-config-css-modules",
"stylelint-config-rational-order",
"stylelint-config-prettier"
],
"plugins": ["stylelint-order", "stylelint-declaration-block-no-ignored-properties"],
"rules": {
"no-descending-specificity": null,
"plugin/declaration-block-no-ignored-properties": true
}
}
...@@ -11,16 +11,21 @@ ...@@ -11,16 +11,21 @@
"url": "https://github.com/umijs/umi-blocks/ant-design-pro/accountcenter" "url": "https://github.com/umijs/umi-blocks/ant-design-pro/accountcenter"
}, },
"dependencies": { "dependencies": {
"@ant-design/pro-layout": "^4.5.5",
"antd": "^3.16.3", "antd": "^3.16.3",
"classnames": "^2.2.6",
"dva": "^2.4.0", "dva": "^2.4.0",
"moment": "^2.24.0",
"numeral": "^2.0.6", "numeral": "^2.0.6",
"react": "^16.6.3", "react": "^16.6.3",
"react-router": "^5.0.1",
"redux": "^4.0.1",
"umi-request": "^1.0.0" "umi-request": "^1.0.0"
}, },
"devDependencies": { "devDependencies": {
"umi": "^2.6.9", "umi": "^2.6.9",
"umi-plugin-react": "^1.7.2", "umi-plugin-block-dev": "^1.0.0",
"umi-plugin-block-dev": "^1.0.0" "umi-plugin-react": "^1.7.2"
}, },
"license": "ISC", "license": "ISC",
"blockConfig": { "blockConfig": {
......
import { ListItemDataType } from './data'; import { ListItemDataType } from './data.d';
const titles = [ const titles = [
'Alipay', 'Alipay',
...@@ -21,69 +21,6 @@ const avatars = [ ...@@ -21,69 +21,6 @@ const avatars = [
'https://gw.alipayobjects.com/zos/rmsportal/nxkuOJlFJuAUhzlMTCEe.png', // Webpack 'https://gw.alipayobjects.com/zos/rmsportal/nxkuOJlFJuAUhzlMTCEe.png', // Webpack
]; ];
const getNotice = [
{
id: 'xxx1',
title: titles[0],
logo: avatars[0],
description: '那是一种内在的东西,他们到达不了,也无法触及的',
updatedAt: new Date(),
member: '科学搬砖组',
href: '',
memberLink: '',
},
{
id: 'xxx2',
title: titles[1],
logo: avatars[1],
description: '希望是一个好东西,也许是最好的,好东西是不会消亡的',
updatedAt: new Date('2017-07-24'),
member: '全组都是吴彦祖',
href: '',
memberLink: '',
},
{
id: 'xxx3',
title: titles[2],
logo: avatars[2],
description: '城镇中有那么多的酒馆,她却偏偏走进了我的酒馆',
updatedAt: new Date(),
member: '中二少女团',
href: '',
memberLink: '',
},
{
id: 'xxx4',
title: titles[3],
logo: avatars[3],
description: '那时候我只会想自己想要什么,从不想自己拥有什么',
updatedAt: new Date('2017-07-23'),
member: '程序员日常',
href: '',
memberLink: '',
},
{
id: 'xxx5',
title: titles[4],
logo: avatars[4],
description: '凛冬将至',
updatedAt: new Date('2017-07-23'),
member: '高逼格设计天团',
href: '',
memberLink: '',
},
{
id: 'xxx6',
title: titles[5],
logo: avatars[5],
description: '生命就像一盒巧克力,结果往往出人意料',
updatedAt: new Date('2017-07-23'),
member: '骗你来学计算机',
href: '',
memberLink: '',
},
];
const covers = [ const covers = [
'https://gw.alipayobjects.com/zos/rmsportal/uMfMFlvUuceEyPpotzlq.png', 'https://gw.alipayobjects.com/zos/rmsportal/uMfMFlvUuceEyPpotzlq.png',
'https://gw.alipayobjects.com/zos/rmsportal/iZBVOIhGJiAnhplqjvZW.png', 'https://gw.alipayobjects.com/zos/rmsportal/iZBVOIhGJiAnhplqjvZW.png',
...@@ -119,7 +56,7 @@ function fakeList(count: number): ListItemDataType[] { ...@@ -119,7 +56,7 @@ function fakeList(count: number): ListItemDataType[] {
owner: user[i % 10], owner: user[i % 10],
title: titles[i % 8], title: titles[i % 8],
avatar: avatars[i % 8], avatar: avatars[i % 8],
cover: parseInt(i / 4 + '', 10) % 2 === 0 ? covers[i % 4] : covers[3 - (i % 4)], cover: parseInt(`${i / 4}`, 10) % 2 === 0 ? covers[i % 4] : covers[3 - (i % 4)],
status: ['active', 'exception', 'normal'][i % 3] as status: ['active', 'exception', 'normal'][i % 3] as
| 'normal' | 'normal'
| 'exception' | 'exception'
......
import { Avatar, Card, Dropdown, Icon, List, Menu, Tooltip } from 'antd';
import React, { Component } from 'react'; import React, { Component } from 'react';
import { List, Card, Icon, Dropdown, Menu, Avatar, Tooltip } from 'antd';
import numeral from 'numeral';
import { connect } from 'dva'; import { connect } from 'dva';
import stylesApplications from './index.less'; import numeral from 'numeral';
import { ModalState } from '../../model'; import { ModalState } from '../../model';
import stylesApplications from './index.less';
export function formatWan(val: number) { export function formatWan(val: number) {
const v = val * 1; const v = val * 1;
......
import { Avatar } from 'antd';
import React from 'react'; import React from 'react';
import moment from 'moment'; import moment from 'moment';
import { Avatar } from 'antd';
import styles from './index.less'; import styles from './index.less';
export interface ApplicationsProps { export interface ApplicationsProps {
......
import { Icon, List, Tag } from 'antd';
import React, { Component } from 'react'; import React, { Component } from 'react';
import { List, Icon, Tag } from 'antd';
import { connect } from 'dva'; import { connect } from 'dva';
import ArticleListContent from '../ArticleListContent'; import ArticleListContent from '../ArticleListContent';
import styles from './index.less'; import { ListItemDataType } from '../../data.d';
import { ModalState } from '../../model'; import { ModalState } from '../../model';
import { ListItemDataType } from '../../data'; import styles from './index.less';
@connect(({ BLOCK_NAME_CAMEL_CASE }: { BLOCK_NAME_CAMEL_CASE: ModalState }) => ({ @connect(({ BLOCK_NAME_CAMEL_CASE }: { BLOCK_NAME_CAMEL_CASE: ModalState }) => ({
list: BLOCK_NAME_CAMEL_CASE.list, list: BLOCK_NAME_CAMEL_CASE.list,
......
import { Avatar, Tooltip } from 'antd';
import React from 'react'; import React from 'react';
import { Tooltip, Avatar } from 'antd';
import classNames from 'classnames'; import classNames from 'classnames';
import styles from './index.less'; import styles from './index.less';
...@@ -19,10 +20,10 @@ export interface AvatarListProps { ...@@ -19,10 +20,10 @@ export interface AvatarListProps {
maxLength?: number; maxLength?: number;
excessItemsStyle?: React.CSSProperties; excessItemsStyle?: React.CSSProperties;
style?: React.CSSProperties; style?: React.CSSProperties;
children: React.ReactElement<AvatarItemProps> | Array<React.ReactElement<AvatarItemProps>>; children: React.ReactElement<AvatarItemProps> | React.ReactElement<AvatarItemProps>[];
} }
const avatarSizeToClassName = (size?: SizeType) => const avatarSizeToClassName = (size?: SizeType | 'mini') =>
classNames(styles.avatarItem, { classNames(styles.avatarItem, {
[styles.avatarItemLarge]: size === 'large', [styles.avatarItemLarge]: size === 'large',
[styles.avatarItemSmall]: size === 'small', [styles.avatarItemSmall]: size === 'small',
...@@ -54,9 +55,7 @@ const AvatarList: React.SFC<AvatarListProps> & { Item: typeof Item } = ({ ...@@ -54,9 +55,7 @@ const AvatarList: React.SFC<AvatarListProps> & { Item: typeof Item } = ({
}) => { }) => {
const numOfChildren = React.Children.count(children); const numOfChildren = React.Children.count(children);
const numToShow = maxLength >= numOfChildren ? numOfChildren : maxLength; const numToShow = maxLength >= numOfChildren ? numOfChildren : maxLength;
const childrenArray = React.Children.toArray(children) as Array< const childrenArray = React.Children.toArray(children) as React.ReactElement<AvatarItemProps>[];
React.ReactElement<AvatarItemProps>
>;
const childrenWithProps = childrenArray.slice(0, numToShow).map(child => const childrenWithProps = childrenArray.slice(0, numToShow).map(child =>
React.cloneElement(child, { React.cloneElement(child, {
size, size,
......
import { Card, List } from 'antd';
import React, { Component } from 'react'; import React, { Component } from 'react';
import { List, Card } from 'antd';
import moment from 'moment';
import { connect } from 'dva'; import { connect } from 'dva';
import moment from 'moment';
import AvatarList from '../AvatarList'; import AvatarList from '../AvatarList';
import styles from './index.less'; import { ListItemDataType } from '../../data.d';
import { ModalState } from '../../model'; import { ModalState } from '../../model';
import { ListItemDataType } from '../../data'; import styles from './index.less';
@connect(({ BLOCK_NAME_CAMEL_CASE }: { BLOCK_NAME_CAMEL_CASE: ModalState }) => ({ @connect(({ BLOCK_NAME_CAMEL_CASE }: { BLOCK_NAME_CAMEL_CASE: ModalState }) => ({
list: BLOCK_NAME_CAMEL_CASE.list, list: BLOCK_NAME_CAMEL_CASE.list,
......
export interface ITag { export interface TagType {
key: string; key: string;
label: string; label: string;
} }
export interface IProvince { export interface ProvinceType {
label: string; label: string;
key: string; key: string;
} }
export interface ICity { export interface CityType {
label: string; label: string;
key: string; key: string;
} }
export interface IGeographic { export interface GeographicType {
province: IProvince; province: ProvinceType;
city: ICity; city: CityType;
} }
export interface INotice { export interface NoticeType {
id: string; id: string;
title: string; title: string;
logo: string; logo: string;
...@@ -33,16 +33,16 @@ export interface CurrentUser { ...@@ -33,16 +33,16 @@ export interface CurrentUser {
name: string; name: string;
avatar: string; avatar: string;
userid: string; userid: string;
notice: INotice[]; notice: NoticeType[];
email: string; email: string;
signature: string; signature: string;
title: string; title: string;
group: string; group: string;
tags: ITag[]; tags: TagType[];
notifyCount: number; notifyCount: number;
unreadCount: number; unreadCount: number;
country: string; country: string;
geographic: IGeographic; geographic: GeographicType;
address: string; address: string;
phone: string; phone: string;
} }
......
import { Avatar, Card, Col, Divider, Icon, Input, Row, Tag } from 'antd';
import React, { PureComponent } from 'react'; import React, { PureComponent } from 'react';
import { connect } from 'dva';
import { Dispatch } from 'redux'; import { Dispatch } from 'redux';
import Link from 'umi/link';
import { GridContent } from '@ant-design/pro-layout'; import { GridContent } from '@ant-design/pro-layout';
import Link from 'umi/link';
import { RouteChildrenProps } from 'react-router'; import { RouteChildrenProps } from 'react-router';
import { Card, Row, Col, Icon, Avatar, Tag, Divider, Input } from 'antd'; import { connect } from 'dva';
import styles from './Center.less';
import { ITag, CurrentUser } from './data';
import { ModalState } from './model'; import { ModalState } from './model';
import Projects from './components/Projects';
import Articles from './components/Articles'; import Articles from './components/Articles';
import Applications from './components/Applications'; import Applications from './components/Applications';
import Projects from './components/Projects'; import { CurrentUser, TagType } from './data.d';
import styles from './Center.less';
const operationTabList = [ const operationTabList = [
{ {
...@@ -45,7 +46,7 @@ interface BLOCK_NAME_CAMEL_CASEProps extends RouteChildrenProps { ...@@ -45,7 +46,7 @@ interface BLOCK_NAME_CAMEL_CASEProps extends RouteChildrenProps {
currentUserLoading: boolean; currentUserLoading: boolean;
} }
interface BLOCK_NAME_CAMEL_CASEState { interface BLOCK_NAME_CAMEL_CASEState {
newTags: ITag[]; newTags: TagType[];
tabKey: 'articles' | 'applications' | 'projects'; tabKey: 'articles' | 'applications' | 'projects';
inputVisible: boolean; inputVisible: boolean;
inputValue: string; inputValue: string;
...@@ -56,7 +57,7 @@ interface BLOCK_NAME_CAMEL_CASEState { ...@@ -56,7 +57,7 @@ interface BLOCK_NAME_CAMEL_CASEState {
loading, loading,
BLOCK_NAME_CAMEL_CASE, BLOCK_NAME_CAMEL_CASE,
}: { }: {
loading: { effects: any }; loading: { effects: { [key: string]: boolean } };
BLOCK_NAME_CAMEL_CASE: ModalState; BLOCK_NAME_CAMEL_CASE: ModalState;
}) => ({ }) => ({
currentUser: BLOCK_NAME_CAMEL_CASE.currentUser, currentUser: BLOCK_NAME_CAMEL_CASE.currentUser,
...@@ -92,7 +93,7 @@ class PAGE_NAME_UPPER_CAMEL_CASE extends PureComponent< ...@@ -92,7 +93,7 @@ class PAGE_NAME_UPPER_CAMEL_CASE extends PureComponent<
tabKey: 'articles', tabKey: 'articles',
}; };
input: Input | null | undefined; public input: Input | null | undefined = undefined;
componentDidMount() { componentDidMount() {
const { dispatch } = this.props; const { dispatch } = this.props;
...@@ -138,6 +139,7 @@ class PAGE_NAME_UPPER_CAMEL_CASE extends PureComponent< ...@@ -138,6 +139,7 @@ class PAGE_NAME_UPPER_CAMEL_CASE extends PureComponent<
inputValue: '', inputValue: '',
}); });
}; };
renderChildrenByTabKey = (tabKey: BLOCK_NAME_CAMEL_CASEState['tabKey']) => { renderChildrenByTabKey = (tabKey: BLOCK_NAME_CAMEL_CASEState['tabKey']) => {
if (tabKey === 'projects') { if (tabKey === 'projects') {
return <Projects />; return <Projects />;
...@@ -150,6 +152,7 @@ class PAGE_NAME_UPPER_CAMEL_CASE extends PureComponent< ...@@ -150,6 +152,7 @@ class PAGE_NAME_UPPER_CAMEL_CASE extends PureComponent<
} }
return null; return null;
}; };
render() { render() {
const { newTags, inputVisible, inputValue, tabKey } = this.state; const { newTags, inputVisible, inputValue, tabKey } = this.state;
const { currentUser, currentUserLoading } = this.props; const { currentUser, currentUserLoading } = this.props;
...@@ -184,9 +187,9 @@ class PAGE_NAME_UPPER_CAMEL_CASE extends PureComponent< ...@@ -184,9 +187,9 @@ class PAGE_NAME_UPPER_CAMEL_CASE extends PureComponent<
<Divider dashed /> <Divider dashed />
<div className={styles.tags}> <div className={styles.tags}>
<div className={styles.tagsTitle}>标签</div> <div className={styles.tagsTitle}>标签</div>
{currentUser.tags.concat(newTags).map(item => { {currentUser.tags.concat(newTags).map(item => (
return <Tag key={item.key}>{item.label}</Tag>; <Tag key={item.key}>{item.label}</Tag>
})} ))}
{inputVisible && ( {inputVisible && (
<Input <Input
ref={ref => this.saveInputRef(ref)} ref={ref => this.saveInputRef(ref)}
......
import { AnyAction, Reducer } from 'redux';
import { EffectsCommandMap } from 'dva';
import { CurrentUser, ListItemDataType } from './data.d';
import { queryCurrent, queryFakeList } from './service'; import { queryCurrent, queryFakeList } from './service';
import { CurrentUser, ListItemDataType } from './data';
export interface ModalState { export interface ModalState {
currentUser: Partial<CurrentUser>; currentUser: Partial<CurrentUser>;
list: ListItemDataType[]; list: ListItemDataType[];
} }
import { Reducer } from 'redux';
import { EffectsCommandMap } from 'dva';
import { AnyAction } from 'redux';
export type Effect = ( export type Effect = (
action: AnyAction, action: AnyAction,
effects: EffectsCommandMap & { select: <T>(func: (state: ModalState) => T) => T }, effects: EffectsCommandMap & { select: <T>(func: (state: ModalState) => T) => T },
...@@ -56,13 +54,13 @@ const Model: ModelType = { ...@@ -56,13 +54,13 @@ const Model: ModelType = {
reducers: { reducers: {
saveCurrentUser(state, action) { saveCurrentUser(state, action) {
return { return {
...state!, ...(state as ModalState),
currentUser: action.payload || {}, currentUser: action.payload || {},
}; };
}, },
queryList(state, action) { queryList(state, action) {
return { return {
...state!, ...(state as ModalState),
list: action.payload, list: action.payload,
}; };
}, },
......
...@@ -5,7 +5,7 @@ export async function queryCurrent() { ...@@ -5,7 +5,7 @@ export async function queryCurrent() {
} }
export async function queryFakeList(params: { count: number }) { export async function queryFakeList(params: { count: number }) {
return request(`/api/fake_list`, { return request('/api/fake_list', {
params, params,
}); });
} }
...@@ -12,15 +12,18 @@ ...@@ -12,15 +12,18 @@
"dev": "umi dev" "dev": "umi dev"
}, },
"dependencies": { "dependencies": {
"@ant-design/pro-layout": "^4.5.5",
"antd": "^3.16.3", "antd": "^3.16.3",
"dva": "^2.4.0", "dva": "^2.4.0",
"react": "^16.6.3", "react": "^16.6.3",
"umi-request": "^1.0.0" "redux": "^4.0.1",
"umi-request": "^1.0.0",
"umi-plugin-react": "^1.8.4",
"umi": "^2.6.9"
}, },
"devDependencies": { "devDependencies": {
"umi": "^2.6.9", "umi-plugin-block-dev": "^1.0.0"
"umi-plugin-block-dev": "^1.0.0",
"umi-plugin-react": "^1.3.0-beta.1"
}, },
"blockConfig": { "blockConfig": {
"specVersion": "0.1" "specVersion": "0.1"
......
import React, { Component } from 'react'; import React, { Component } from 'react';
import { Select, Spin } from 'antd'; import { Select, Spin } from 'antd';
import { Dispatch } from 'redux';
import { connect } from 'dva'; import { connect } from 'dva';
import { CityType, ProvinceType } from '../data.d';
import styles from './GeographicView.less'; import styles from './GeographicView.less';
import { Dispatch } from 'redux';
import { ProvinceData, CityData } from '../data';
const { Option } = Select; const { Option } = Select;
interface SelectItem { interface SelectItem {
label: string; label: string;
key: string; key: string;
} }
const nullSlectItem: SelectItem = { const nullSelectItem: SelectItem = {
label: '', label: '',
key: '', key: '',
}; };
interface GeographicViewProps { interface GeographicViewProps {
dispatch?: Dispatch<any>; dispatch?: Dispatch<any>;
province?: ProvinceData[]; province?: ProvinceType[];
city?: CityData[]; city?: CityType[];
value?: { value?: {
province: SelectItem; province: SelectItem;
city: SelectItem; city: SelectItem;
...@@ -33,8 +35,8 @@ interface GeographicViewProps { ...@@ -33,8 +35,8 @@ interface GeographicViewProps {
loading, loading,
}: { }: {
BLOCK_NAME_CAMEL_CASE: { BLOCK_NAME_CAMEL_CASE: {
province: ProvinceData[]; province: ProvinceType[];
city: CityData[]; city: CityType[];
}; };
loading: any; loading: any;
}) => { }) => {
...@@ -85,7 +87,7 @@ class GeographicView extends Component<GeographicViewProps> { ...@@ -85,7 +87,7 @@ class GeographicView extends Component<GeographicViewProps> {
return []; return [];
}; };
getOption = (list: CityData[] | ProvinceData[]) => { getOption = (list: CityType[] | ProvinceType[]) => {
if (!list || list.length < 1) { if (!list || list.length < 1) {
return ( return (
<Option key={0} value={0}> <Option key={0} value={0}>
...@@ -93,9 +95,9 @@ class GeographicView extends Component<GeographicViewProps> { ...@@ -93,9 +95,9 @@ class GeographicView extends Component<GeographicViewProps> {
</Option> </Option>
); );
} }
return (list as CityData[]).map(item => ( return (list as CityType[]).map(item => (
<Option key={item.id} value={item.id}> <Option key={item.key} value={item.key}>
{item.name} {item.label}
</Option> </Option>
)); ));
}; };
...@@ -112,7 +114,7 @@ class GeographicView extends Component<GeographicViewProps> { ...@@ -112,7 +114,7 @@ class GeographicView extends Component<GeographicViewProps> {
if (onChange) { if (onChange) {
onChange({ onChange({
province: item, province: item,
city: nullSlectItem, city: nullSelectItem,
}); });
} }
}; };
...@@ -131,14 +133,14 @@ class GeographicView extends Component<GeographicViewProps> { ...@@ -131,14 +133,14 @@ class GeographicView extends Component<GeographicViewProps> {
const { value } = this.props; const { value } = this.props;
if (!value) { if (!value) {
return { return {
province: nullSlectItem, province: nullSelectItem,
city: nullSlectItem, city: nullSelectItem,
}; };
} }
const { province, city } = value; const { province, city } = value;
return { return {
province: province || nullSlectItem, province: province || nullSelectItem,
city: city || nullSlectItem, city: city || nullSelectItem,
}; };
} }
......
import React, { Fragment, PureComponent } from 'react'; import React, { Fragment, PureComponent } from 'react';
import { Input } from 'antd'; import { Input } from 'antd';
import styles from './PhoneView.less'; import styles from './PhoneView.less';
...@@ -20,15 +21,17 @@ class PhoneView extends PureComponent<PhoneViewProps> { ...@@ -20,15 +21,17 @@ class PhoneView extends PureComponent<PhoneViewProps> {
className={styles.area_code} className={styles.area_code}
value={values[0]} value={values[0]}
onChange={e => { onChange={e => {
// tslint:disable-next-line: no-unused-expression if (onChange) {
onChange && onChange(`${e.target.value}-${values[1]}`); onChange(`${e.target.value}-${values[1]}`);
}
}} }}
/> />
<Input <Input
className={styles.phone_number} className={styles.phone_number}
onChange={e => { onChange={e => {
// tslint:disable-next-line: no-unused-expression if (onChange) {
onChange && onChange(`${values[0]}-${e.target.value}`); onChange(`${values[0]}-${e.target.value}`);
}
}} }}
value={values[1]} value={values[1]}
/> />
......
import { Button, Form, Input, Select, Upload, message } from 'antd';
import { FormattedMessage, formatMessage } from 'umi-plugin-react/locale';
import React, { Component, Fragment } from 'react'; import React, { Component, Fragment } from 'react';
import { formatMessage, FormattedMessage } from 'umi-plugin-react/locale';
import { Form, Input, Upload, Select, Button, message } from 'antd';
import { FormComponentProps } from 'antd/es/form'; import { FormComponentProps } from 'antd/es/form';
import { connect } from 'dva'; import { connect } from 'dva';
import styles from './BaseView.less'; import { CurrentUser } from '../data.d';
import GeographicView from './GeographicView'; import GeographicView from './GeographicView';
import PhoneView from './PhoneView'; import PhoneView from './PhoneView';
import { CurrentUser } from '../data'; import styles from './BaseView.less';
const FormItem = Form.Item; const FormItem = Form.Item;
const { Option } = Select; const { Option } = Select;
...@@ -70,7 +72,8 @@ interface BaseViewProps extends FormComponentProps { ...@@ -70,7 +72,8 @@ interface BaseViewProps extends FormComponentProps {
currentUser: BLOCK_NAME_CAMEL_CASE.currentUser, currentUser: BLOCK_NAME_CAMEL_CASE.currentUser,
})) }))
class BaseView extends Component<BaseViewProps> { class BaseView extends Component<BaseViewProps> {
view: HTMLDivElement | undefined; view: HTMLDivElement | undefined = undefined;
componentDidMount() { componentDidMount() {
this.setBaseInfo(); this.setBaseInfo();
} }
...@@ -102,10 +105,10 @@ class BaseView extends Component<BaseViewProps> { ...@@ -102,10 +105,10 @@ class BaseView extends Component<BaseViewProps> {
this.view = ref; this.view = ref;
}; };
handlerSubmit = (event: Event) => { handlerSubmit = (event: React.MouseEvent) => {
event.preventDefault(); event.preventDefault();
const { form } = this.props; const { form } = this.props;
form.validateFields((err, values) => { form.validateFields(err => {
if (!err) { if (!err) {
message.success(formatMessage({ id: 'BLOCK_NAME.basic.update.success' })); message.success(formatMessage({ id: 'BLOCK_NAME.basic.update.success' }));
} }
......
import React, { Component, Fragment } from 'react'; import { FormattedMessage, formatMessage } from 'umi-plugin-react/locale';
import { formatMessage, FormattedMessage } from 'umi-plugin-react/locale';
import { Icon, List } from 'antd'; import { Icon, List } from 'antd';
import React, { Component, Fragment } from 'react';
class BindingView extends Component { class BindingView extends Component {
getData = () => [ getData = () => [
......
import { List, Switch } from 'antd';
import React, { Component, Fragment } from 'react'; import React, { Component, Fragment } from 'react';
import { formatMessage } from 'umi-plugin-react/locale'; import { formatMessage } from 'umi-plugin-react/locale';
import { Switch, List } from 'antd';
type Unpacked<T> = T extends (infer U)[] ? U : T; type Unpacked<T> = T extends (infer U)[] ? U : T;
......
import { FormattedMessage, formatMessage } from 'umi-plugin-react/locale';
import React, { Component, Fragment } from 'react'; import React, { Component, Fragment } from 'react';
import { formatMessage, FormattedMessage } from 'umi-plugin-react/locale';
import { List } from 'antd'; import { List } from 'antd';
type Unpacked<T> = T extends (infer U)[] ? U : T; type Unpacked<T> = T extends (infer U)[] ? U : T;
......
export interface ITag { export interface TagType {
key: string; key: string;
label: string; label: string;
} }
export interface IProvince { export interface ProvinceType {
label: string; label: string;
key: string; key: string;
} }
export interface ICity { export interface CityType {
label: string; label: string;
key: string; key: string;
} }
export interface IGeographic { export interface GeographicType {
province: IProvince; province: ProvinceType;
city: ICity; city: CityType;
} }
export interface INotice { export interface NoticeType {
id: string; id: string;
title: string; title: string;
logo: string; logo: string;
...@@ -33,16 +33,16 @@ export interface CurrentUser { ...@@ -33,16 +33,16 @@ export interface CurrentUser {
name: string; name: string;
avatar: string; avatar: string;
userid: string; userid: string;
notice: INotice[]; notice: NoticeType[];
email: string; email: string;
signature: string; signature: string;
title: string; title: string;
group: string; group: string;
tags: ITag[]; tags: TagType[];
notifyCount: number; notifyCount: number;
unreadCount: number; unreadCount: number;
country: string; country: string;
geographic: IGeographic; geographic: GeographicType;
address: string; address: string;
phone: string; phone: string;
} }
import React, { Component } from 'react'; import React, { Component } from 'react';
import { connect } from 'dva';
import { Dispatch } from 'redux'; import { Dispatch } from 'redux';
import { FormattedMessage } from 'umi-plugin-react/locale'; import { FormattedMessage } from 'umi-plugin-react/locale';
import { GridContent } from '@ant-design/pro-layout'; import { GridContent } from '@ant-design/pro-layout';
import { Menu } from 'antd'; import { Menu } from 'antd';
import styles from './style.less'; import { connect } from 'dva';
import BaseView from './components/base'; import BaseView from './components/base';
import SecurityView from './components/security';
import BindingView from './components/binding'; import BindingView from './components/binding';
import { CurrentUser } from './data.d';
import NotificationView from './components/notification'; import NotificationView from './components/notification';
import { CurrentUser } from './data'; import SecurityView from './components/security';
import styles from './style.less';
const { Item } = Menu; const { Item } = Menu;
...@@ -33,7 +34,8 @@ class PAGE_NAME_UPPER_CAMEL_CASE extends Component< ...@@ -33,7 +34,8 @@ class PAGE_NAME_UPPER_CAMEL_CASE extends Component<
PAGE_NAME_UPPER_CAMEL_CASEProps, PAGE_NAME_UPPER_CAMEL_CASEProps,
PAGE_NAME_UPPER_CAMEL_CASEState PAGE_NAME_UPPER_CAMEL_CASEState
> { > {
main: HTMLDivElement | undefined; main: HTMLDivElement | undefined = undefined;
constructor(props: PAGE_NAME_UPPER_CAMEL_CASEProps) { constructor(props: PAGE_NAME_UPPER_CAMEL_CASEProps) {
super(props); super(props);
const menuMap = { const menuMap = {
......
import { query as queryUsers, queryCurrent, queryProvince, queryCity } from './service'; import { AnyAction, Reducer } from 'redux';
import { Reducer } from 'redux';
import { EffectsCommandMap } from 'dva'; import { EffectsCommandMap } from 'dva';
import { AnyAction } from 'redux'; import { CityType, CurrentUser, ProvinceType } from './data.d';
import { CurrentUser, City, Province } from './data'; import { queryCity, queryCurrent, queryProvince, query as queryUsers } from './service';
export interface ModalState { export interface ModalState {
currentUser?: Partial<CurrentUser>; currentUser?: Partial<CurrentUser>;
province?: Province[]; province?: ProvinceType[];
city?: City[]; city?: CityType[];
isLoading?: boolean; isLoading?: boolean;
} }
......
...@@ -12,22 +12,27 @@ ...@@ -12,22 +12,27 @@
"dev": "umi dev" "dev": "umi dev"
}, },
"dependencies": { "dependencies": {
"@ant-design/pro-layout": "^4.5.5",
"@antv/data-set": "^0.10.2", "@antv/data-set": "^0.10.2",
"antd": "^3.16.3", "antd": "^3.16.3",
"bizcharts": "^3.5.3-beta.0", "bizcharts": "^3.5.3-beta.0",
"bizcharts-plugin-slider": "^2.1.1-beta.1", "bizcharts-plugin-slider": "^2.1.1-beta.1",
"dva": "^2.4.0", "classnames": "^2.2.6",
"dva": "^2.4.0",
"@types/lodash.debounce": "^4.0.6",
"lodash.debounce": "^4.0.8",
"moment": "^2.22.2", "moment": "^2.22.2",
"numeral": "^2.0.6", "numeral": "^2.0.6",
"react": "^16.6.3", "react": "^16.6.3",
"react-fittext": "^1.0.0", "react-fittext": "^1.0.0",
"redux": "^4.0.1",
"umi-plugin-react": "^1.7.2",
"umi-request": "^1.0.0" "umi-request": "^1.0.0"
}, },
"devDependencies": { "devDependencies": {
"@types/numeral": "^0.0.25",
"umi": "^2.6.9", "umi": "^2.6.9",
"umi-plugin-block-dev": "^1.1.0", "umi-plugin-block-dev": "^1.1.0"
"umi-plugin-react": "^1.7.2",
"@types/numeral": "^0.0.25"
}, },
"blockConfig": { "blockConfig": {
"specVersion": "0.1" "specVersion": "0.1"
......
import moment from 'moment'; import moment from 'moment';
import { IVisitData, IRadarData, IAnalysisData } from './data'; import { AnalysisData, RadarData, VisitDataType } from './data.d';
// mock data // mock data
const visitData: IVisitData[] = []; const visitData: VisitDataType[] = [];
const beginDay = new Date().getTime(); const beginDay = new Date().getTime();
const fakeY = [7, 5, 4, 2, 4, 7, 5, 6, 5, 9, 6, 3, 1, 5, 3, 6, 5]; const fakeY = [7, 5, 4, 2, 4, 7, 5, 6, 5, 9, 6, 3, 1, 5, 3, 6, 5];
...@@ -159,7 +159,7 @@ const radarOriginData = [ ...@@ -159,7 +159,7 @@ const radarOriginData = [
}, },
]; ];
const radarData: IRadarData[] = []; const radarData: RadarData[] = [];
const radarTitleMap = { const radarTitleMap = {
ref: '引用', ref: '引用',
koubei: '口碑', koubei: '口碑',
...@@ -179,7 +179,7 @@ radarOriginData.forEach(item => { ...@@ -179,7 +179,7 @@ radarOriginData.forEach(item => {
}); });
}); });
const getFakeChartData: IAnalysisData = { const getFakeChartData: AnalysisData = {
visitData, visitData,
visitData2, visitData2,
salesData, salesData,
......
import { Axis, Chart, Geom, Tooltip } from 'bizcharts';
import React, { Component } from 'react'; import React, { Component } from 'react';
import { Chart, Axis, Tooltip, Geom } from 'bizcharts';
import Debounce from 'lodash-decorators/debounce'; import Debounce from 'lodash.debounce';
import Bind from 'lodash-decorators/bind';
import autoHeight from '../autoHeight'; import autoHeight from '../autoHeight';
import styles from '../index.less'; import styles from '../index.less';
export interface IBarProps { export interface BarProps {
title: React.ReactNode; title: React.ReactNode;
color?: string; color?: string;
padding?: [number, number, number, number]; padding?: [number, number, number, number];
height?: number; height?: number;
data: Array<{ data: {
x: string; x: string;
y: number; y: number;
}>; }[];
forceFit?: boolean; forceFit?: boolean;
autoLabel?: boolean; autoLabel?: boolean;
style?: React.CSSProperties; style?: React.CSSProperties;
} }
class Bar extends Component< class Bar extends Component<
IBarProps, BarProps,
{ {
autoHideXLabels: boolean; autoHideXLabels: boolean;
} }
...@@ -28,26 +28,12 @@ class Bar extends Component< ...@@ -28,26 +28,12 @@ class Bar extends Component<
state = { state = {
autoHideXLabels: false, autoHideXLabels: false,
}; };
root: HTMLDivElement | undefined;
node: HTMLDivElement | undefined;
componentDidMount() { root: HTMLDivElement | undefined = undefined;
window.addEventListener('resize', this.resize, { passive: true });
}
componentWillUnmount() { node: HTMLDivElement | undefined = undefined;
window.removeEventListener('resize', this.resize);
}
handleRoot = (n: HTMLDivElement) => {
this.root = n;
};
handleRef = (n: HTMLDivElement) => {
this.node = n;
};
@Bind() resize = Debounce(() => {
@Debounce(400)
resize() {
if (!this.node || !this.node.parentNode) { if (!this.node || !this.node.parentNode) {
return; return;
} }
...@@ -70,8 +56,24 @@ class Bar extends Component< ...@@ -70,8 +56,24 @@ class Bar extends Component<
autoHideXLabels: false, autoHideXLabels: false,
}); });
} }
}, 500);
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;
};
render() { render() {
const { const {
height = 1, height = 1,
...@@ -115,8 +117,8 @@ class Bar extends Component< ...@@ -115,8 +117,8 @@ class Bar extends Component<
<Axis <Axis
name="x" name="x"
title={false} title={false}
label={autoHideXLabels ? false : {}} label={autoHideXLabels ? undefined : {}}
tickLine={autoHideXLabels ? false : {}} tickLine={autoHideXLabels ? undefined : {}}
/> />
<Axis name="y" min={0} /> <Axis name="y" min={0} />
<Tooltip showTitle={false} crosshairs={false} /> <Tooltip showTitle={false} crosshairs={false} />
......
import React from 'react';
import { Card } from 'antd'; import { Card } from 'antd';
import classNames from 'classnames';
import { CardProps } from 'antd/es/card'; import { CardProps } from 'antd/es/card';
import React from 'react';
import classNames from 'classnames';
import styles from './index.less'; import styles from './index.less';
type totalType = () => React.ReactNode; type totalType = () => React.ReactNode;
const renderTotal = (total?: number | totalType | React.ReactNode) => { const renderTotal = (total?: number | totalType | React.ReactNode) => {
if (!total) { if (!total) {
return; return null;
} }
let totalDom; let totalDom;
switch (typeof total) { switch (typeof total) {
...@@ -25,7 +24,7 @@ const renderTotal = (total?: number | totalType | React.ReactNode) => { ...@@ -25,7 +24,7 @@ const renderTotal = (total?: number | totalType | React.ReactNode) => {
return totalDom; return totalDom;
}; };
export interface IChartCardProps extends CardProps { export interface ChartCardProps extends CardProps {
title: React.ReactNode; title: React.ReactNode;
action?: React.ReactNode; action?: React.ReactNode;
total?: React.ReactNode | number | (() => React.ReactNode | number); total?: React.ReactNode | number | (() => React.ReactNode | number);
...@@ -35,7 +34,7 @@ export interface IChartCardProps extends CardProps { ...@@ -35,7 +34,7 @@ export interface IChartCardProps extends CardProps {
style?: React.CSSProperties; style?: React.CSSProperties;
} }
class ChartCard extends React.Component<IChartCardProps> { class ChartCard extends React.Component<ChartCardProps> {
renderContent = () => { renderContent = () => {
const { contentHeight, title, avatar, action, total, footer, children, loading } = this.props; const { contentHeight, title, avatar, action, total, footer, children, loading } = this.props;
if (loading) { if (loading) {
......
import React from 'react'; import React from 'react';
import styles from './index.less'; import styles from './index.less';
export interface IFieldProps { export interface FieldProps {
label: React.ReactNode; label: React.ReactNode;
value: React.ReactNode; value: React.ReactNode;
style?: React.CSSProperties; style?: React.CSSProperties;
} }
const Field: React.SFC<IFieldProps> = ({ label, value, ...rest }) => ( const Field: React.SFC<FieldProps> = ({ label, value, ...rest }) => (
<div className={styles.field} {...rest}> <div className={styles.field} {...rest}>
<span className={styles.label}>{label}</span> <span className={styles.label}>{label}</span>
<span className={styles.number}>{value}</span> <span className={styles.number}>{value}</span>
......
import { Axis, Chart, Coord, Geom, Guide, Shape } from 'bizcharts';
import React from 'react'; import React from 'react';
import { Chart, Geom, Axis, Coord, Guide, Shape } from 'bizcharts';
import autoHeight from '../autoHeight'; import autoHeight from '../autoHeight';
const { Arc, Html, Line } = Guide; const { Arc, Html, Line } = Guide;
export interface IGaugeProps { export interface GaugeProps {
title: React.ReactNode; title: React.ReactNode;
color?: string; color?: string;
height?: number; height?: number;
...@@ -30,148 +31,149 @@ const defaultFormatter = (val: string): string => { ...@@ -30,148 +31,149 @@ const defaultFormatter = (val: string): string => {
} }
}; };
Shape.registerShape!('point', 'pointer', { if (Shape.registerShape) {
drawShape(cfg: any, group: any) { Shape.registerShape('point', 'pointer', {
let point = cfg.points[0]; drawShape(cfg: any, group: any) {
point = (this as any).parsePoint(point); let point = cfg.points[0];
const center = (this as any).parsePoint({ point = (this as any).parsePoint(point);
x: 0, const center = (this as any).parsePoint({
y: 0, x: 0,
}); y: 0,
group.addShape('line', { });
attrs: { group.addShape('line', {
x1: center.x, attrs: {
y1: center.y, x1: center.x,
x2: point.x, y1: center.y,
y2: point.y, x2: point.x,
stroke: cfg.color, y2: point.y,
lineWidth: 2, stroke: cfg.color,
lineCap: 'round', lineWidth: 2,
}, lineCap: 'round',
}); },
return group.addShape('circle', { });
attrs: { return group.addShape('circle', {
x: center.x, attrs: {
y: center.y, x: center.x,
r: 6, y: center.y,
stroke: cfg.color, r: 6,
lineWidth: 3, stroke: cfg.color,
fill: '#fff', lineWidth: 3,
}, fill: '#fff',
}); },
}, });
}); },
});
}
class Gauge extends React.Component<IGaugeProps> { const Gauge: React.FC<GaugeProps> = props => {
render() { const {
const { title,
title, height = 1,
height = 1, percent,
percent, forceFit = true,
forceFit = true, formatter = defaultFormatter,
formatter = defaultFormatter, color = '#2F9CFF',
color = '#2F9CFF', bgColor = '#F0F2F5',
bgColor = '#F0F2F5', } = props;
} = this.props; const cols = {
const cols = { value: {
value: { type: 'linear',
type: 'linear', min: 0,
min: 0, max: 10,
max: 10, tickCount: 6,
tickCount: 6, nice: true,
nice: true, },
}, };
}; const data = [{ value: percent / 10 }];
const renderHtml = () => ` const renderHtml = () => `
<div style="width: 300px;text-align: center;font-size: 12px!important;"> <div style="width: 300px;text-align: center;font-size: 12px!important;">
<p style="font-size: 14px; color: rgba(0,0,0,0.43);margin: 0;">${title}</p> <p style="font-size: 14px; color: rgba(0,0,0,0.43);margin: 0;">${title}</p>
<p style="font-size: 24px;color: rgba(0,0,0,0.85);margin: 0;"> <p style="font-size: 24px;color: rgba(0,0,0,0.85);margin: 0;">
${(data[0].value * 10).toFixed(2)}% ${(data[0].value * 10).toFixed(2)}%
</p> </p>
</div>`; </div>`;
const data = [{ value: percent / 10 }]; const textStyle: {
const textStyle: { fontSize: number;
fontSize: number; fill: string;
fill: string; textAlign: 'center';
textAlign: 'center'; } = {
} = { fontSize: 12,
fontSize: 12, fill: 'rgba(0, 0, 0, 0.65)',
fill: 'rgba(0, 0, 0, 0.65)', textAlign: 'center',
textAlign: 'center', };
};
return ( return (
<Chart height={height} data={data} scale={cols} padding={[-16, 0, 16, 0]} forceFit={forceFit}> <Chart height={height} data={data} scale={cols} padding={[-16, 0, 16, 0]} forceFit={forceFit}>
<Coord type="polar" startAngle={-1.25 * Math.PI} endAngle={0.25 * Math.PI} radius={0.8} /> <Coord type="polar" startAngle={-1.25 * Math.PI} endAngle={0.25 * Math.PI} radius={0.8} />
<Axis name="1" line={undefined} /> <Axis name="1" line={undefined} />
<Axis <Axis
line={undefined} line={undefined}
tickLine={undefined} tickLine={undefined}
subTickLine={undefined} subTickLine={undefined}
name="value" name="value"
zIndex={2} zIndex={2}
label={{ label={{
offset: -12, offset: -12,
formatter, formatter,
textStyle: textStyle, textStyle,
}}
/>
<Guide>
<Line
start={[3, 0.905]}
end={[3, 0.85]}
lineStyle={{
stroke: color,
lineDash: undefined,
lineWidth: 2,
}} }}
/> />
<Guide> <Line
<Line start={[5, 0.905]}
start={[3, 0.905]} end={[5, 0.85]}
end={[3, 0.85]} lineStyle={{
lineStyle={{ stroke: color,
stroke: color, lineDash: undefined,
lineDash: undefined, lineWidth: 3,
lineWidth: 2, }}
}}
/>
<Line
start={[5, 0.905]}
end={[5, 0.85]}
lineStyle={{
stroke: color,
lineDash: undefined,
lineWidth: 3,
}}
/>
<Line
start={[7, 0.905]}
end={[7, 0.85]}
lineStyle={{
stroke: color,
lineDash: undefined,
lineWidth: 3,
}}
/>
<Arc
start={[0, 0.965]}
end={[10, 0.965]}
style={{
stroke: bgColor,
lineWidth: 10,
}}
/>
<Arc
start={[0, 0.965]}
end={[data[0].value, 0.965]}
style={{
stroke: color,
lineWidth: 10,
}}
/>
<Html position={['50%', '95%']} html={renderHtml()} />
</Guide>
<Geom
line={false}
type="point"
position="value*1"
shape="pointer"
color={color}
active={false}
/> />
</Chart> <Line
); start={[7, 0.905]}
} end={[7, 0.85]}
} lineStyle={{
stroke: color,
lineDash: undefined,
lineWidth: 3,
}}
/>
<Arc
start={[0, 0.965]}
end={[10, 0.965]}
style={{
stroke: bgColor,
lineWidth: 10,
}}
/>
<Arc
start={[0, 0.965]}
end={[data[0].value, 0.965]}
style={{
stroke: color,
lineWidth: 10,
}}
/>
<Html position={['50%', '95%']} html={renderHtml()} />
</Guide>
<Geom
line={false}
type="point"
position="value*1"
shape="pointer"
color={color}
active={false}
/>
</Chart>
);
};
export default autoHeight()(Gauge); export default autoHeight()(Gauge);
import { Axis, Chart, Geom, Tooltip, AxisProps } from 'bizcharts';
import React from 'react'; import React from 'react';
import { Chart, Axis, Tooltip, Geom } from 'bizcharts';
import autoHeight from '../autoHeight'; import autoHeight from '../autoHeight';
import styles from '../index.less'; import styles from '../index.less';
export interface IAxis { export interface MiniAreaProps {
title: any;
line: any;
gridAlign: any;
labels: any;
tickLine: any;
grid: any;
}
export interface IMiniAreaProps {
color?: string; color?: string;
height?: number; height?: number;
borderColor?: string; borderColor?: string;
line?: boolean; line?: boolean;
animate?: boolean; animate?: boolean;
xAxis?: IAxis; xAxis?: AxisProps;
forceFit?: boolean; forceFit?: boolean;
scale?: { x: any; y: any }; scale?: {
yAxis?: IAxis; x?: {
tickCount: number;
};
y?: {
tickCount: number;
};
};
yAxis?: Partial<AxisProps>;
borderWidth?: number; borderWidth?: number;
data: Array<{ data: {
x: number | string; x: number | string;
y: number; y: number;
}>; }[];
} }
class MiniArea extends React.Component<IMiniAreaProps> { const MiniArea: React.FC<MiniAreaProps> = props => {
render() { const {
const { height = 1,
height = 1, data = [],
data = [], forceFit = true,
forceFit = true, color = 'rgba(24, 144, 255, 0.2)',
color = 'rgba(24, 144, 255, 0.2)', borderColor = '#1089ff',
borderColor = '#1089ff', scale = { x: {}, y: {} },
scale = { x: {}, y: {} }, borderWidth = 2,
borderWidth = 2, line,
line, xAxis,
xAxis, yAxis,
yAxis, animate = true,
animate = true, } = props;
} = this.props;
const padding: [number, number, number, number] = [36, 5, 30, 5]; const padding: [number, number, number, number] = [36, 5, 30, 5];
const scaleProps = { const scaleProps = {
x: { x: {
type: 'cat', type: 'cat',
range: [0, 1], range: [0, 1],
...scale!.x, ...scale.x,
}, },
y: { y: {
min: 0, min: 0,
...scale!.y, ...scale.y,
}, },
}; };
const tooltip: [string, (...args: any[]) => { name?: string; value: string }] = [ const tooltip: [string, (...args: any[]) => { name?: string; value: string }] = [
'x*y', 'x*y',
(x: string, y: string) => ({ (x: string, y: string) => ({
name: x, name: x,
value: y, value: y,
}), }),
]; ];
const chartHeight = height + 54; const chartHeight = height + 54;
return ( return (
<div className={styles.miniChart} style={{ height }}> <div className={styles.miniChart} style={{ height }}>
<div className={styles.chartContent}> <div className={styles.chartContent}>
{height > 0 && ( {height > 0 && (
<Chart <Chart
animate={animate} animate={animate}
scale={scaleProps} scale={scaleProps}
height={chartHeight} height={chartHeight}
forceFit={forceFit} forceFit={forceFit}
data={data} data={data}
padding={padding} padding={padding}
> >
<Axis <Axis
key="axis-x" key="axis-x"
name="x" name="x"
label={false} label={undefined}
line={false} line={undefined}
tickLine={false} tickLine={undefined}
grid={false} grid={undefined}
{...xAxis} {...xAxis}
/> />
<Axis <Axis
key="axis-y" key="axis-y"
name="y" name="y"
label={false} label={undefined}
line={false} line={undefined}
tickLine={false} tickLine={undefined}
grid={false} grid={undefined}
{...yAxis} {...yAxis}
/> />
<Tooltip showTitle={false} crosshairs={false} /> <Tooltip showTitle={false} crosshairs={false} />
<Geom
type="area"
position="x*y"
color={color}
tooltip={tooltip}
shape="smooth"
style={{
fillOpacity: 1,
}}
/>
{line ? (
<Geom <Geom
type="area" type="line"
position="x*y" position="x*y"
color={color}
tooltip={tooltip}
shape="smooth" shape="smooth"
style={{ color={borderColor}
fillOpacity: 1, size={borderWidth}
}} tooltip={false}
/> />
{line ? ( ) : (
<Geom <span style={{ display: 'none' }} />
type="line" )}
position="x*y" </Chart>
shape="smooth" )}
color={borderColor}
size={borderWidth}
tooltip={false}
/>
) : (
<span style={{ display: 'none' }} />
)}
</Chart>
)}
</div>
</div> </div>
); </div>
} );
} };
export default autoHeight()(MiniArea); export default autoHeight()(MiniArea);
import { Chart, Geom, Tooltip } from 'bizcharts';
import React from 'react'; import React from 'react';
import { Chart, Tooltip, Geom } from 'bizcharts';
import autoHeight from '../autoHeight'; import autoHeight from '../autoHeight';
import styles from '../index.less'; import styles from '../index.less';
export interface IMiniBarProps { export interface MiniBarProps {
color?: string; color?: string;
height?: number; height?: number;
data: Array<{ data: {
x: number | string; x: number | string;
y: number; y: number;
}>; }[];
forceFit?: boolean; forceFit?: boolean;
style?: React.CSSProperties; style?: React.CSSProperties;
} }
class MiniBar extends React.Component<IMiniBarProps> { const MiniBar: React.FC<MiniBarProps> = props => {
render() { const { height = 0, forceFit = true, color = '#1890FF', data = [] } = props;
const { height = 0, forceFit = true, color = '#1890FF', data = [] } = this.props;
const scale = {
const scale = { x: {
x: { type: 'cat',
type: 'cat', },
}, y: {
y: { min: 0,
min: 0, },
}, };
};
const padding: [number, number, number, number] = [36, 5, 30, 5];
const padding: [number, number, number, number] = [36, 5, 30, 5];
const tooltip: [string, (...args: any[]) => { name?: string; value: string }] = [
const tooltip: [string, (...args: any[]) => { name?: string; value: string }] = [ 'x*y',
'x*y', (x: string, y: string) => ({
(x: string, y: string) => ({ name: x,
name: x, value: y,
value: y, }),
}), ];
];
// for tooltip not to be hide
// for tooltip not to be hide const chartHeight = height + 54;
const chartHeight = height + 54;
return (
return ( <div className={styles.miniChart} style={{ height }}>
<div className={styles.miniChart} style={{ height }}> <div className={styles.chartContent}>
<div className={styles.chartContent}> <Chart scale={scale} height={chartHeight} forceFit={forceFit} data={data} padding={padding}>
<Chart <Tooltip showTitle={false} crosshairs={false} />
scale={scale} <Geom type="interval" position="x*y" color={color} tooltip={tooltip} />
height={chartHeight} </Chart>
forceFit={forceFit}
data={data}
padding={padding}
>
<Tooltip showTitle={false} crosshairs={false} />
<Geom type="interval" position="x*y" color={color} tooltip={tooltip} />
</Chart>
</div>
</div> </div>
); </div>
} );
} };
export default autoHeight()(MiniBar); export default autoHeight()(MiniBar);
...@@ -2,7 +2,7 @@ import React from 'react'; ...@@ -2,7 +2,7 @@ import React from 'react';
import { Tooltip } from 'antd'; import { Tooltip } from 'antd';
import styles from './index.less'; import styles from './index.less';
export interface IMiniProgressProps { export interface MiniProgressProps {
target: number; target: number;
targetLabel?: string; targetLabel?: string;
color?: string; color?: string;
...@@ -11,33 +11,31 @@ export interface IMiniProgressProps { ...@@ -11,33 +11,31 @@ export interface IMiniProgressProps {
style?: React.CSSProperties; style?: React.CSSProperties;
} }
const MiniProgress: React.SFC<IMiniProgressProps> = ({ const MiniProgress: React.SFC<MiniProgressProps> = ({
targetLabel, targetLabel,
target, target,
color = 'rgb(19, 194, 194)', color = 'rgb(19, 194, 194)',
strokeWidth, strokeWidth,
percent, percent,
}) => { }) => (
return ( <div className={styles.miniProgress}>
<div className={styles.miniProgress}> <Tooltip title={targetLabel}>
<Tooltip title={targetLabel}> <div className={styles.target} style={{ left: target ? `${target}%` : undefined }}>
<div className={styles.target} style={{ left: target ? `${target}%` : undefined }}> <span style={{ backgroundColor: color || undefined }} />
<span style={{ backgroundColor: color || undefined }} /> <span style={{ backgroundColor: color || undefined }} />
<span style={{ backgroundColor: color || undefined }} />
</div>
</Tooltip>
<div className={styles.progressWrap}>
<div
className={styles.progress}
style={{
backgroundColor: color || undefined,
width: percent ? `${percent}%` : undefined,
height: strokeWidth || undefined,
}}
/>
</div> </div>
</Tooltip>
<div className={styles.progressWrap}>
<div
className={styles.progress}
style={{
backgroundColor: color || undefined,
width: percent ? `${percent}%` : undefined,
height: strokeWidth || undefined,
}}
/>
</div> </div>
); </div>
}; );
export default MiniProgress; export default MiniProgress;
import { Chart, Coord, Geom, Tooltip } from 'bizcharts';
import React, { Component } from 'react'; import React, { Component } from 'react';
import { Chart, Tooltip, Geom, Coord } from 'bizcharts';
import { DataView } from '@antv/data-set'; import { DataView } from '@antv/data-set';
import Debounce from 'lodash.debounce';
import { Divider } from 'antd'; import { Divider } from 'antd';
import classNames from 'classnames';
import ReactFitText from 'react-fittext'; import ReactFitText from 'react-fittext';
import Debounce from 'lodash-decorators/debounce'; import classNames from 'classnames';
import Bind from 'lodash-decorators/bind';
import autoHeight from '../autoHeight'; import autoHeight from '../autoHeight';
import styles from './index.less'; import styles from './index.less';
export interface IPieProps {
export interface PieProps {
animate?: boolean; animate?: boolean;
color?: string; color?: string;
colors?: string[]; colors?: string[];
...@@ -19,10 +19,10 @@ export interface IPieProps { ...@@ -19,10 +19,10 @@ export interface IPieProps {
hasLegend?: boolean; hasLegend?: boolean;
padding?: [number, number, number, number]; padding?: [number, number, number, number];
percent?: number; percent?: number;
data?: Array<{ data?: {
x: string | string; x: string | string;
y: number; y: number;
}>; }[];
inner?: number; inner?: number;
lineWidth?: number; lineWidth?: number;
forceFit?: boolean; forceFit?: boolean;
...@@ -34,19 +34,46 @@ export interface IPieProps { ...@@ -34,19 +34,46 @@ export interface IPieProps {
valueFormat?: (value: string) => string | React.ReactNode; valueFormat?: (value: string) => string | React.ReactNode;
subTitle?: React.ReactNode; subTitle?: React.ReactNode;
} }
interface IPieState { interface PieState {
legendData: Array<{ checked: boolean; x: string; color: string; percent: number; y: string }>; legendData: { checked: boolean; x: string; color: string; percent: number; y: string }[];
legendBlock: boolean; legendBlock: boolean;
} }
class Pie extends Component<IPieProps, IPieState> { class Pie extends Component<PieProps, PieState> {
state: IPieState = { state: PieState = {
legendData: [], legendData: [],
legendBlock: false, legendBlock: false,
}; };
requestRef: number | undefined; requestRef: number | undefined = undefined;
root!: HTMLDivElement;
chart: G2.Chart | undefined; root: HTMLDivElement | undefined = undefined;
chart: G2.Chart | undefined = undefined;
// for window resize auto responsive legend
resize = Debounce(() => {
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,
});
}
}, 400);
componentDidMount() { componentDidMount() {
window.addEventListener( window.addEventListener(
...@@ -58,7 +85,7 @@ class Pie extends Component<IPieProps, IPieState> { ...@@ -58,7 +85,7 @@ class Pie extends Component<IPieProps, IPieState> {
); );
} }
componentDidUpdate(preProps: IPieProps) { componentDidUpdate(preProps: PieProps) {
const { data } = this.props; const { data } = this.props;
if (data !== preProps.data) { if (data !== preProps.data) {
// because of charts data create when rendered // because of charts data create when rendered
...@@ -90,7 +117,7 @@ class Pie extends Component<IPieProps, IPieState> { ...@@ -90,7 +117,7 @@ class Pie extends Component<IPieProps, IPieState> {
if (!this.chart) return; if (!this.chart) return;
const geom = this.chart.getAllGeoms()[0]; // 获取所有的图形 const geom = this.chart.getAllGeoms()[0]; // 获取所有的图形
if (!geom) return; if (!geom) return;
const items = geom.get('dataArray') || []; // 获取图形对应的 const items = (geom as any).get('dataArray') || []; // 获取图形对应的
const legendData = items.map((item: { color: any; _origin: any }[]) => { const legendData = items.map((item: { color: any; _origin: any }[]) => {
/* eslint no-underscore-dangle:0 */ /* eslint no-underscore-dangle:0 */
...@@ -104,6 +131,7 @@ class Pie extends Component<IPieProps, IPieState> { ...@@ -104,6 +131,7 @@ class Pie extends Component<IPieProps, IPieState> {
legendData, legendData,
}); });
}; };
handleRoot = (n: HTMLDivElement) => { handleRoot = (n: HTMLDivElement) => {
this.root = n; this.root = n;
}; };
...@@ -118,7 +146,7 @@ class Pie extends Component<IPieProps, IPieState> { ...@@ -118,7 +146,7 @@ class Pie extends Component<IPieProps, IPieState> {
const filteredLegendData = legendData.filter(l => l.checked).map(l => l.x); const filteredLegendData = legendData.filter(l => l.checked).map(l => l.x);
if (this.chart) { if (this.chart) {
this.chart.filter('x', val => filteredLegendData.indexOf(val + '') > -1); this.chart.filter('x', val => filteredLegendData.indexOf(`${val}`) > -1);
} }
this.setState({ this.setState({
...@@ -126,33 +154,6 @@ class Pie extends Component<IPieProps, IPieState> { ...@@ -126,33 +154,6 @@ class Pie extends Component<IPieProps, IPieState> {
}); });
}; };
// 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() { render() {
const { const {
valueFormat, valueFormat,
...@@ -216,11 +217,11 @@ class Pie extends Component<IPieProps, IPieState> { ...@@ -216,11 +217,11 @@ class Pie extends Component<IPieProps, IPieState> {
data = [ data = [
{ {
x: '占比', x: '占比',
y: parseFloat(percent + ''), y: parseFloat(`${percent}`),
}, },
{ {
x: '反比', x: '反比',
y: 100 - parseFloat(percent + ''), y: 100 - parseFloat(`${percent}`),
}, },
]; ];
} }
......
import { Chart, Coord, Geom, Shape, Tooltip } from 'bizcharts';
import React, { Component } from 'react'; import React, { Component } from 'react';
import { Chart, Geom, Coord, Shape, Tooltip } from 'bizcharts';
import DataSet from '@antv/data-set'; import DataSet from '@antv/data-set';
import Debounce from 'lodash-decorators/debounce'; import Debounce from 'lodash.debounce';
import Bind from 'lodash-decorators/bind';
import classNames from 'classnames'; import classNames from 'classnames';
import autoHeight from '../autoHeight'; import autoHeight from '../autoHeight';
import styles from './index.less'; import styles from './index.less';
...@@ -12,33 +12,36 @@ import styles from './index.less'; ...@@ -12,33 +12,36 @@ import styles from './index.less';
const imgUrl = 'https://gw.alipayobjects.com/zos/rmsportal/gWyeGLCdFFRavBGIDzWk.png'; const imgUrl = 'https://gw.alipayobjects.com/zos/rmsportal/gWyeGLCdFFRavBGIDzWk.png';
export interface ITagCloudProps { export interface TagCloudProps {
data: Array<{ data: {
name: string; name: string;
value: number; value: number;
}>; }[];
height?: number; height?: number;
className?: string; className?: string;
style?: React.CSSProperties; style?: React.CSSProperties;
} }
interface ITagCloudState { interface TagCloudState {
dv: any; dv: any;
height?: number; height?: number;
width: number; width: number;
} }
class TagCloud extends Component<ITagCloudProps, ITagCloudState> { class TagCloud extends Component<TagCloudProps, TagCloudState> {
state = { state = {
dv: null, dv: null,
height: 0, height: 0,
width: 0, width: 0,
}; };
isUnmount!: boolean;
requestRef!: number;
root: HTMLDivElement | undefined; isUnmount: boolean = false;
imageMask: HTMLImageElement | undefined;
requestRef: number = 0;
root: HTMLDivElement | undefined = undefined;
imageMask: HTMLImageElement | undefined = undefined;
componentDidMount() { componentDidMount() {
requestAnimationFrame(() => { requestAnimationFrame(() => {
...@@ -48,22 +51,25 @@ class TagCloud extends Component<ITagCloudProps, ITagCloudState> { ...@@ -48,22 +51,25 @@ class TagCloud extends Component<ITagCloudProps, ITagCloudState> {
window.addEventListener('resize', this.resize, { passive: true }); window.addEventListener('resize', this.resize, { passive: true });
} }
componentDidUpdate(preProps?: ITagCloudProps) { componentDidUpdate(preProps?: TagCloudProps) {
const { data } = this.props; const { data } = this.props;
if (preProps && JSON.stringify(preProps.data) !== JSON.stringify(data)) { if (preProps && JSON.stringify(preProps.data) !== JSON.stringify(data)) {
this.renderChart(this.props); this.renderChart(this.props);
} }
} }
componentWillUnmount() { componentWillUnmount() {
this.isUnmount = true; this.isUnmount = true;
window.cancelAnimationFrame(this.requestRef); window.cancelAnimationFrame(this.requestRef);
window.removeEventListener('resize', this.resize); window.removeEventListener('resize', this.resize);
} }
resize = () => { resize = () => {
this.requestRef = requestAnimationFrame(() => { this.requestRef = requestAnimationFrame(() => {
this.renderChart(this.props); this.renderChart(this.props);
}); });
}; };
saveRootRef = (node: HTMLDivElement) => { saveRootRef = (node: HTMLDivElement) => {
this.root = node; this.root = node;
}; };
...@@ -77,7 +83,8 @@ class TagCloud extends Component<ITagCloudProps, ITagCloudState> { ...@@ -77,7 +83,8 @@ class TagCloud extends Component<ITagCloudProps, ITagCloudState> {
origin?: any; origin?: any;
color?: any; color?: any;
}) { }) {
return Object.assign({}, cfg.style, { return {
...cfg.style,
fillOpacity: cfg.opacity, fillOpacity: cfg.opacity,
fontSize: cfg.origin._origin.size, fontSize: cfg.origin._origin.size,
rotate: cfg.origin._origin.rotate, rotate: cfg.origin._origin.rotate,
...@@ -86,7 +93,7 @@ class TagCloud extends Component<ITagCloudProps, ITagCloudState> { ...@@ -86,7 +93,7 @@ class TagCloud extends Component<ITagCloudProps, ITagCloudState> {
fontFamily: cfg.origin._origin.font, fontFamily: cfg.origin._origin.font,
fill: cfg.color, fill: cfg.color,
textBaseline: 'Alphabetic', textBaseline: 'Alphabetic',
}); };
} }
(Shape as any).registerShape('point', 'cloud', { (Shape as any).registerShape('point', 'cloud', {
...@@ -96,18 +103,17 @@ class TagCloud extends Component<ITagCloudProps, ITagCloudState> { ...@@ -96,18 +103,17 @@ class TagCloud extends Component<ITagCloudProps, ITagCloudState> {
) { ) {
const attrs = getTextAttrs(cfg); const attrs = getTextAttrs(cfg);
return container.addShape('text', { return container.addShape('text', {
attrs: Object.assign(attrs, { attrs: {
...attrs,
x: cfg.x, x: cfg.x,
y: cfg.y, y: cfg.y,
}), },
}); });
}, },
}); });
}; };
@Bind() renderChart = Debounce((nextProps: TagCloudProps) => {
@Debounce(500)
renderChart(nextProps: ITagCloudProps) {
// const colors = ['#1890FF', '#41D9C7', '#2FC25B', '#FACC14', '#9AE65C']; // const colors = ['#1890FF', '#41D9C7', '#2FC25B', '#FACC14', '#9AE65C'];
const { data, height } = nextProps || this.props; const { data, height } = nextProps || this.props;
...@@ -134,8 +140,8 @@ class TagCloud extends Component<ITagCloudProps, ITagCloudState> { ...@@ -134,8 +140,8 @@ class TagCloud extends Component<ITagCloudProps, ITagCloudState> {
return 0; return 0;
}, },
fontSize(d: { value: number }) { fontSize(d: { value: number }) {
// eslint-disable-next-line const size = ((d.value - min) / (max - min)) ** 2;
return Math.pow((d.value - min) / (max - min), 2) * (17.5 - 5) + 5; return size * (17.5 - 5) + 5;
}, },
}); });
...@@ -159,7 +165,7 @@ class TagCloud extends Component<ITagCloudProps, ITagCloudState> { ...@@ -159,7 +165,7 @@ class TagCloud extends Component<ITagCloudProps, ITagCloudState> {
} else { } else {
onload(); onload();
} }
} }, 500);
render() { render() {
const { className, height } = this.props; const { className, height } = this.props;
......
import React from 'react'; import { Axis, Chart, Geom, Legend, Tooltip } from 'bizcharts';
import { Chart, Tooltip, Geom, Legend, Axis } from 'bizcharts';
import DataSet from '@antv/data-set'; import DataSet from '@antv/data-set';
import React from 'react';
import Slider from 'bizcharts-plugin-slider'; import Slider from 'bizcharts-plugin-slider';
import autoHeight from '../autoHeight'; import autoHeight from '../autoHeight';
import styles from './index.less'; import styles from './index.less';
export interface ITimelineChartProps { export interface TimelineChartProps {
data: Array<{ data: {
x: number; x: number;
y1: number; y1: number;
y2: number; y2: number;
}>; }[];
title?: string; title?: string;
titleMap: { y1: string; y2: string }; titleMap: { y1: string; y2: string };
padding?: [number, number, number, number]; padding?: [number, number, number, number];
...@@ -19,115 +20,113 @@ export interface ITimelineChartProps { ...@@ -19,115 +20,113 @@ export interface ITimelineChartProps {
borderWidth?: number; borderWidth?: number;
} }
class TimelineChart extends React.Component<ITimelineChartProps> { const TimelineChart: React.FC<TimelineChartProps> = props => {
render() { const {
const { title,
title, height = 400,
height = 400, padding = [60, 20, 40, 40] as [number, number, number, number],
padding = [60, 20, 40, 40] as [number, number, number, number], titleMap = {
titleMap = { y1: 'y1',
y1: 'y1', y2: 'y2',
y2: 'y2', },
}, borderWidth = 2,
borderWidth = 2, data: sourceData,
data: sourceData, } = props;
} = this.props;
const data = Array.isArray(sourceData) ? sourceData : [{ x: 0, y1: 0, y2: 0 }]; const data = Array.isArray(sourceData) ? sourceData : [{ x: 0, y1: 0, y2: 0 }];
data.sort((a, b) => a.x - b.x); 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,
);
}
let max; const ds = new DataSet({
if (data[0] && data[0].y1 && data[0].y2) { state: {
max = Math.max( start: data[0].x,
[...data].sort((a, b) => b.y1 - a.y1)[0].y1, end: data[data.length - 1].x,
[...data].sort((a, b) => b.y2 - a.y2)[0].y2, },
); });
}
const ds = new DataSet({ const dv = ds.createView();
state: { dv.source(data)
start: data[0].x, .transform({
end: data[data.length - 1].x, 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 dv = ds.createView(); const timeScale = {
dv.source(data) type: 'time',
.transform({ tickInterval: 60 * 60 * 1000,
type: 'filter', mask: 'HH:mm',
callback: (obj: { x: string }) => { range: [0, 1],
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 = { const cols = {
x: timeScale, x: timeScale,
value: { value: {
max, max,
min: 0, min: 0,
}, },
}; };
const SliderGen = () => ( const SliderGen = () => (
<Slider <Slider
padding={[0, padding[1] + 20, 0, padding[3]]} padding={[0, padding[1] + 20, 0, padding[3]]}
width="auto" width="auto"
height={26} height={26}
xAxis="x" xAxis="x"
yAxis="y1" yAxis="y1"
scales={{ x: timeScale }} scales={{ x: timeScale }}
data={data} data={data}
start={ds.state.start} start={ds.state.start}
end={ds.state.end} end={ds.state.end}
backgroundChart={{ type: 'line' }} backgroundChart={{ type: 'line' }}
onChange={({ startValue, endValue }: { startValue: string; endValue: string }) => { onChange={({ startValue, endValue }: { startValue: string; endValue: string }) => {
ds.setState('start', startValue); ds.setState('start', startValue);
ds.setState('end', endValue); ds.setState('end', endValue);
}} }}
/> />
); );
return ( return (
<div className={styles.timelineChart} style={{ height: height + 30 }}> <div className={styles.timelineChart} style={{ height: height + 30 }}>
<div> <div>
{title && <h4>{title}</h4>} {title && <h4>{title}</h4>}
<Chart height={height} padding={padding} data={dv} scale={cols} forceFit> <Chart height={height} padding={padding} data={dv} scale={cols} forceFit>
<Axis name="x" /> <Axis name="x" />
<Tooltip /> <Tooltip />
<Legend name="key" position="top" /> <Legend name="key" position="top" />
<Geom type="line" position="x*value" size={borderWidth} color="key" /> <Geom type="line" position="x*value" size={borderWidth} color="key" />
</Chart> </Chart>
<div style={{ marginRight: -20 }}> <div style={{ marginRight: -20 }}>
<SliderGen /> <SliderGen />
</div>
</div> </div>
</div> </div>
); </div>
} );
} };
export default autoHeight()(TimelineChart); export default autoHeight()(TimelineChart);
import React, { Component } from 'react'; import React, { Component } from 'react';
import autoHeight from '../autoHeight'; import autoHeight from '../autoHeight';
import styles from './index.less'; import styles from './index.less';
...@@ -6,7 +7,7 @@ import styles from './index.less'; ...@@ -6,7 +7,7 @@ import styles from './index.less';
/* eslint no-mixed-operators: 0 */ /* eslint no-mixed-operators: 0 */
// riddle: https://riddle.alibaba-inc.com/riddles/2d9a4b90 // riddle: https://riddle.alibaba-inc.com/riddles/2d9a4b90
export interface IWaterWaveProps { export interface WaterWaveProps {
title: React.ReactNode; title: React.ReactNode;
color?: string; color?: string;
height?: number; height?: number;
...@@ -14,13 +15,16 @@ export interface IWaterWaveProps { ...@@ -14,13 +15,16 @@ export interface IWaterWaveProps {
style?: React.CSSProperties; style?: React.CSSProperties;
} }
class WaterWave extends Component<IWaterWaveProps> { class WaterWave extends Component<WaterWaveProps> {
state = { state = {
radio: 1, radio: 1,
}; };
timer: number = 0; timer: number = 0;
root: HTMLDivElement | undefined | null;
node: HTMLCanvasElement | undefined | null; root: HTMLDivElement | undefined | null = null;
node: HTMLCanvasElement | undefined | null = null;
componentDidMount() { componentDidMount() {
this.renderChart(); this.renderChart();
...@@ -34,7 +38,7 @@ class WaterWave extends Component<IWaterWaveProps> { ...@@ -34,7 +38,7 @@ class WaterWave extends Component<IWaterWaveProps> {
); );
} }
componentDidUpdate(props: IWaterWaveProps) { componentDidUpdate(props: WaterWaveProps) {
const { percent } = this.props; const { percent } = this.props;
if (props.percent !== percent) { if (props.percent !== percent) {
// 不加这个会造成绘制缓慢 // 不加这个会造成绘制缓慢
...@@ -59,6 +63,7 @@ class WaterWave extends Component<IWaterWaveProps> { ...@@ -59,6 +63,7 @@ class WaterWave extends Component<IWaterWaveProps> {
}); });
} }
}; };
renderChart(type?: string) { renderChart(type?: string) {
const { percent, color = '#1890FF' } = this.props; const { percent, color = '#1890FF' } = this.props;
const data = percent / 100; const data = percent / 100;
...@@ -201,6 +206,7 @@ class WaterWave extends Component<IWaterWaveProps> { ...@@ -201,6 +206,7 @@ class WaterWave extends Component<IWaterWaveProps> {
} }
render(); render();
} }
render() { render() {
const { radio } = this.state; const { radio } = this.state;
const { percent, title, height = 1 } = this.props; const { percent, title, height = 1 } = this.props;
......
...@@ -6,15 +6,16 @@ export type IReactComponent<P = any> = ...@@ -6,15 +6,16 @@ export type IReactComponent<P = any> =
| React.ClassicComponentClass<P>; | React.ClassicComponentClass<P>;
function computeHeight(node: HTMLDivElement) { function computeHeight(node: HTMLDivElement) {
node.style.height = '100%'; const { style } = node;
const totalHeight = parseInt(getComputedStyle(node).height + '', 10); style.height = '100%';
const totalHeight = parseInt(`${getComputedStyle(node).height}`, 10);
const padding = const padding =
parseInt(getComputedStyle(node).paddingTop + '', 10) + parseInt(`${getComputedStyle(node).paddingTop}`, 10) +
parseInt(getComputedStyle(node).paddingBottom + '', 10); parseInt(`${getComputedStyle(node).paddingBottom}`, 10);
return totalHeight - padding; return totalHeight - padding;
} }
function getAutoHeight(n: HTMLDivElement) { function getAutoHeight(n: HTMLDivElement | undefined) {
if (!n) { if (!n) {
return 0; return 0;
} }
...@@ -30,24 +31,25 @@ function getAutoHeight(n: HTMLDivElement) { ...@@ -30,24 +31,25 @@ function getAutoHeight(n: HTMLDivElement) {
return height; return height;
} }
interface IAutoHeightProps { interface AutoHeightProps {
height?: number; height?: number;
} }
function autoHeight() { function autoHeight() {
return function<P extends IAutoHeightProps>( return <P extends AutoHeightProps>(
WrappedComponent: React.ComponentClass<P> | React.SFC<P>, WrappedComponent: React.ComponentClass<P> | React.SFC<P>,
): React.ComponentClass<P> { ): React.ComponentClass<P> => {
class AutoHeightComponent extends React.Component<P & IAutoHeightProps> { class AutoHeightComponent extends React.Component<P & AutoHeightProps> {
state = { state = {
computedHeight: 0, computedHeight: 0,
}; };
root!: HTMLDivElement;
root: HTMLDivElement | undefined = undefined;
componentDidMount() { componentDidMount() {
const { height } = this.props; const { height } = this.props;
if (!height) { if (!height) {
let h = getAutoHeight(this.root); let h = getAutoHeight(this.root);
// eslint-disable-next-line
this.setState({ computedHeight: h }); this.setState({ computedHeight: h });
if (h < 1) { if (h < 1) {
h = getAutoHeight(this.root); h = getAutoHeight(this.root);
...@@ -55,9 +57,11 @@ function autoHeight() { ...@@ -55,9 +57,11 @@ function autoHeight() {
} }
} }
} }
handleRoot = (node: HTMLDivElement) => { handleRoot = (node: HTMLDivElement) => {
this.root = node; this.root = node;
}; };
render() { render() {
const { height } = this.props; const { height } = this.props;
const { computedHeight } = this.state; const { computedHeight } = this.state;
......
import numeral from 'numeral'; import numeral from 'numeral';
import Bar from './Bar';
import ChartCard from './ChartCard'; import ChartCard from './ChartCard';
import Field from './Field'; import Field from './Field';
import Bar from './Bar';
import Pie from './Pie';
import Gauge from './Gauge'; import Gauge from './Gauge';
import MiniArea from './MiniArea'; import MiniArea from './MiniArea';
import MiniBar from './MiniBar'; import MiniBar from './MiniBar';
import MiniProgress from './MiniProgress'; import MiniProgress from './MiniProgress';
import WaterWave from './WaterWave'; import Pie from './Pie';
import TagCloud from './TagCloud'; import TagCloud from './TagCloud';
import TimelineChart from './TimelineChart'; import TimelineChart from './TimelineChart';
import WaterWave from './WaterWave';
const yuan = (val: number | string) => ${numeral(val).format('0,0')}`; const yuan = (val: number | string) => ${numeral(val).format('0,0')}`;
......
import React from 'react'; import { Col, Icon, Row, Tooltip } from 'antd';
import { Row, Col, Icon, Tooltip } from 'antd';
import { FormattedMessage } from 'umi-plugin-react/locale'; import { FormattedMessage } from 'umi-plugin-react/locale';
import Charts from './Charts'; import React from 'react';
import numeral from 'numeral'; import numeral from 'numeral';
import styles from '../style.less'; import { ChartCard, MiniArea, MiniBar, MiniProgress, Field } from './Charts';
import Yuan from '../utils/Yuan'; import { VisitDataType } from '../data.d';
import Trend from './Trend'; import Trend from './Trend';
import { IVisitData } from '../data.d'; import Yuan from '../utils/Yuan';
const { ChartCard, MiniArea, MiniBar, MiniProgress, Field } = Charts; import styles from '../style.less';
const topColResponsiveProps = { const topColResponsiveProps = {
xs: 24, xs: 24,
...@@ -18,148 +18,143 @@ const topColResponsiveProps = { ...@@ -18,148 +18,143 @@ const topColResponsiveProps = {
style: { marginBottom: 24 }, style: { marginBottom: 24 },
}; };
const IntroduceRow = ({ loading, visitData }: { loading: boolean; visitData: IVisitData[] }) => { const IntroduceRow = ({ loading, visitData }: { loading: boolean; visitData: VisitDataType[] }) => (
return ( <Row gutter={24}>
<Row gutter={24}> <Col {...topColResponsiveProps}>
<Col {...topColResponsiveProps}> <ChartCard
<ChartCard bordered={false}
bordered={false} title={
title={ <FormattedMessage id="BLOCK_NAME.analysis.total-sales" defaultMessage="Total Sales" />
<FormattedMessage id="BLOCK_NAME.analysis.total-sales" defaultMessage="Total Sales" /> }
} action={
action={ <Tooltip
<Tooltip title={
title={ <FormattedMessage id="BLOCK_NAME.analysis.introduce" defaultMessage="Introduce" />
<FormattedMessage id="BLOCK_NAME.analysis.introduce" defaultMessage="Introduce" /> }
} >
> <Icon type="info-circle-o" />
<Icon type="info-circle-o" /> </Tooltip>
</Tooltip> }
} loading={loading}
loading={loading} total={() => <Yuan>126560</Yuan>}
total={() => <Yuan>126560</Yuan>} footer={
footer={ <Field
<Field label={
label={ <FormattedMessage id="BLOCK_NAME.analysis.day-sales" defaultMessage="Daily Sales" />
<FormattedMessage id="BLOCK_NAME.analysis.day-sales" defaultMessage="Daily Sales" /> }
} value={`¥${numeral(12423).format('0,0')}`}
value={`¥${numeral(12423).format('0,0')}`} />
/> }
} contentHeight={46}
contentHeight={46} >
> <Trend flag="up" style={{ marginRight: 16 }}>
<Trend flag="up" style={{ marginRight: 16 }}> <FormattedMessage id="BLOCK_NAME.analysis.week" defaultMessage="Weekly Changes" />
<FormattedMessage id="BLOCK_NAME.analysis.week" defaultMessage="Weekly Changes" /> <span className={styles.trendText}>12%</span>
<span className={styles.trendText}>12%</span> </Trend>
</Trend> <Trend flag="down">
<Trend flag="down"> <FormattedMessage id="BLOCK_NAME.analysis.day" defaultMessage="Daily Changes" />
<FormattedMessage id="BLOCK_NAME.analysis.day" defaultMessage="Daily Changes" /> <span className={styles.trendText}>11%</span>
<span className={styles.trendText}>11%</span> </Trend>
</Trend> </ChartCard>
</ChartCard> </Col>
</Col>
<Col {...topColResponsiveProps}> <Col {...topColResponsiveProps}>
<ChartCard <ChartCard
bordered={false} bordered={false}
loading={loading} loading={loading}
title={<FormattedMessage id="BLOCK_NAME.analysis.visits" defaultMessage="Visits" />} title={<FormattedMessage id="BLOCK_NAME.analysis.visits" defaultMessage="Visits" />}
action={ action={
<Tooltip <Tooltip
title={ title={
<FormattedMessage id="BLOCK_NAME.analysis.introduce" defaultMessage="Introduce" /> <FormattedMessage id="BLOCK_NAME.analysis.introduce" defaultMessage="Introduce" />
} }
> >
<Icon type="info-circle-o" /> <Icon type="info-circle-o" />
</Tooltip> </Tooltip>
} }
total={numeral(8846).format('0,0')} total={numeral(8846).format('0,0')}
footer={ footer={
<Field <Field
label={ label={
<FormattedMessage <FormattedMessage id="BLOCK_NAME.analysis.day-visits" defaultMessage="Daily Visits" />
id="BLOCK_NAME.analysis.day-visits" }
defaultMessage="Daily Visits" value={numeral(1234).format('0,0')}
/> />
} }
value={numeral(1234).format('0,0')} contentHeight={46}
/> >
} <MiniArea color="#975FE4" data={visitData} />
contentHeight={46} </ChartCard>
> </Col>
<MiniArea color="#975FE4" data={visitData} /> <Col {...topColResponsiveProps}>
</ChartCard> <ChartCard
</Col> bordered={false}
<Col {...topColResponsiveProps}> loading={loading}
<ChartCard title={<FormattedMessage id="BLOCK_NAME.analysis.payments" defaultMessage="Payments" />}
bordered={false} action={
loading={loading} <Tooltip
title={<FormattedMessage id="BLOCK_NAME.analysis.payments" defaultMessage="Payments" />} title={
action={ <FormattedMessage id="BLOCK_NAME.analysis.introduce" defaultMessage="Introduce" />
<Tooltip }
title={ >
<FormattedMessage id="BLOCK_NAME.analysis.introduce" defaultMessage="Introduce" /> <Icon type="info-circle-o" />
} </Tooltip>
> }
<Icon type="info-circle-o" /> total={numeral(6560).format('0,0')}
</Tooltip> footer={
} <Field
total={numeral(6560).format('0,0')} label={
footer={ <FormattedMessage
<Field id="BLOCK_NAME.analysis.conversion-rate"
label={ defaultMessage="Conversion Rate"
<FormattedMessage />
id="BLOCK_NAME.analysis.conversion-rate" }
defaultMessage="Conversion Rate" value="60%"
/> />
} }
value="60%" contentHeight={46}
/> >
} <MiniBar data={visitData} />
contentHeight={46} </ChartCard>
> </Col>
<MiniBar data={visitData} /> <Col {...topColResponsiveProps}>
</ChartCard> <ChartCard
</Col> loading={loading}
<Col {...topColResponsiveProps}> bordered={false}
<ChartCard title={
loading={loading} <FormattedMessage
bordered={false} id="BLOCK_NAME.analysis.operational-effect"
title={ defaultMessage="Operational Effect"
<FormattedMessage />
id="BLOCK_NAME.analysis.operational-effect" }
defaultMessage="Operational Effect" action={
/> <Tooltip
} title={
action={ <FormattedMessage id="BLOCK_NAME.analysis.introduce" defaultMessage="Introduce" />
<Tooltip }
title={ >
<FormattedMessage id="BLOCK_NAME.analysis.introduce" defaultMessage="Introduce" /> <Icon type="info-circle-o" />
} </Tooltip>
> }
<Icon type="info-circle-o" /> total="78%"
</Tooltip> footer={
} <div style={{ whiteSpace: 'nowrap', overflow: 'hidden' }}>
total="78%" <Trend flag="up" style={{ marginRight: 16 }}>
footer={ <FormattedMessage id="BLOCK_NAME.analysis.week" defaultMessage="Weekly Changes" />
<div style={{ whiteSpace: 'nowrap', overflow: 'hidden' }}> <span className={styles.trendText}>12%</span>
<Trend flag="up" style={{ marginRight: 16 }}> </Trend>
<FormattedMessage id="BLOCK_NAME.analysis.week" defaultMessage="Weekly Changes" /> <Trend flag="down">
<span className={styles.trendText}>12%</span> <FormattedMessage id="BLOCK_NAME.analysis.day" defaultMessage="Weekly Changes" />
</Trend> <span className={styles.trendText}>11%</span>
<Trend flag="down"> </Trend>
<FormattedMessage id="BLOCK_NAME.analysis.day" defaultMessage="Weekly Changes" /> </div>
<span className={styles.trendText}>11%</span> }
</Trend> contentHeight={46}
</div> >
} <MiniProgress percent={78} strokeWidth={8} target={80} color="#13C2C2" />
contentHeight={46} </ChartCard>
> </Col>
<MiniProgress percent={78} strokeWidth={8} target={80} color="#13C2C2" /> </Row>
</ChartCard> );
</Col>
</Row>
);
};
export default IntroduceRow; export default IntroduceRow;
import React from 'react';
import { Icon } from 'antd'; import { Icon } from 'antd';
import React from 'react';
import classNames from 'classnames'; import classNames from 'classnames';
import styles from './index.less'; import styles from './index.less';
export interface NumberInfoProps { export interface NumberInfoProps {
title?: React.ReactNode | string; title?: React.ReactNode | string;
subTitle?: React.ReactNode | string; subTitle?: React.ReactNode | string;
......
import { Card, Col, Row, Tabs } from 'antd';
import { FormattedMessage, formatMessage } from 'umi-plugin-react/locale';
import React from 'react'; import React from 'react';
import { Card, Tabs, Row, Col } from 'antd'; import { OfflineChartData, OfflineDataType } from '../data.d';
import { formatMessage, FormattedMessage } from 'umi-plugin-react/locale';
import Charts from './Charts'; import { TimelineChart, Pie } from './Charts';
import styles from '../style.less';
import NumberInfo from './NumberInfo'; import NumberInfo from './NumberInfo';
import { IOfflineData, IOfflineChartData } from '../data'; import styles from '../style.less';
const { TimelineChart, Pie } = Charts;
const CustomTab = ({ const CustomTab = ({
data, data,
currentTabKey: currentKey, currentTabKey: currentKey,
}: { }: {
data: IOfflineData; data: OfflineDataType;
currentTabKey: string; currentTabKey: string;
}) => { }) => (
return ( <Row gutter={8} style={{ width: 138, margin: '8px 0' }}>
<Row gutter={8} style={{ width: 138, margin: '8px 0' }}> <Col span={12}>
<Col span={12}> <NumberInfo
<NumberInfo title={data.name}
title={data.name} subTitle={
subTitle={ <FormattedMessage
<FormattedMessage id="BLOCK_NAME.analysis.conversion-rate"
id="BLOCK_NAME.analysis.conversion-rate" defaultMessage="Conversion Rate"
defaultMessage="Conversion Rate" />
/> }
} gap={2}
gap={2} total={`${data.cvr * 100}%`}
total={`${data.cvr * 100}%`} theme={currentKey !== data.name ? 'light' : undefined}
theme={currentKey !== data.name ? 'light' : undefined} />
/> </Col>
</Col> <Col span={12} style={{ paddingTop: 36 }}>
<Col span={12} style={{ paddingTop: 36 }}> <Pie
<Pie animate={false}
animate={false} inner={0.55}
inner={0.55} tooltip={false}
tooltip={false} margin={[0, 0, 0, 0]}
margin={[0, 0, 0, 0]} percent={data.cvr * 100}
percent={data.cvr * 100} height={64}
height={64} />
/> </Col>
</Col> </Row>
</Row> );
);
};
const { TabPane } = Tabs; const { TabPane } = Tabs;
...@@ -55,8 +53,8 @@ const OfflineData = ({ ...@@ -55,8 +53,8 @@ const OfflineData = ({
}: { }: {
activeKey: string; activeKey: string;
loading: boolean; loading: boolean;
offlineData: IOfflineData[]; offlineData: OfflineDataType[];
offlineChartData: IOfflineChartData[]; offlineChartData: OfflineChartData[];
handleTabChange: (activeKey: string) => void; handleTabChange: (activeKey: string) => void;
}) => ( }) => (
<Card loading={loading} className={styles.offlineCard} bordered={false} style={{ marginTop: 32 }}> <Card loading={loading} className={styles.offlineCard} bordered={false} style={{ marginTop: 32 }}>
......
import React from 'react';
import { Card, Radio } from 'antd'; import { Card, Radio } from 'antd';
import Charts from './Charts';
import { FormattedMessage } from 'umi-plugin-react/locale'; import { FormattedMessage } from 'umi-plugin-react/locale';
import styles from '../style.less';
import Yuan from '../utils/Yuan';
import { RadioChangeEvent } from 'antd/es/radio'; import { RadioChangeEvent } from 'antd/es/radio';
import { ISalesData } from '../data'; import React from 'react';
import { VisitDataType } from '../data.d';
const { Pie } = Charts; import { Pie } from './Charts';
import Yuan from '../utils/Yuan';
import styles from '../style.less';
const ProportionSales = ({ const ProportionSales = ({
dropdownGroup, dropdownGroup,
...@@ -19,61 +18,59 @@ const ProportionSales = ({ ...@@ -19,61 +18,59 @@ const ProportionSales = ({
loading: boolean; loading: boolean;
dropdownGroup: React.ReactNode; dropdownGroup: React.ReactNode;
salesType: 'all' | 'online' | 'stores'; salesType: 'all' | 'online' | 'stores';
salesPieData: ISalesData[]; salesPieData: VisitDataType[];
handleChangeSalesType?: (e: RadioChangeEvent) => void; handleChangeSalesType?: (e: RadioChangeEvent) => void;
}) => { }) => (
return ( <Card
<Card loading={loading}
loading={loading} className={styles.salesCard}
className={styles.salesCard} bordered={false}
bordered={false} title={
title={ <FormattedMessage
<FormattedMessage id="BLOCK_NAME.analysis.the-proportion-of-sales"
id="BLOCK_NAME.analysis.the-proportion-of-sales" defaultMessage="The Proportion of Sales"
defaultMessage="The Proportion of Sales" />
/> }
} bodyStyle={{ padding: 24 }}
bodyStyle={{ padding: 24 }} extra={
extra={ <div className={styles.salesCardExtra}>
<div className={styles.salesCardExtra}> {dropdownGroup}
{dropdownGroup} <div className={styles.salesTypeRadio}>
<div className={styles.salesTypeRadio}> <Radio.Group value={salesType} onChange={handleChangeSalesType}>
<Radio.Group value={salesType} onChange={handleChangeSalesType}> <Radio.Button value="all">
<Radio.Button value="all"> <FormattedMessage id="BLOCK_NAME.channel.all" defaultMessage="ALL" />
<FormattedMessage id="BLOCK_NAME.channel.all" defaultMessage="ALL" /> </Radio.Button>
</Radio.Button> <Radio.Button value="online">
<Radio.Button value="online"> <FormattedMessage id="BLOCK_NAME.channel.online" defaultMessage="Online" />
<FormattedMessage id="BLOCK_NAME.channel.online" defaultMessage="Online" /> </Radio.Button>
</Radio.Button> <Radio.Button value="stores">
<Radio.Button value="stores"> <FormattedMessage id="BLOCK_NAME.channel.stores" defaultMessage="Stores" />
<FormattedMessage id="BLOCK_NAME.channel.stores" defaultMessage="Stores" /> </Radio.Button>
</Radio.Button> </Radio.Group>
</Radio.Group>
</div>
</div> </div>
}
style={{ marginTop: 24 }}
>
<div
style={{
minHeight: 380,
}}
>
<h4 style={{ marginTop: 8, marginBottom: 32 }}>
<FormattedMessage id="BLOCK_NAME.analysis.sales" defaultMessage="Sales" />
</h4>
<Pie
hasLegend
subTitle={<FormattedMessage id="BLOCK_NAME.analysis.sales" defaultMessage="Sales" />}
total={() => <Yuan>{salesPieData.reduce((pre, now) => now.y + pre, 0)}</Yuan>}
data={salesPieData}
valueFormat={value => <Yuan>{value}</Yuan>}
height={248}
lineWidth={4}
/>
</div> </div>
</Card> }
); style={{ marginTop: 24 }}
}; >
<div
style={{
minHeight: 380,
}}
>
<h4 style={{ marginTop: 8, marginBottom: 32 }}>
<FormattedMessage id="BLOCK_NAME.analysis.sales" defaultMessage="Sales" />
</h4>
<Pie
hasLegend
subTitle={<FormattedMessage id="BLOCK_NAME.analysis.sales" defaultMessage="Sales" />}
total={() => <Yuan>{salesPieData.reduce((pre, now) => now.y + pre, 0)}</Yuan>}
data={salesPieData}
valueFormat={value => <Yuan>{value}</Yuan>}
height={248}
lineWidth={4}
/>
</div>
</Card>
);
export default ProportionSales; export default ProportionSales;
import React from 'react'; import { Card, Col, DatePicker, Row, Tabs } from 'antd';
import { Row, Col, Card, Tabs, DatePicker } from 'antd';
import { FormattedMessage, formatMessage } from 'umi-plugin-react/locale'; import { FormattedMessage, formatMessage } from 'umi-plugin-react/locale';
import numeral from 'numeral';
import Charts from './Charts';
import { RangePickerValue } from 'antd/es/date-picker/interface'; import { RangePickerValue } from 'antd/es/date-picker/interface';
import { ISalesData } from '../data'; import React from 'react';
import numeral from 'numeral';
import { VisitDataType } from '../data.d';
import { Bar } from './Charts';
import styles from '../style.less'; import styles from '../style.less';
const { Bar } = Charts;
const { RangePicker } = DatePicker; const { RangePicker } = DatePicker;
const { TabPane } = Tabs; const { TabPane } = Tabs;
...@@ -30,7 +29,7 @@ const SalesCard = ({ ...@@ -30,7 +29,7 @@ const SalesCard = ({
}: { }: {
rangePickerValue: RangePickerValue; rangePickerValue: RangePickerValue;
isActive: (key: 'today' | 'week' | 'month' | 'year') => string; isActive: (key: 'today' | 'week' | 'month' | 'year') => string;
salesData: ISalesData[]; salesData: VisitDataType[];
loading: boolean; loading: boolean;
handleRangePickerChange: (dates: RangePickerValue, dateStrings: [string, string]) => void; handleRangePickerChange: (dates: RangePickerValue, dateStrings: [string, string]) => void;
selectDate: (key: 'today' | 'week' | 'month' | 'year') => void; selectDate: (key: 'today' | 'week' | 'month' | 'year') => void;
......
import React from 'react'; import { Card, Col, Icon, Row, Table, Tooltip } from 'antd';
import { Row, Col, Table, Tooltip, Card, Icon } from 'antd';
import { FormattedMessage } from 'umi-plugin-react/locale'; import { FormattedMessage } from 'umi-plugin-react/locale';
import Charts from './Charts'; import React from 'react';
import Trend from './Trend';
import NumberInfo from './NumberInfo';
import numeral from 'numeral'; import numeral from 'numeral';
import styles from '../style.less'; import { SearchDataType, VisitDataType } from '../data.d';
import { ISearchData, IVisitData2 } from '../data';
const { MiniArea } = Charts; import { MiniArea } from './Charts';
import NumberInfo from './NumberInfo';
import Trend from './Trend';
import styles from '../style.less';
const columns = [ const columns = [
{ {
...@@ -51,9 +50,9 @@ const TopSearch = ({ ...@@ -51,9 +50,9 @@ const TopSearch = ({
dropdownGroup, dropdownGroup,
}: { }: {
loading: boolean; loading: boolean;
visitData2: IVisitData2[]; visitData2: VisitDataType[];
dropdownGroup: React.ReactNode; dropdownGroup: React.ReactNode;
searchData: ISearchData[]; searchData: SearchDataType[];
}) => ( }) => (
<Card <Card
loading={loading} loading={loading}
......
import React from 'react';
import { Icon } from 'antd'; import { Icon } from 'antd';
import React from 'react';
import classNames from 'classnames'; import classNames from 'classnames';
import styles from './index.less'; import styles from './index.less';
export interface ITrendProps { export interface TrendProps {
colorful?: boolean; colorful?: boolean;
flag: 'up' | 'down'; flag: 'up' | 'down';
style?: React.CSSProperties; style?: React.CSSProperties;
...@@ -11,7 +11,7 @@ export interface ITrendProps { ...@@ -11,7 +11,7 @@ export interface ITrendProps {
className?: string; className?: string;
} }
const Trend: React.SFC<ITrendProps> = ({ const Trend: React.SFC<TrendProps> = ({
colorful = true, colorful = true,
reverseColor = false, reverseColor = false,
flag, flag,
......
export interface IVisitData { export interface VisitDataType {
x: string; x: string;
y: number; y: number;
} }
export interface IVisitData2 { export interface SearchDataType {
x: string;
y: number;
}
export interface ISalesData {
x: string;
y: number;
}
export interface ISearchData {
index: number; index: number;
keyword: string; keyword: string;
count: number; count: number;
...@@ -21,47 +11,32 @@ export interface ISearchData { ...@@ -21,47 +11,32 @@ export interface ISearchData {
status: number; status: number;
} }
export interface IOfflineData { export interface OfflineDataType {
name: string; name: string;
cvr: number; cvr: number;
} }
export interface IOfflineChartData { export interface OfflineChartData {
x: any; x: any;
y1: number; y1: number;
y2: number; y2: number;
} }
export interface ISalesTypeData { export interface RadarData {
x: string;
y: number;
}
export interface ISalesTypeDataOnline {
x: string;
y: number;
}
export interface ISalesTypeDataOffline {
x: string;
y: number;
}
export interface IRadarData {
name: string; name: string;
label: string; label: string;
value: number; value: number;
} }
export interface IAnalysisData { export interface AnalysisData {
visitData: IVisitData[]; visitData: VisitDataType[];
visitData2: IVisitData2[]; visitData2: VisitDataType[];
salesData: ISalesData[]; salesData: VisitDataType[];
searchData: ISearchData[]; searchData: SearchDataType[];
offlineData: IOfflineData[]; offlineData: OfflineDataType[];
offlineChartData: IOfflineChartData[]; offlineChartData: OfflineChartData[];
salesTypeData: ISalesTypeData[]; salesTypeData: VisitDataType[];
salesTypeDataOnline: ISalesTypeDataOnline[]; salesTypeDataOnline: VisitDataType[];
salesTypeDataOffline: ISalesTypeDataOffline[]; salesTypeDataOffline: VisitDataType[];
radarData: IRadarData[]; radarData: RadarData[];
} }
import { Col, Dropdown, Icon, Menu, Row } from 'antd';
import React, { Component, Suspense } from 'react'; import React, { Component, Suspense } from 'react';
import { connect } from 'dva';
import { Row, Col, Icon, Menu, Dropdown } from 'antd'; import { Dispatch } from 'redux';
import { GridContent } from '@ant-design/pro-layout';
import { RadioChangeEvent } from 'antd/es/radio';
import { RangePickerValue } from 'antd/es/date-picker/interface'; import { RangePickerValue } from 'antd/es/date-picker/interface';
import { connect } from 'dva';
import PageLoading from './components/PageLoading';
import { getTimeDistance } from './utils/utils'; import { getTimeDistance } from './utils/utils';
import { AnalysisData } from './data.d';
import styles from './style.less'; import styles from './style.less';
import PageLoading from './components/PageLoading';
import { Dispatch } from 'redux';
import { IAnalysisData } from './data.d';
import { RadioChangeEvent } from 'antd/es/radio';
import { GridContent } from '@ant-design/pro-layout';
const IntroduceRow = React.lazy(() => import('./components/IntroduceRow')); const IntroduceRow = React.lazy(() => import('./components/IntroduceRow'));
const SalesCard = React.lazy(() => import('./components/SalesCard')); const SalesCard = React.lazy(() => import('./components/SalesCard'));
...@@ -17,7 +18,7 @@ const ProportionSales = React.lazy(() => import('./components/ProportionSales')) ...@@ -17,7 +18,7 @@ const ProportionSales = React.lazy(() => import('./components/ProportionSales'))
const OfflineData = React.lazy(() => import('./components/OfflineData')); const OfflineData = React.lazy(() => import('./components/OfflineData'));
interface BLOCK_NAME_CAMEL_CASEProps { interface BLOCK_NAME_CAMEL_CASEProps {
BLOCK_NAME_CAMEL_CASE: IAnalysisData; BLOCK_NAME_CAMEL_CASE: AnalysisData;
dispatch: Dispatch<any>; dispatch: Dispatch<any>;
loading: boolean; loading: boolean;
} }
...@@ -51,8 +52,11 @@ class PAGE_NAME_UPPER_CAMEL_CASE extends Component< ...@@ -51,8 +52,11 @@ class PAGE_NAME_UPPER_CAMEL_CASE extends Component<
currentTabKey: '', currentTabKey: '',
rangePickerValue: getTimeDistance('year'), rangePickerValue: getTimeDistance('year'),
}; };
reqRef!: number;
timeoutId!: number; reqRef: number = 0;
timeoutId: number = 0;
componentDidMount() { componentDidMount() {
const { dispatch } = this.props; const { dispatch } = this.props;
this.reqRef = requestAnimationFrame(() => { this.reqRef = requestAnimationFrame(() => {
......
import { fakeChartData } from './service'; import { AnyAction, Reducer } from 'redux';
import { IAnalysisData } from './data';
import { Reducer } from 'redux';
import { EffectsCommandMap } from 'dva'; import { EffectsCommandMap } from 'dva';
import { AnyAction } from 'redux'; import { AnalysisData } from './data.d';
import { fakeChartData } from './service';
export type Effect = ( export type Effect = (
action: AnyAction, action: AnyAction,
effects: EffectsCommandMap & { select: <T>(func: (state: IAnalysisData) => T) => T }, effects: EffectsCommandMap & { select: <T>(func: (state: AnalysisData) => T) => T },
) => void; ) => void;
export interface ModelType { export interface ModelType {
namespace: string; namespace: string;
state: IAnalysisData; state: AnalysisData;
effects: { effects: {
fetch: Effect; fetch: Effect;
fetchSalesData: Effect; fetchSalesData: Effect;
}; };
reducers: { reducers: {
save: Reducer<IAnalysisData>; save: Reducer<AnalysisData>;
clear: Reducer<IAnalysisData>; clear: Reducer<AnalysisData>;
}; };
} }
......
...@@ -6,7 +6,8 @@ import { yuan } from '../components/Charts'; ...@@ -6,7 +6,8 @@ import { yuan } from '../components/Charts';
export default class Yuan extends React.Component<{ export default class Yuan extends React.Component<{
children: React.ReactText; children: React.ReactText;
}> { }> {
main: HTMLSpanElement | undefined | null; main: HTMLSpanElement | undefined | null = null;
componentDidMount() { componentDidMount() {
this.renderToHtml(); this.renderToHtml();
} }
...@@ -14,6 +15,7 @@ export default class Yuan extends React.Component<{ ...@@ -14,6 +15,7 @@ export default class Yuan extends React.Component<{
componentDidUpdate() { componentDidUpdate() {
this.renderToHtml(); this.renderToHtml();
} }
renderToHtml = () => { renderToHtml = () => {
const { children } = this.props; const { children } = this.props;
if (this.main) { if (this.main) {
......
import moment from 'moment';
import { RangePickerValue } from 'antd/es/date-picker/interface'; import { RangePickerValue } from 'antd/es/date-picker/interface';
import moment from 'moment';
export function fixedZero(val: number) { export function fixedZero(val: number) {
return val * 1 < 10 ? `0${val}` : val; return val * 1 < 10 ? `0${val}` : val;
......
...@@ -13,21 +13,25 @@ ...@@ -13,21 +13,25 @@
"dependencies": { "dependencies": {
"@ant-design/pro-layout": "^4.5.2", "@ant-design/pro-layout": "^4.5.2",
"@antv/data-set": "^0.10.2", "@antv/data-set": "^0.10.2",
"@types/lodash.debounce": "^4.0.6",
"antd": "^3.16.3", "antd": "^3.16.3",
"bizcharts": "^3.5.3-beta.0", "bizcharts": "^3.5.3-beta.0",
"bizcharts-plugin-slider": "^2.1.1-beta.1", "bizcharts-plugin-slider": "^2.1.1-beta.1",
"classnames": "^2.2.6",
"dva": "^2.4.0", "dva": "^2.4.0",
"lodash.debounce": "^4.0.8",
"numeral": "^2.0.6", "numeral": "^2.0.6",
"react": "^16.8.6", "react": "^16.8.6",
"react-fittext": "^1.0.0", "react-fittext": "^1.0.0",
"umi-request": "^1.0.0" "redux": "^4.0.1",
},
"devDependencies": {
"@types/numeral": "^0.0.25",
"mockjs": "^1.0.1-beta3",
"umi": "^2.6.9", "umi": "^2.6.9",
"umi-plugin-block-dev": "^1.0.0", "umi-plugin-block-dev": "^1.0.0",
"umi-plugin-react": "^1.7.2" "umi-plugin-react": "^1.7.2",
"umi-request": "^1.0.0",
"mockjs": "^1.0.1-beta3"
},
"devDependencies": {
"@types/numeral": "^0.0.25"
}, },
"license": "ISC", "license": "ISC",
"blockConfig": { "blockConfig": {
......
import React, { Component } from 'react'; import React, { Component } from 'react';
import Charts from '../Charts';
import { Statistic } from 'antd'; import { Statistic } from 'antd';
import { MiniArea } from '../Charts';
import styles from './index.less'; import styles from './index.less';
const { MiniArea } = Charts;
function fixedZero(val: number) { function fixedZero(val: number) {
return val * 1 < 10 ? `0${val}` : val; return val * 1 < 10 ? `0${val}` : val;
} }
...@@ -24,12 +23,15 @@ export default class ActiveChart extends Component { ...@@ -24,12 +23,15 @@ export default class ActiveChart extends Component {
state = { state = {
activeData: getActiveData(), activeData: getActiveData(),
}; };
timer: number | undefined;
requestRef: number | undefined; timer: number | undefined = undefined;
requestRef: number | undefined = undefined;
componentDidMount() { componentDidMount() {
this.loopData(); this.loopData();
} }
componentWillUnmount() { componentWillUnmount() {
clearTimeout(this.timer); clearTimeout(this.timer);
if (this.requestRef) { if (this.requestRef) {
......
import { Axis, Chart, Coord, Geom, Guide, Shape } from 'bizcharts';
import React from 'react'; import React from 'react';
import { Chart, Geom, Axis, Coord, Guide, Shape } from 'bizcharts';
import autoHeight from '../autoHeight'; import autoHeight from '../autoHeight';
const { Arc, Html, Line } = Guide; const { Arc, Html, Line } = Guide;
export interface IGaugeProps { export interface GaugeProps {
title: React.ReactNode; title: React.ReactNode;
color?: string; color?: string;
height?: number; height?: number;
...@@ -30,148 +31,149 @@ const defaultFormatter = (val: string): string => { ...@@ -30,148 +31,149 @@ const defaultFormatter = (val: string): string => {
} }
}; };
Shape.registerShape!('point', 'pointer', { if (Shape.registerShape) {
drawShape(cfg: any, group: any) { Shape.registerShape('point', 'pointer', {
let point = cfg.points[0]; drawShape(cfg: any, group: any) {
point = (this as any).parsePoint(point); let point = cfg.points[0];
const center = (this as any).parsePoint({ point = (this as any).parsePoint(point);
x: 0, const center = (this as any).parsePoint({
y: 0, x: 0,
}); y: 0,
group.addShape('line', { });
attrs: { group.addShape('line', {
x1: center.x, attrs: {
y1: center.y, x1: center.x,
x2: point.x, y1: center.y,
y2: point.y, x2: point.x,
stroke: cfg.color, y2: point.y,
lineWidth: 2, stroke: cfg.color,
lineCap: 'round', lineWidth: 2,
}, lineCap: 'round',
}); },
return group.addShape('circle', { });
attrs: { return group.addShape('circle', {
x: center.x, attrs: {
y: center.y, x: center.x,
r: 6, y: center.y,
stroke: cfg.color, r: 6,
lineWidth: 3, stroke: cfg.color,
fill: '#fff', lineWidth: 3,
}, fill: '#fff',
}); },
}, });
}); },
});
}
const Gauge: React.FC<GaugeProps> = props => {
const {
title,
height = 1,
percent,
forceFit = true,
formatter = defaultFormatter,
color = '#2F9CFF',
bgColor = '#F0F2F5',
} = props;
const cols = {
value: {
type: 'linear',
min: 0,
max: 10,
tickCount: 6,
nice: true,
},
};
const data = [{ value: percent / 10 }];
class Gauge extends React.Component<IGaugeProps> { const renderHtml = () => `
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 = () => `
<div style="width: 300px;text-align: center;font-size: 12px!important;"> <div style="width: 300px;text-align: center;font-size: 12px!important;">
<p style="font-size: 14px; color: rgba(0,0,0,0.43);margin: 0;">${title}</p> <p style="font-size: 14px; color: rgba(0,0,0,0.43);margin: 0;">${title}</p>
<p style="font-size: 24px;color: rgba(0,0,0,0.85);margin: 0;"> <p style="font-size: 24px;color: rgba(0,0,0,0.85);margin: 0;">
${(data[0].value * 10).toFixed(2)}% ${(data[0].value * 10).toFixed(2)}%
</p> </p>
</div>`; </div>`;
const data = [{ value: percent / 10 }]; const textStyle: {
const textStyle: { fontSize: number;
fontSize: number; fill: string;
fill: string; textAlign: 'center';
textAlign: 'center'; } = {
} = { fontSize: 12,
fontSize: 12, fill: 'rgba(0, 0, 0, 0.65)',
fill: 'rgba(0, 0, 0, 0.65)', textAlign: 'center',
textAlign: 'center', };
}; return (
return ( <Chart height={height} data={data} scale={cols} padding={[-16, 0, 16, 0]} forceFit={forceFit}>
<Chart height={height} data={data} scale={cols} padding={[-16, 0, 16, 0]} forceFit={forceFit}> <Coord type="polar" startAngle={-1.25 * Math.PI} endAngle={0.25 * Math.PI} radius={0.8} />
<Coord type="polar" startAngle={-1.25 * Math.PI} endAngle={0.25 * Math.PI} radius={0.8} /> <Axis name="1" line={undefined} />
<Axis name="1" line={undefined} /> <Axis
<Axis line={undefined}
line={undefined} tickLine={undefined}
tickLine={undefined} subTickLine={undefined}
subTickLine={undefined} name="value"
name="value" zIndex={2}
zIndex={2} label={{
label={{ offset: -12,
offset: -12, formatter,
formatter, textStyle,
textStyle: textStyle, }}
/>
<Guide>
<Line
start={[3, 0.905]}
end={[3, 0.85]}
lineStyle={{
stroke: color,
lineDash: undefined,
lineWidth: 2,
}} }}
/> />
<Guide> <Line
<Line start={[5, 0.905]}
start={[3, 0.905]} end={[5, 0.85]}
end={[3, 0.85]} lineStyle={{
lineStyle={{ stroke: color,
stroke: color, lineDash: undefined,
lineDash: undefined, lineWidth: 3,
lineWidth: 2, }}
}}
/>
<Line
start={[5, 0.905]}
end={[5, 0.85]}
lineStyle={{
stroke: color,
lineDash: undefined,
lineWidth: 3,
}}
/>
<Line
start={[7, 0.905]}
end={[7, 0.85]}
lineStyle={{
stroke: color,
lineDash: undefined,
lineWidth: 3,
}}
/>
<Arc
start={[0, 0.965]}
end={[10, 0.965]}
style={{
stroke: bgColor,
lineWidth: 10,
}}
/>
<Arc
start={[0, 0.965]}
end={[data[0].value, 0.965]}
style={{
stroke: color,
lineWidth: 10,
}}
/>
<Html position={['50%', '95%']} html={renderHtml()} />
</Guide>
<Geom
line={false}
type="point"
position="value*1"
shape="pointer"
color={color}
active={false}
/> />
</Chart> <Line
); start={[7, 0.905]}
} end={[7, 0.85]}
} lineStyle={{
stroke: color,
lineDash: undefined,
lineWidth: 3,
}}
/>
<Arc
start={[0, 0.965]}
end={[10, 0.965]}
style={{
stroke: bgColor,
lineWidth: 10,
}}
/>
<Arc
start={[0, 0.965]}
end={[data[0].value, 0.965]}
style={{
stroke: color,
lineWidth: 10,
}}
/>
<Html position={['50%', '95%']} html={renderHtml()} />
</Guide>
<Geom
line={false}
type="point"
position="value*1"
shape="pointer"
color={color}
active={false}
/>
</Chart>
);
};
export default autoHeight()(Gauge); export default autoHeight()(Gauge);
import { Axis, AxisProps, Chart, Geom, Tooltip } from 'bizcharts';
import React from 'react'; import React from 'react';
import { Chart, Axis, Tooltip, Geom } from 'bizcharts';
import autoHeight from '../autoHeight'; import autoHeight from '../autoHeight';
import styles from '../index.less'; import styles from '../index.less';
export interface IAxis { export interface MiniAreaProps {
title: any;
line: any;
gridAlign: any;
labels: any;
tickLine: any;
grid: any;
label: any;
}
export interface IMiniAreaProps {
color?: string; color?: string;
height?: number; height?: number;
borderColor?: string; borderColor?: string;
line?: boolean; line?: boolean;
animate?: boolean; animate?: boolean;
xAxis?: IAxis; xAxis?: AxisProps;
forceFit?: boolean; forceFit?: boolean;
scale?: { x?: any; y?: any }; scale?: {
yAxis?: Partial<IAxis>; x?: {
tickCount: number;
};
y?: {
tickCount: number;
};
};
yAxis?: Partial<AxisProps>;
borderWidth?: number; borderWidth?: number;
data: Array<{ data: {
x: number | string; x: number | string;
y: number; y: number;
}>; }[];
} }
class MiniArea extends React.Component<IMiniAreaProps> { const MiniArea: React.FC<MiniAreaProps> = props => {
render() { const {
const { height = 1,
height = 1, data = [],
data = [], forceFit = true,
forceFit = true, color = 'rgba(24, 144, 255, 0.2)',
color = 'rgba(24, 144, 255, 0.2)', borderColor = '#1089ff',
borderColor = '#1089ff', scale = { x: {}, y: {} },
scale = { x: {}, y: {} }, borderWidth = 2,
borderWidth = 2, line,
line, xAxis,
xAxis, yAxis,
yAxis, animate = true,
animate = true, } = props;
} = this.props;
const padding: [number, number, number, number] = [36, 5, 30, 5]; const padding: [number, number, number, number] = [36, 5, 30, 5];
const scaleProps = { const scaleProps = {
x: { x: {
type: 'cat', type: 'cat',
range: [0, 1], range: [0, 1],
...scale!.x, ...scale.x,
}, },
y: { y: {
min: 0, min: 0,
...scale!.y, ...scale.y,
}, },
}; };
const tooltip: [string, (...args: any[]) => { name?: string; value: string }] = [ const tooltip: [string, (...args: any[]) => { name?: string; value: string }] = [
'x*y', 'x*y',
(x: string, y: string) => ({ (x: string, y: string) => ({
name: x, name: x,
value: y, value: y,
}), }),
]; ];
const chartHeight = height + 54; const chartHeight = height + 54;
return ( return (
<div className={styles.miniChart} style={{ height }}> <div className={styles.miniChart} style={{ height }}>
<div className={styles.chartContent}> <div className={styles.chartContent}>
{height > 0 && ( {height > 0 && (
<Chart <Chart
animate={animate} animate={animate}
scale={scaleProps} scale={scaleProps}
height={chartHeight} height={chartHeight}
forceFit={forceFit} forceFit={forceFit}
data={data} data={data}
padding={padding} padding={padding}
> >
<Axis <Axis
key="axis-x" key="axis-x"
name="x" name="x"
label={false} label={null}
line={false} line={null}
tickLine={false} tickLine={null}
grid={false} grid={null}
{...xAxis} {...xAxis}
/> />
<Axis <Axis
key="axis-y" key="axis-y"
name="y" name="y"
label={false} label={null}
line={false} line={null}
tickLine={false} tickLine={null}
grid={false} grid={null}
{...yAxis} {...yAxis}
/> />
<Tooltip showTitle={false} crosshairs={false} /> <Tooltip showTitle={false} crosshairs={false} />
<Geom
type="area"
position="x*y"
color={color}
tooltip={tooltip}
shape="smooth"
style={{
fillOpacity: 1,
}}
/>
{line ? (
<Geom <Geom
type="area" type="line"
position="x*y" position="x*y"
color={color}
tooltip={tooltip}
shape="smooth" shape="smooth"
style={{ color={borderColor}
fillOpacity: 1, size={borderWidth}
}} tooltip={false}
/> />
{line ? ( ) : (
<Geom <span style={{ display: 'none' }} />
type="line" )}
position="x*y" </Chart>
shape="smooth" )}
color={borderColor}
size={borderWidth}
tooltip={false}
/>
) : (
<span style={{ display: 'none' }} />
)}
</Chart>
)}
</div>
</div> </div>
); </div>
} );
} };
export default autoHeight()(MiniArea); export default autoHeight()(MiniArea);
import { Chart, Coord, Geom, Tooltip } from 'bizcharts';
import React, { Component } from 'react'; import React, { Component } from 'react';
import { Chart, Tooltip, Geom, Coord } from 'bizcharts';
import { DataView } from '@antv/data-set'; import { DataView } from '@antv/data-set';
import Debounce from 'lodash.debounce';
import { Divider } from 'antd'; import { Divider } from 'antd';
import classNames from 'classnames';
import ReactFitText from 'react-fittext'; import ReactFitText from 'react-fittext';
import Debounce from 'lodash-decorators/debounce'; import classNames from 'classnames';
import Bind from 'lodash-decorators/bind';
import autoHeight from '../autoHeight'; import autoHeight from '../autoHeight';
import styles from './index.less'; import styles from './index.less';
export interface IPieProps {
export interface PieProps {
animate?: boolean; animate?: boolean;
color?: string; color?: string;
colors?: string[]; colors?: string[];
...@@ -19,10 +19,10 @@ export interface IPieProps { ...@@ -19,10 +19,10 @@ export interface IPieProps {
hasLegend?: boolean; hasLegend?: boolean;
padding?: [number, number, number, number]; padding?: [number, number, number, number];
percent?: number; percent?: number;
data?: Array<{ data?: {
x: string | string; x: string | string;
y: number; y: number;
}>; }[];
inner?: number; inner?: number;
lineWidth?: number; lineWidth?: number;
forceFit?: boolean; forceFit?: boolean;
...@@ -34,19 +34,46 @@ export interface IPieProps { ...@@ -34,19 +34,46 @@ export interface IPieProps {
valueFormat?: (value: string) => string | React.ReactNode; valueFormat?: (value: string) => string | React.ReactNode;
subTitle?: React.ReactNode; subTitle?: React.ReactNode;
} }
interface IPieState { interface PieState {
legendData: Array<{ checked: boolean; x: string; color: string; percent: number; y: string }>; legendData: { checked: boolean; x: string; color: string; percent: number; y: string }[];
legendBlock: boolean; legendBlock: boolean;
} }
class Pie extends Component<IPieProps, IPieState> { class Pie extends Component<PieProps, PieState> {
state: IPieState = { state: PieState = {
legendData: [], legendData: [],
legendBlock: false, legendBlock: false,
}; };
requestRef: number | undefined; chart: G2.Chart | undefined = undefined;
root!: HTMLDivElement;
chart: G2.Chart | undefined; root: HTMLDivElement | undefined = undefined;
requestRef: number | undefined = 0;
// for window resize auto responsive legend
resize = Debounce(() => {
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,
});
}
}, 300);
componentDidMount() { componentDidMount() {
window.addEventListener( window.addEventListener(
...@@ -58,7 +85,7 @@ class Pie extends Component<IPieProps, IPieState> { ...@@ -58,7 +85,7 @@ class Pie extends Component<IPieProps, IPieState> {
); );
} }
componentDidUpdate(preProps: IPieProps) { componentDidUpdate(preProps: PieProps) {
const { data } = this.props; const { data } = this.props;
if (data !== preProps.data) { if (data !== preProps.data) {
// because of charts data create when rendered // because of charts data create when rendered
...@@ -90,7 +117,8 @@ class Pie extends Component<IPieProps, IPieState> { ...@@ -90,7 +117,8 @@ class Pie extends Component<IPieProps, IPieState> {
if (!this.chart) return; if (!this.chart) return;
const geom = this.chart.getAllGeoms()[0]; // 获取所有的图形 const geom = this.chart.getAllGeoms()[0]; // 获取所有的图形
if (!geom) return; if (!geom) return;
const items = geom.get('dataArray') || []; // 获取图形对应的 // g2 的类型有问题
const items = (geom as any).get('dataArray') || []; // 获取图形对应的
const legendData = items.map((item: { color: any; _origin: any }[]) => { const legendData = items.map((item: { color: any; _origin: any }[]) => {
/* eslint no-underscore-dangle:0 */ /* eslint no-underscore-dangle:0 */
...@@ -104,11 +132,12 @@ class Pie extends Component<IPieProps, IPieState> { ...@@ -104,11 +132,12 @@ class Pie extends Component<IPieProps, IPieState> {
legendData, legendData,
}); });
}; };
handleRoot = (n: HTMLDivElement) => { handleRoot = (n: HTMLDivElement) => {
this.root = n; this.root = n;
}; };
handleLegendClick = (item: any, i: string | number) => { handleLegendClick = (item: { checked: boolean }, i: string | number) => {
const newItem = item; const newItem = item;
newItem.checked = !newItem.checked; newItem.checked = !newItem.checked;
...@@ -118,7 +147,7 @@ class Pie extends Component<IPieProps, IPieState> { ...@@ -118,7 +147,7 @@ class Pie extends Component<IPieProps, IPieState> {
const filteredLegendData = legendData.filter(l => l.checked).map(l => l.x); const filteredLegendData = legendData.filter(l => l.checked).map(l => l.x);
if (this.chart) { if (this.chart) {
this.chart.filter('x', val => filteredLegendData.indexOf(val + '') > -1); this.chart.filter('x', val => filteredLegendData.indexOf(`${val}`) > -1);
} }
this.setState({ this.setState({
...@@ -126,33 +155,6 @@ class Pie extends Component<IPieProps, IPieState> { ...@@ -126,33 +155,6 @@ class Pie extends Component<IPieProps, IPieState> {
}); });
}; };
// 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() { render() {
const { const {
valueFormat, valueFormat,
...@@ -216,11 +218,11 @@ class Pie extends Component<IPieProps, IPieState> { ...@@ -216,11 +218,11 @@ class Pie extends Component<IPieProps, IPieState> {
data = [ data = [
{ {
x: '占比', x: '占比',
y: parseFloat(percent + ''), y: parseFloat(`${percent}`),
}, },
{ {
x: '反比', x: '反比',
y: 100 - parseFloat(percent + ''), y: 100 - parseFloat(`${percent}`),
}, },
]; ];
} }
......
import { Chart, Coord, Geom, Shape, Tooltip } from 'bizcharts';
import React, { Component } from 'react'; import React, { Component } from 'react';
import { Chart, Geom, Coord, Shape, Tooltip } from 'bizcharts';
import DataSet from '@antv/data-set'; import DataSet from '@antv/data-set';
import Debounce from 'lodash-decorators/debounce'; import Debounce from 'lodash.debounce';
import Bind from 'lodash-decorators/bind';
import classNames from 'classnames'; import classNames from 'classnames';
import autoHeight from '../autoHeight'; import autoHeight from '../autoHeight';
import styles from './index.less'; import styles from './index.less';
...@@ -12,33 +12,36 @@ import styles from './index.less'; ...@@ -12,33 +12,36 @@ import styles from './index.less';
const imgUrl = 'https://gw.alipayobjects.com/zos/rmsportal/gWyeGLCdFFRavBGIDzWk.png'; const imgUrl = 'https://gw.alipayobjects.com/zos/rmsportal/gWyeGLCdFFRavBGIDzWk.png';
export interface ITagCloudProps { export interface TagCloudProps {
data: Array<{ data: {
name: string; name: string;
value: string; value: string;
}>; }[];
height?: number; height?: number;
className?: string; className?: string;
style?: React.CSSProperties; style?: React.CSSProperties;
} }
interface ITagCloudState { interface TagCloudState {
dv: any; dv: any;
height?: number; height?: number;
width: number; width: number;
} }
class TagCloud extends Component<ITagCloudProps, ITagCloudState> { class TagCloud extends Component<TagCloudProps, TagCloudState> {
state = { state = {
dv: null, dv: null,
height: 0, height: 0,
width: 0, width: 0,
}; };
isUnmount!: boolean;
requestRef!: number;
root: HTMLDivElement | undefined; requestRef: number = 0;
imageMask: HTMLImageElement | undefined;
isUnmount: boolean = false;
root: HTMLDivElement | undefined = undefined;
imageMask: HTMLImageElement | undefined = undefined;
componentDidMount() { componentDidMount() {
requestAnimationFrame(() => { requestAnimationFrame(() => {
...@@ -48,22 +51,25 @@ class TagCloud extends Component<ITagCloudProps, ITagCloudState> { ...@@ -48,22 +51,25 @@ class TagCloud extends Component<ITagCloudProps, ITagCloudState> {
window.addEventListener('resize', this.resize, { passive: true }); window.addEventListener('resize', this.resize, { passive: true });
} }
componentDidUpdate(preProps?: ITagCloudProps) { componentDidUpdate(preProps?: TagCloudProps) {
const { data } = this.props; const { data } = this.props;
if (preProps && JSON.stringify(preProps.data) !== JSON.stringify(data)) { if (preProps && JSON.stringify(preProps.data) !== JSON.stringify(data)) {
this.renderChart(this.props); this.renderChart(this.props);
} }
} }
componentWillUnmount() { componentWillUnmount() {
this.isUnmount = true; this.isUnmount = true;
window.cancelAnimationFrame(this.requestRef); window.cancelAnimationFrame(this.requestRef);
window.removeEventListener('resize', this.resize); window.removeEventListener('resize', this.resize);
} }
resize = () => { resize = () => {
this.requestRef = requestAnimationFrame(() => { this.requestRef = requestAnimationFrame(() => {
this.renderChart(this.props); this.renderChart(this.props);
}); });
}; };
saveRootRef = (node: HTMLDivElement) => { saveRootRef = (node: HTMLDivElement) => {
this.root = node; this.root = node;
}; };
...@@ -77,7 +83,8 @@ class TagCloud extends Component<ITagCloudProps, ITagCloudState> { ...@@ -77,7 +83,8 @@ class TagCloud extends Component<ITagCloudProps, ITagCloudState> {
origin?: any; origin?: any;
color?: any; color?: any;
}) { }) {
return Object.assign({}, cfg.style, { return {
...cfg.style,
fillOpacity: cfg.opacity, fillOpacity: cfg.opacity,
fontSize: cfg.origin._origin.size, fontSize: cfg.origin._origin.size,
rotate: cfg.origin._origin.rotate, rotate: cfg.origin._origin.rotate,
...@@ -86,7 +93,7 @@ class TagCloud extends Component<ITagCloudProps, ITagCloudState> { ...@@ -86,7 +93,7 @@ class TagCloud extends Component<ITagCloudProps, ITagCloudState> {
fontFamily: cfg.origin._origin.font, fontFamily: cfg.origin._origin.font,
fill: cfg.color, fill: cfg.color,
textBaseline: 'Alphabetic', textBaseline: 'Alphabetic',
}); };
} }
(Shape as any).registerShape('point', 'cloud', { (Shape as any).registerShape('point', 'cloud', {
...@@ -96,18 +103,17 @@ class TagCloud extends Component<ITagCloudProps, ITagCloudState> { ...@@ -96,18 +103,17 @@ class TagCloud extends Component<ITagCloudProps, ITagCloudState> {
) { ) {
const attrs = getTextAttrs(cfg); const attrs = getTextAttrs(cfg);
return container.addShape('text', { return container.addShape('text', {
attrs: Object.assign(attrs, { attrs: {
...attrs,
x: cfg.x, x: cfg.x,
y: cfg.y, y: cfg.y,
}), },
}); });
}, },
}); });
}; };
@Bind() renderChart = Debounce((nextProps: TagCloudProps) => {
@Debounce(500)
renderChart(nextProps: ITagCloudProps) {
// const colors = ['#1890FF', '#41D9C7', '#2FC25B', '#FACC14', '#9AE65C']; // const colors = ['#1890FF', '#41D9C7', '#2FC25B', '#FACC14', '#9AE65C'];
const { data, height } = nextProps || this.props; const { data, height } = nextProps || this.props;
if (data.length < 1 || !this.root) { if (data.length < 1 || !this.root) {
...@@ -133,8 +139,8 @@ class TagCloud extends Component<ITagCloudProps, ITagCloudState> { ...@@ -133,8 +139,8 @@ class TagCloud extends Component<ITagCloudProps, ITagCloudState> {
return 0; return 0;
}, },
fontSize(d: { value: number }) { fontSize(d: { value: number }) {
// eslint-disable-next-line const size = ((d.value - min) / (max - min)) ** 2;
return Math.pow((d.value - min) / (max - min), 2) * (17.5 - 5) + 5; return size * (17.5 - 5) + 5;
}, },
}); });
...@@ -158,7 +164,7 @@ class TagCloud extends Component<ITagCloudProps, ITagCloudState> { ...@@ -158,7 +164,7 @@ class TagCloud extends Component<ITagCloudProps, ITagCloudState> {
} else { } else {
onload(); onload();
} }
} }, 200);
render() { render() {
const { className, height } = this.props; const { className, height } = this.props;
......
import React, { Component } from 'react'; import React, { Component } from 'react';
import autoHeight from '../autoHeight'; import autoHeight from '../autoHeight';
import styles from './index.less'; import styles from './index.less';
...@@ -6,7 +7,7 @@ import styles from './index.less'; ...@@ -6,7 +7,7 @@ import styles from './index.less';
/* eslint no-mixed-operators: 0 */ /* eslint no-mixed-operators: 0 */
// riddle: https://riddle.alibaba-inc.com/riddles/2d9a4b90 // riddle: https://riddle.alibaba-inc.com/riddles/2d9a4b90
export interface IWaterWaveProps { export interface WaterWaveProps {
title: React.ReactNode; title: React.ReactNode;
color?: string; color?: string;
height?: number; height?: number;
...@@ -14,13 +15,16 @@ export interface IWaterWaveProps { ...@@ -14,13 +15,16 @@ export interface IWaterWaveProps {
style?: React.CSSProperties; style?: React.CSSProperties;
} }
class WaterWave extends Component<IWaterWaveProps> { class WaterWave extends Component<WaterWaveProps> {
state = { state = {
radio: 1, radio: 1,
}; };
timer: number = 0; timer: number = 0;
root: HTMLDivElement | undefined | null;
node: HTMLCanvasElement | undefined | null; root: HTMLDivElement | undefined | null = null;
node: HTMLCanvasElement | undefined | null = null;
componentDidMount() { componentDidMount() {
this.renderChart(); this.renderChart();
...@@ -34,7 +38,7 @@ class WaterWave extends Component<IWaterWaveProps> { ...@@ -34,7 +38,7 @@ class WaterWave extends Component<IWaterWaveProps> {
); );
} }
componentDidUpdate(props: IWaterWaveProps) { componentDidUpdate(props: WaterWaveProps) {
const { percent } = this.props; const { percent } = this.props;
if (props.percent !== percent) { if (props.percent !== percent) {
// 不加这个会造成绘制缓慢 // 不加这个会造成绘制缓慢
...@@ -59,6 +63,7 @@ class WaterWave extends Component<IWaterWaveProps> { ...@@ -59,6 +63,7 @@ class WaterWave extends Component<IWaterWaveProps> {
}); });
} }
}; };
renderChart(type?: string) { renderChart(type?: string) {
const { percent, color = '#1890FF' } = this.props; const { percent, color = '#1890FF' } = this.props;
const data = percent / 100; const data = percent / 100;
...@@ -201,6 +206,7 @@ class WaterWave extends Component<IWaterWaveProps> { ...@@ -201,6 +206,7 @@ class WaterWave extends Component<IWaterWaveProps> {
} }
render(); render();
} }
render() { render() {
const { radio } = this.state; const { radio } = this.state;
const { percent, title, height = 1 } = this.props; const { percent, title, height = 1 } = this.props;
......
...@@ -6,11 +6,12 @@ export type IReactComponent<P = any> = ...@@ -6,11 +6,12 @@ export type IReactComponent<P = any> =
| React.ClassicComponentClass<P>; | React.ClassicComponentClass<P>;
function computeHeight(node: HTMLDivElement) { function computeHeight(node: HTMLDivElement) {
node.style.height = '100%'; const { style } = node;
const totalHeight = parseInt(getComputedStyle(node).height + '', 10); style.height = '100%';
const totalHeight = parseInt(`${getComputedStyle(node).height}`, 10);
const padding = const padding =
parseInt(getComputedStyle(node).paddingTop + '', 10) + parseInt(`${getComputedStyle(node).paddingTop}`, 10) +
parseInt(getComputedStyle(node).paddingBottom + '', 10); parseInt(`${getComputedStyle(node).paddingBottom}`, 10);
return totalHeight - padding; return totalHeight - padding;
} }
...@@ -30,22 +31,24 @@ function getAutoHeight(n: HTMLDivElement) { ...@@ -30,22 +31,24 @@ function getAutoHeight(n: HTMLDivElement) {
return height; return height;
} }
interface IAutoHeightProps { interface AutoHeightProps {
height?: number; height?: number;
} }
function autoHeight() { function autoHeight() {
return function<P extends IAutoHeightProps>( return <P extends AutoHeightProps>(
WrappedComponent: React.ComponentClass<P> | React.SFC<P>, WrappedComponent: React.ComponentClass<P> | React.SFC<P>,
): React.ComponentClass<P> { ): React.ComponentClass<P> => {
class AutoHeightComponent extends React.Component<P & IAutoHeightProps> { class AutoHeightComponent extends React.Component<P & AutoHeightProps> {
state = { state = {
computedHeight: 0, computedHeight: 0,
}; };
root!: HTMLDivElement;
root: HTMLDivElement | null = null;
componentDidMount() { componentDidMount() {
const { height } = this.props; const { height } = this.props;
if (!height) { if (!height && this.root) {
let h = getAutoHeight(this.root); let h = getAutoHeight(this.root);
this.setState({ computedHeight: h }); this.setState({ computedHeight: h });
if (h < 1) { if (h < 1) {
...@@ -54,9 +57,11 @@ function autoHeight() { ...@@ -54,9 +57,11 @@ function autoHeight() {
} }
} }
} }
handleRoot = (node: HTMLDivElement) => { handleRoot = (node: HTMLDivElement) => {
this.root = node; this.root = node;
}; };
render() { render() {
const { height } = this.props; const { height } = this.props;
const { computedHeight } = this.state; const { computedHeight } = this.state;
......
import Pie from './Pie';
import Gauge from './Gauge'; import Gauge from './Gauge';
import WaterWave from './WaterWave';
import TagCloud from './TagCloud';
import MiniArea from './MiniArea'; import MiniArea from './MiniArea';
import Pie from './Pie';
import TagCloud from './TagCloud';
import WaterWave from './WaterWave';
const Charts = { const Charts = {
Pie, Pie,
WaterWave, WaterWave,
......
export interface ITag { export interface TagType {
name: string; name: string;
value: string; value: string;
type: string; type: string;
......
import { Card, Col, Row, Statistic, Tooltip } from 'antd';
import { FormattedMessage, formatMessage } from 'umi-plugin-react/locale';
import React, { Component } from 'react'; import React, { Component } from 'react';
import { Dispatch } from 'redux';
import { GridContent } from '@ant-design/pro-layout';
import { connect } from 'dva'; import { connect } from 'dva';
import { formatMessage, FormattedMessage } from 'umi-plugin-react/locale';
import { Row, Col, Card, Statistic, Tooltip } from 'antd';
import numeral from 'numeral'; import numeral from 'numeral';
import { Dispatch } from 'redux'; import { StateType } from './model';
import { IStateType } from './model'; import { Pie, WaterWave, Gauge, TagCloud } from './components/Charts';
import ActiveChart from './components/ActiveChart'; import ActiveChart from './components/ActiveChart';
import styles from './style.less'; import styles from './style.less';
import Charts from './components/Charts';
import { GridContent } from '@ant-design/pro-layout';
const { Countdown } = Statistic; const { Countdown } = Statistic;
const { Pie, WaterWave, Gauge, TagCloud } = Charts;
const targetTime = new Date().getTime() + 3900000; const targetTime = new Date().getTime() + 3900000;
interface PAGE_NAME_UPPER_CAMEL_CASEProps { interface PAGE_NAME_UPPER_CAMEL_CASEProps {
BLOCK_NAME_CAMEL_CASE: IStateType; BLOCK_NAME_CAMEL_CASE: StateType;
dispatch: Dispatch<any>; dispatch: Dispatch<any>;
loading: boolean; loading: boolean;
} }
...@@ -27,7 +26,7 @@ interface PAGE_NAME_UPPER_CAMEL_CASEProps { ...@@ -27,7 +26,7 @@ interface PAGE_NAME_UPPER_CAMEL_CASEProps {
BLOCK_NAME_CAMEL_CASE, BLOCK_NAME_CAMEL_CASE,
loading, loading,
}: { }: {
BLOCK_NAME_CAMEL_CASE: IStateType; BLOCK_NAME_CAMEL_CASE: StateType;
loading: { loading: {
models: { [key: string]: boolean }; models: { [key: string]: boolean };
}; };
......
import { queryTags } from './service'; import { AnyAction, Reducer } from 'redux';
import { ITag } from './data';
import { Reducer } from 'redux';
import { EffectsCommandMap } from 'dva'; import { EffectsCommandMap } from 'dva';
import { AnyAction } from 'redux'; import { TagType } from './data.d';
import { queryTags } from './service';
export interface IStateType { export interface StateType {
tags: ITag[]; tags: TagType[];
} }
export type Effect = ( export type Effect = (
action: AnyAction, action: AnyAction,
effects: EffectsCommandMap & { select: <T>(func: (state: IStateType) => T) => T }, effects: EffectsCommandMap & { select: <T>(func: (state: StateType) => T) => T },
) => void; ) => void;
export interface ModelType { export interface ModelType {
namespace: string; namespace: string;
state: IStateType; state: StateType;
effects: { effects: {
fetchTags: Effect; fetchTags: Effect;
}; };
reducers: { reducers: {
saveTags: Reducer<IStateType>; saveTags: Reducer<StateType>;
}; };
} }
......
...@@ -11,13 +11,15 @@ ...@@ -11,13 +11,15 @@
"url": "https://github.com/umijs/umi-blocks/ant-design-pro/workplace" "url": "https://github.com/umijs/umi-blocks/ant-design-pro/workplace"
}, },
"dependencies": { "dependencies": {
"@ant-design/pro-layout": "^4.5.5",
"antd": "^3.16.3", "antd": "^3.16.3",
"bizcharts": "^3.5.3-beta.0",
"dva": "^2.4.0", "dva": "^2.4.0",
"moment": "^2.22.2", "moment": "^2.22.2",
"prop-types": "^15.5.10", "prop-types": "^15.5.10",
"react": "^16.6.3", "react": "^16.6.3",
"umi-request": "^1.0.0", "redux": "^4.0.1",
"bizcharts": "^3.5.3-beta.0" "umi-request": "^1.0.0"
}, },
"devDependencies": { "devDependencies": {
"umi": "^2.6.9", "umi": "^2.6.9",
......
import React, { PureComponent, createElement } from 'react'; import React, { PureComponent, createElement } from 'react';
import { Button } from 'antd'; import { Button } from 'antd';
import styles from './index.less'; import styles from './index.less';
......
...@@ -6,15 +6,16 @@ export type IReactComponent<P = any> = ...@@ -6,15 +6,16 @@ export type IReactComponent<P = any> =
| React.ClassicComponentClass<P>; | React.ClassicComponentClass<P>;
function computeHeight(node: HTMLDivElement) { function computeHeight(node: HTMLDivElement) {
node.style.height = '100%'; const { style } = node;
const totalHeight = parseInt(getComputedStyle(node).height + '', 10); style.height = '100%';
const totalHeight = parseInt(`${getComputedStyle(node).height}`, 10);
const padding = const padding =
parseInt(getComputedStyle(node).paddingTop + '', 10) + parseInt(`${getComputedStyle(node).paddingTop}`, 10) +
parseInt(getComputedStyle(node).paddingBottom + '', 10); parseInt(`${getComputedStyle(node).paddingBottom}`, 10);
return totalHeight - padding; return totalHeight - padding;
} }
function getAutoHeight(n: HTMLDivElement) { function getAutoHeight(n: HTMLDivElement | undefined) {
if (!n) { if (!n) {
return 0; return 0;
} }
...@@ -30,24 +31,25 @@ function getAutoHeight(n: HTMLDivElement) { ...@@ -30,24 +31,25 @@ function getAutoHeight(n: HTMLDivElement) {
return height; return height;
} }
interface IAutoHeightProps { interface AutoHeightProps {
height?: number; height?: number;
} }
function autoHeight() { function autoHeight() {
return function<P extends IAutoHeightProps>( return <P extends AutoHeightProps>(
WrappedComponent: React.ComponentClass<P> | React.SFC<P>, WrappedComponent: React.ComponentClass<P> | React.SFC<P>,
): React.ComponentClass<P> { ): React.ComponentClass<P> => {
class AutoHeightComponent extends React.Component<P & IAutoHeightProps> { class AutoHeightComponent extends React.Component<P & AutoHeightProps> {
state = { state = {
computedHeight: 0, computedHeight: 0,
}; };
root!: HTMLDivElement;
root: HTMLDivElement | undefined = undefined;
componentDidMount() { componentDidMount() {
const { height } = this.props; const { height } = this.props;
if (!height) { if (!height) {
let h = getAutoHeight(this.root); let h = getAutoHeight(this.root);
// eslint-disable-next-line
this.setState({ computedHeight: h }); this.setState({ computedHeight: h });
if (h < 1) { if (h < 1) {
h = getAutoHeight(this.root); h = getAutoHeight(this.root);
...@@ -55,9 +57,11 @@ function autoHeight() { ...@@ -55,9 +57,11 @@ function autoHeight() {
} }
} }
} }
handleRoot = (node: HTMLDivElement) => { handleRoot = (node: HTMLDivElement) => {
this.root = node; this.root = node;
}; };
render() { render() {
const { height } = this.props; const { height } = this.props;
const { computedHeight } = this.state; const { computedHeight } = this.state;
......
import { Axis, Chart, Coord, Geom, Tooltip } from 'bizcharts';
import { Col, Row } from 'antd';
import React, { Component } from 'react'; import React, { Component } from 'react';
import { Chart, Tooltip, Geom, Coord, Axis } from 'bizcharts';
import { Row, Col } from 'antd';
import autoHeight from './autoHeight'; import autoHeight from './autoHeight';
import styles from './index.less'; import styles from './index.less';
export interface IRadarProps { export interface RadarProps {
title?: React.ReactNode; title?: React.ReactNode;
height?: number; height?: number;
padding?: [number, number, number, number]; padding?: [number, number, number, number];
hasLegend?: boolean; hasLegend?: boolean;
data: Array<{ data: {
name: string; name: string;
label: string; label: string;
value: string | number; value: string | number;
}>; }[];
colors?: string[]; colors?: string[];
animate?: boolean; animate?: boolean;
forceFit?: boolean; forceFit?: boolean;
tickCount?: number; tickCount?: number;
style?: React.CSSProperties; style?: React.CSSProperties;
} }
interface IRadarState { interface RadarState {
legendData: Array<{ legendData: {
checked: boolean; checked: boolean;
name: string; name: string;
color: string; color: string;
percent: number; percent: number;
value: string; value: string;
}>; }[];
} }
/* eslint react/no-danger:0 */ /* eslint react/no-danger:0 */
class Radar extends Component<IRadarProps, IRadarState> { class Radar extends Component<RadarProps, RadarState> {
state: IRadarState = { state: RadarState = {
legendData: [], legendData: [],
}; };
chart: G2.Chart | undefined;
node: HTMLDivElement | undefined; chart: G2.Chart | undefined = undefined;
node: HTMLDivElement | undefined = undefined;
componentDidMount() { componentDidMount() {
this.getLegendData(); this.getLegendData();
} }
componentDidUpdate(preProps: IRadarProps) { componentDidUpdate(preProps: RadarProps) {
const { data } = this.props; const { data } = this.props;
if (data !== preProps.data) { if (data !== preProps.data) {
this.getLegendData(); this.getLegendData();
...@@ -57,10 +60,10 @@ class Radar extends Component<IRadarProps, IRadarState> { ...@@ -57,10 +60,10 @@ class Radar extends Component<IRadarProps, IRadarState> {
if (!this.chart) return; if (!this.chart) return;
const geom = this.chart.getAllGeoms()[0]; // 获取所有的图形 const geom = this.chart.getAllGeoms()[0]; // 获取所有的图形
if (!geom) return; if (!geom) return;
const items = geom.get('dataArray') || []; // 获取图形对应的 const items = (geom as any).get('dataArray') || []; // 获取图形对应的
const legendData = items.map((item: { color: any; _origin: any }[]) => { const legendData = items.map((item: { color: any; _origin: any }[]) => {
// eslint-disable-next-line // eslint-disable-next-line no-underscore-dangle
const origins = item.map(t => t._origin); const origins = item.map(t => t._origin);
const result = { const result = {
name: origins[0].name, name: origins[0].name,
...@@ -97,7 +100,7 @@ class Radar extends Component<IRadarProps, IRadarState> { ...@@ -97,7 +100,7 @@ class Radar extends Component<IRadarProps, IRadarState> {
const filteredLegendData = legendData.filter(l => l.checked).map(l => l.name); const filteredLegendData = legendData.filter(l => l.checked).map(l => l.name);
if (this.chart) { if (this.chart) {
this.chart.filter('name', val => filteredLegendData.indexOf(val + '') > -1); this.chart.filter('name', val => filteredLegendData.indexOf(`${val}`) > -1);
this.chart.repaint(); this.chart.repaint();
} }
......
export interface ITag { export interface TagType {
key: string; key: string;
label: string; label: string;
} }
export interface IProvince { export interface ProvinceType {
label: string; label: string;
key: string; key: string;
} }
export interface ICity { export interface CityType {
label: string; label: string;
key: string; key: string;
} }
export interface IGeographic { export interface GeographicType {
province: IProvince; province: ProvinceType;
city: ICity; city: CityType;
} }
export interface INotice { export interface NoticeType {
id: string; id: string;
title: string; title: string;
logo: string; logo: string;
...@@ -29,30 +29,30 @@ export interface INotice { ...@@ -29,30 +29,30 @@ export interface INotice {
memberLink: string; memberLink: string;
} }
export interface ICurrentUser { export interface CurrentUser {
name: string; name: string;
avatar: string; avatar: string;
userid: string; userid: string;
notice: INotice[]; notice: NoticeType[];
email: string; email: string;
signature: string; signature: string;
title: string; title: string;
group: string; group: string;
tags: ITag[]; tags: TagType[];
notifyCount: number; notifyCount: number;
unreadCount: number; unreadCount: number;
country: string; country: string;
geographic: IGeographic; geographic: GeographicType;
address: string; address: string;
phone: string; phone: string;
} }
export interface IMember { export interface Member {
avatar: string; avatar: string;
name: string; name: string;
id: string; id: string;
} }
export interface IActivities { export interface ActivitiesType {
id: string; id: string;
updatedAt: string; updatedAt: string;
user: { user: {
...@@ -71,7 +71,7 @@ export interface IActivities { ...@@ -71,7 +71,7 @@ export interface IActivities {
template: string; template: string;
} }
export interface IRadarData { export interface RadarDataType {
label: string; label: string;
name: string; name: string;
value: number; value: number;
......
import { Avatar, Card, Col, List, Row } from 'antd';
import React, { PureComponent } from 'react'; import React, { PureComponent } from 'react';
import moment from 'moment';
import { connect } from 'dva';
import Link from 'umi/link';
import { Row, Col, Card, List, Avatar } from 'antd';
import { Dispatch } from 'redux';
import EditableLinkGroup from './components/EditableLinkGroup'; import { Dispatch } from 'redux';
import Link from 'umi/link';
import { PageHeaderWrapper } from '@ant-design/pro-layout';
import { connect } from 'dva';
import moment from 'moment';
import Radar from './components/Radar'; import Radar from './components/Radar';
import { ModalState } from './model'; import { ModalState } from './model';
import { ICurrentUser, IActivities, IRadarData, INotice } from './data'; import EditableLinkGroup from './components/EditableLinkGroup';
import { PageHeaderWrapper } from '@ant-design/pro-layout';
import styles from './style.less'; import styles from './style.less';
import { ActivitiesType, CurrentUser, NoticeType, RadarDataType } from './data.d';
const links = [ const links = [
{ {
...@@ -41,10 +40,10 @@ const links = [ ...@@ -41,10 +40,10 @@ const links = [
]; ];
interface BLOCK_NAME_CAMEL_CASEProps { interface BLOCK_NAME_CAMEL_CASEProps {
currentUser: ICurrentUser; currentUser: CurrentUser;
projectNotice: INotice[]; projectNotice: NoticeType[];
activities: IActivities[]; activities: ActivitiesType[];
radarData: IRadarData[]; radarData: RadarDataType[];
dispatch: Dispatch<any>; dispatch: Dispatch<any>;
currentUserLoading: boolean; currentUserLoading: boolean;
projectLoading: boolean; projectLoading: boolean;
...@@ -83,7 +82,7 @@ class PAGE_NAME_UPPER_CAMEL_CASE extends PureComponent<BLOCK_NAME_CAMEL_CASEProp ...@@ -83,7 +82,7 @@ class PAGE_NAME_UPPER_CAMEL_CASE extends PureComponent<BLOCK_NAME_CAMEL_CASEProp
}); });
} }
renderActivities(item: IActivities) { renderActivities = (item: ActivitiesType) => {
const events = item.template.split(/@\{([^{}]*)\}/gi).map(key => { const events = item.template.split(/@\{([^{}]*)\}/gi).map(key => {
if (item[key]) { if (item[key]) {
return ( return (
...@@ -113,7 +112,7 @@ class PAGE_NAME_UPPER_CAMEL_CASE extends PureComponent<BLOCK_NAME_CAMEL_CASEProp ...@@ -113,7 +112,7 @@ class PAGE_NAME_UPPER_CAMEL_CASE extends PureComponent<BLOCK_NAME_CAMEL_CASEProp
/> />
</List.Item> </List.Item>
); );
} };
render() { render() {
const { const {
...@@ -207,11 +206,9 @@ class PAGE_NAME_UPPER_CAMEL_CASE extends PureComponent<BLOCK_NAME_CAMEL_CASEProp ...@@ -207,11 +206,9 @@ class PAGE_NAME_UPPER_CAMEL_CASE extends PureComponent<BLOCK_NAME_CAMEL_CASEProp
title="动态" title="动态"
loading={activitiesLoading} loading={activitiesLoading}
> >
<List<IActivities> <List<ActivitiesType>
loading={activitiesLoading} loading={activitiesLoading}
renderItem={item => { renderItem={item => this.renderActivities(item)}
return this.renderActivities(item);
}}
dataSource={activities} dataSource={activities}
className={styles.activitiesList} className={styles.activitiesList}
size="large" size="large"
......
import { AnyAction, Reducer } from 'redux';
import { EffectsCommandMap } from 'dva'; import { EffectsCommandMap } from 'dva';
import { Reducer, AnyAction } from 'redux'; import { ActivitiesType, CurrentUser, NoticeType, RadarDataType } from './data.d';
import { queryCurrent, queryProjectNotice, queryActivities, fakeChartData } from './service'; import { fakeChartData, queryActivities, queryCurrent, queryProjectNotice } from './service';
import { CurrentUser, Notice, Activeties, RadarData } from './data';
export interface ModalState { export interface ModalState {
currentUser: Partial<CurrentUser>; currentUser: Partial<CurrentUser>;
projectNotice: Notice[]; projectNotice: NoticeType[];
activities: Activeties[]; activities: ActivitiesType[];
radarData: RadarData[]; radarData: RadarDataType[];
} }
export type Effect = ( export type Effect = (
......
...@@ -7,6 +7,7 @@ flow ...@@ -7,6 +7,7 @@ flow
```sh ```sh
umi block add ant-design-pro/flow umi block add ant-design-pro/flow
``` ```
## SNAPSHOT ## SNAPSHOT
![SNAPSHOT](./snapshot.png) ![SNAPSHOT](./snapshot.png)
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
"dev": "umi dev" "dev": "umi dev"
}, },
"dependencies": { "dependencies": {
"@ant-design/pro-layout": "^4.5.5",
"@antv/data-set": "^0.10.2", "@antv/data-set": "^0.10.2",
"antd": "^3.16.3", "antd": "^3.16.3",
"bizcharts": "^3.5.3-beta.0", "bizcharts": "^3.5.3-beta.0",
...@@ -22,13 +23,13 @@ ...@@ -22,13 +23,13 @@
"numeral": "^2.0.6", "numeral": "^2.0.6",
"react": "^16.6.3", "react": "^16.6.3",
"react-fittext": "^1.0.0", "react-fittext": "^1.0.0",
"umi": "^2.6.9",
"umi-plugin-react": "^1.7.2",
"umi-request": "^1.0.0" "umi-request": "^1.0.0"
}, },
"devDependencies": { "devDependencies": {
"umi": "^2.6.9", "@types/numeral": "^0.0.25",
"umi-plugin-block-dev": "^1.1.0", "umi-plugin-block-dev": "^1.1.0"
"umi-plugin-react": "^1.7.2",
"@types/numeral": "^0.0.25"
}, },
"blockConfig": { "blockConfig": {
"specVersion": "0.1" "specVersion": "0.1"
......
import { CanvasMenu, ContextMenu, EdgeMenu, GroupMenu, MultiMenu, NodeMenu } from 'gg-editor';
import React from 'react'; import React from 'react';
import { NodeMenu, EdgeMenu, GroupMenu, MultiMenu, CanvasMenu, ContextMenu } from 'gg-editor';
import MenuItem from './MenuItem'; import MenuItem from './MenuItem';
import styles from './index.less'; import styles from './index.less';
const FlowContextMenu = () => { const FlowContextMenu = () => (
return ( <ContextMenu className={styles.contextMenu}>
<ContextMenu className={styles.contextMenu}> <NodeMenu>
<NodeMenu> <MenuItem command="copy" />
<MenuItem command="copy" /> <MenuItem command="delete" />
<MenuItem command="delete" /> </NodeMenu>
</NodeMenu> <EdgeMenu>
<EdgeMenu> <MenuItem command="delete" />
<MenuItem command="delete" /> </EdgeMenu>
</EdgeMenu> <GroupMenu>
<GroupMenu> <MenuItem command="copy" />
<MenuItem command="copy" /> <MenuItem command="delete" />
<MenuItem command="delete" /> <MenuItem command="unGroup" icon="ungroup" text="Ungroup" />
<MenuItem command="unGroup" icon="ungroup" text="Ungroup" /> </GroupMenu>
</GroupMenu> <MultiMenu>
<MultiMenu> <MenuItem command="copy" />
<MenuItem command="copy" /> <MenuItem command="paste" />
<MenuItem command="paste" /> <MenuItem command="addGroup" icon="group" text="Add Group" />
<MenuItem command="addGroup" icon="group" text="Add Group" /> <MenuItem command="delete" />
<MenuItem command="delete" /> </MultiMenu>
</MultiMenu> <CanvasMenu>
<CanvasMenu> <MenuItem command="undo" />
<MenuItem command="undo" /> <MenuItem command="redo" />
<MenuItem command="redo" /> <MenuItem command="pasteHere" icon="paste" text="Paste Here" />
<MenuItem command="pasteHere" icon="paste" text="Paste Here" /> </CanvasMenu>
</CanvasMenu> </ContextMenu>
</ContextMenu> );
);
};
export default FlowContextMenu; export default FlowContextMenu;
import React from 'react';
import { Command } from 'gg-editor'; import { Command } from 'gg-editor';
import React from 'react';
import IconFont from '../../common/IconFont'; import IconFont from '../../common/IconFont';
import styles from './index.less'; import styles from './index.less';
const upperFirst = (str: string) => { const upperFirst = (str: string) =>
return str.toLowerCase().replace(/( |^)[a-z]/g, (l: string) => l.toUpperCase()); str.toLowerCase().replace(/( |^)[a-z]/g, (l: string) => l.toUpperCase());
};
interface MenuItemProps { interface MenuItemProps {
command: string; command: string;
......
import { CanvasMenu, ContextMenu, NodeMenu } from 'gg-editor';
import React from 'react'; import React from 'react';
import { NodeMenu, CanvasMenu, ContextMenu } from 'gg-editor';
import MenuItem from './MenuItem'; import MenuItem from './MenuItem';
import styles from './index.less'; import styles from './index.less';
const MindContextMenu = () => { const MindContextMenu = () => (
return ( <ContextMenu className={styles.contextMenu}>
<ContextMenu className={styles.contextMenu}> <NodeMenu>
<NodeMenu> <MenuItem command="append" text="Topic" />
<MenuItem command="append" text="Topic" /> <MenuItem command="appendChild" icon="append-child" text="Subtopic" />
<MenuItem command="appendChild" icon="append-child" text="Subtopic" /> <MenuItem command="collapse" text="Fold" />
<MenuItem command="collapse" text="Fold" /> <MenuItem command="expand" text="Unfold" />
<MenuItem command="expand" text="Unfold" /> <MenuItem command="delete" />
<MenuItem command="delete" /> </NodeMenu>
</NodeMenu> <CanvasMenu>
<CanvasMenu> <MenuItem command="undo" />
<MenuItem command="undo" /> <MenuItem command="redo" />
<MenuItem command="redo" /> </CanvasMenu>
</CanvasMenu> </ContextMenu>
</ContextMenu> );
);
};
export default MindContextMenu; export default MindContextMenu;
import FlowContextMenu from './FlowContextMenu'; import FlowContextMenu from './FlowContextMenu';
import MindContextMenu from './MindContextMenu';
import KoniContextMenu from './KoniContextMenu'; import KoniContextMenu from './KoniContextMenu';
import MindContextMenu from './MindContextMenu';
export { FlowContextMenu, MindContextMenu, KoniContextMenu }; export { FlowContextMenu, MindContextMenu, KoniContextMenu };
import React, { Fragment } from 'react';
import { Card, Form, Input, Select } from 'antd'; import { Card, Form, Input, Select } from 'antd';
import { withPropsAPI } from 'gg-editor'; import React, { Fragment } from 'react';
import { FormComponentProps } from 'antd/es/form'; import { FormComponentProps } from 'antd/es/form';
import { withPropsAPI } from 'gg-editor';
const upperFirst = (str: string) => { const upperFirst = (str: string) =>
return str.toLowerCase().replace(/( |^)[a-z]/g, (l: string) => l.toUpperCase()); str.toLowerCase().replace(/( |^)[a-z]/g, (l: string) => l.toUpperCase());
};
const { Item } = Form; const { Item } = Form;
const { Option } = Select; const { Option } = Select;
...@@ -60,15 +60,13 @@ class DetailForm extends React.Component<DetailFormProps> { ...@@ -60,15 +60,13 @@ class DetailForm extends React.Component<DetailFormProps> {
}, 0); }, 0);
}; };
renderEdgeShapeSelect = () => { renderEdgeShapeSelect = () => (
return ( <Select onChange={this.handleSubmit}>
<Select onChange={this.handleSubmit}> <Option value="flow-smooth">Smooth</Option>
<Option value="flow-smooth">Smooth</Option> <Option value="flow-polyline">Polyline</Option>
<Option value="flow-polyline">Polyline</Option> <Option value="flow-polyline-round">Polyline Round</Option>
<Option value="flow-polyline-round">Polyline Round</Option> </Select>
</Select> );
);
};
renderNodeDetail = () => { renderNodeDetail = () => {
const { form } = this.props; const { form } = this.props;
......
import React from 'react'; import { CanvasPanel, DetailPanel, EdgePanel, GroupPanel, MultiPanel, NodePanel } from 'gg-editor';
import { Card } from 'antd'; import { Card } from 'antd';
import { NodePanel, EdgePanel, GroupPanel, MultiPanel, CanvasPanel, DetailPanel } from 'gg-editor'; import React from 'react';
import DetailForm from './DetailForm'; import DetailForm from './DetailForm';
import styles from './index.less'; import styles from './index.less';
const FlowDetailPanel = () => { const FlowDetailPanel = () => (
return ( <DetailPanel className={styles.detailPanel}>
<DetailPanel className={styles.detailPanel}> <NodePanel>
<NodePanel> <DetailForm type="node" />
<DetailForm type="node" /> </NodePanel>
</NodePanel> <EdgePanel>
<EdgePanel> <DetailForm type="edge" />
<DetailForm type="edge" /> </EdgePanel>
</EdgePanel> <GroupPanel>
<GroupPanel> <DetailForm type="group" />
<DetailForm type="group" /> </GroupPanel>
</GroupPanel> <MultiPanel>
<MultiPanel> <Card type="inner" size="small" title="Multi Select" bordered={false} />
<Card type="inner" size="small" title="Multi Select" bordered={false} /> </MultiPanel>
</MultiPanel> <CanvasPanel>
<CanvasPanel> <Card type="inner" size="small" title="Canvas" bordered={false} />
<Card type="inner" size="small" title="Canvas" bordered={false} /> </CanvasPanel>
</CanvasPanel> </DetailPanel>
</DetailPanel> );
);
};
export default FlowDetailPanel; export default FlowDetailPanel;
import React from 'react'; import { CanvasPanel, DetailPanel, NodePanel } from 'gg-editor';
import { Card } from 'antd'; import { Card } from 'antd';
import { NodePanel, CanvasPanel, DetailPanel } from 'gg-editor'; import React from 'react';
import DetailForm from './DetailForm'; import DetailForm from './DetailForm';
import styles from './index.less'; import styles from './index.less';
const MindDetailPanel = () => { const MindDetailPanel = () => (
return ( <DetailPanel className={styles.detailPanel}>
<DetailPanel className={styles.detailPanel}> <NodePanel>
<NodePanel> <DetailForm type="node" />
<DetailForm type="node" /> </NodePanel>
</NodePanel> <CanvasPanel>
<CanvasPanel> <Card type="inner" size="small" title="Canvas" bordered={false} />
<Card type="inner" size="small" title="Canvas" bordered={false} /> </CanvasPanel>
</CanvasPanel> </DetailPanel>
</DetailPanel> );
);
};
export default MindDetailPanel; export default MindDetailPanel;
import FlowDetailPanel from './FlowDetailPanel'; import FlowDetailPanel from './FlowDetailPanel';
import MindDetailPanel from './MindDetailPanel';
import KoniDetailPanel from './KoniDetailPanel'; import KoniDetailPanel from './KoniDetailPanel';
import MindDetailPanel from './MindDetailPanel';
export { FlowDetailPanel, MindDetailPanel, KoniDetailPanel }; export { FlowDetailPanel, MindDetailPanel, KoniDetailPanel };
import React from 'react'; import { Item, ItemPanel } from 'gg-editor';
import { Card } from 'antd'; import { Card } from 'antd';
import { ItemPanel, Item } from 'gg-editor'; import React from 'react';
import styles from './index.less'; import styles from './index.less';
const FlowItemPanel = () => { const FlowItemPanel = () => (
return ( <ItemPanel className={styles.itemPanel}>
<ItemPanel className={styles.itemPanel}> <Card bordered={false}>
<Card bordered={false}> <Item
<Item type="node"
type="node" size="72*72"
size="72*72" shape="flow-circle"
shape="flow-circle" model={{
model={{ color: '#FA8C16',
color: '#FA8C16', label: 'Start',
label: 'Start', }}
}} src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iODAiIGhlaWdodD0iODAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiPjxkZWZzPjxjaXJjbGUgaWQ9ImIiIGN4PSIzNiIgY3k9IjM2IiByPSIzNiIvPjxmaWx0ZXIgeD0iLTkuNyUiIHk9Ii02LjklIiB3aWR0aD0iMTE5LjQlIiBoZWlnaHQ9IjExOS40JSIgZmlsdGVyVW5pdHM9Im9iamVjdEJvdW5kaW5nQm94IiBpZD0iYSI+PGZlT2Zmc2V0IGR5PSIyIiBpbj0iU291cmNlQWxwaGEiIHJlc3VsdD0ic2hhZG93T2Zmc2V0T3V0ZXIxIi8+PGZlR2F1c3NpYW5CbHVyIHN0ZERldmlhdGlvbj0iMiIgaW49InNoYWRvd09mZnNldE91dGVyMSIgcmVzdWx0PSJzaGFkb3dCbHVyT3V0ZXIxIi8+PGZlQ29tcG9zaXRlIGluPSJzaGFkb3dCbHVyT3V0ZXIxIiBpbjI9IlNvdXJjZUFscGhhIiBvcGVyYXRvcj0ib3V0IiByZXN1bHQ9InNoYWRvd0JsdXJPdXRlcjEiLz48ZmVDb2xvck1hdHJpeCB2YWx1ZXM9IjAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAuMDQgMCIgaW49InNoYWRvd0JsdXJPdXRlcjEiLz48L2ZpbHRlcj48L2RlZnM+PGcgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIj48ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSg0IDIpIj48dXNlIGZpbGw9IiMwMDAiIGZpbHRlcj0idXJsKCNhKSIgeGxpbms6aHJlZj0iI2IiLz48dXNlIGZpbGwtb3BhY2l0eT0iLjkyIiBmaWxsPSIjRkZGMkU4IiB4bGluazpocmVmPSIjYiIvPjxjaXJjbGUgc3Ryb2tlPSIjRkZDMDY5IiBjeD0iMzYiIGN5PSIzNiIgcj0iMzUuNSIvPjwvZz48dGV4dCBmb250LWZhbWlseT0iUGluZ0ZhbmdTQy1SZWd1bGFyLCBQaW5nRmFuZyBTQyIgZm9udC1zaXplPSIxMiIgZmlsbD0iIzAwMCIgZmlsbC1vcGFjaXR5PSIuNjUiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDQgMikiPjx0c3BhbiB4PSIyMyIgeT0iNDEiPlN0YXJ0PC90c3Bhbj48L3RleHQ+PC9nPjwvc3ZnPg=="
src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iODAiIGhlaWdodD0iODAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiPjxkZWZzPjxjaXJjbGUgaWQ9ImIiIGN4PSIzNiIgY3k9IjM2IiByPSIzNiIvPjxmaWx0ZXIgeD0iLTkuNyUiIHk9Ii02LjklIiB3aWR0aD0iMTE5LjQlIiBoZWlnaHQ9IjExOS40JSIgZmlsdGVyVW5pdHM9Im9iamVjdEJvdW5kaW5nQm94IiBpZD0iYSI+PGZlT2Zmc2V0IGR5PSIyIiBpbj0iU291cmNlQWxwaGEiIHJlc3VsdD0ic2hhZG93T2Zmc2V0T3V0ZXIxIi8+PGZlR2F1c3NpYW5CbHVyIHN0ZERldmlhdGlvbj0iMiIgaW49InNoYWRvd09mZnNldE91dGVyMSIgcmVzdWx0PSJzaGFkb3dCbHVyT3V0ZXIxIi8+PGZlQ29tcG9zaXRlIGluPSJzaGFkb3dCbHVyT3V0ZXIxIiBpbjI9IlNvdXJjZUFscGhhIiBvcGVyYXRvcj0ib3V0IiByZXN1bHQ9InNoYWRvd0JsdXJPdXRlcjEiLz48ZmVDb2xvck1hdHJpeCB2YWx1ZXM9IjAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAuMDQgMCIgaW49InNoYWRvd0JsdXJPdXRlcjEiLz48L2ZpbHRlcj48L2RlZnM+PGcgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIj48ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSg0IDIpIj48dXNlIGZpbGw9IiMwMDAiIGZpbHRlcj0idXJsKCNhKSIgeGxpbms6aHJlZj0iI2IiLz48dXNlIGZpbGwtb3BhY2l0eT0iLjkyIiBmaWxsPSIjRkZGMkU4IiB4bGluazpocmVmPSIjYiIvPjxjaXJjbGUgc3Ryb2tlPSIjRkZDMDY5IiBjeD0iMzYiIGN5PSIzNiIgcj0iMzUuNSIvPjwvZz48dGV4dCBmb250LWZhbWlseT0iUGluZ0ZhbmdTQy1SZWd1bGFyLCBQaW5nRmFuZyBTQyIgZm9udC1zaXplPSIxMiIgZmlsbD0iIzAwMCIgZmlsbC1vcGFjaXR5PSIuNjUiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDQgMikiPjx0c3BhbiB4PSIyMyIgeT0iNDEiPlN0YXJ0PC90c3Bhbj48L3RleHQ+PC9nPjwvc3ZnPg==" />
/> <Item
<Item type="node"
type="node" size="80*48"
size="80*48" shape="flow-rect"
shape="flow-rect" model={{
model={{ color: '#1890FF',
color: '#1890FF', label: 'Normal',
label: 'Normal', }}
}} src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iODgiIGhlaWdodD0iNTYiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiPjxkZWZzPjxyZWN0IGlkPSJiIiB4PSIwIiB5PSIwIiB3aWR0aD0iODAiIGhlaWdodD0iNDgiIHJ4PSI0Ii8+PGZpbHRlciB4PSItOC44JSIgeT0iLTEwLjQlIiB3aWR0aD0iMTE3LjUlIiBoZWlnaHQ9IjEyOS4yJSIgZmlsdGVyVW5pdHM9Im9iamVjdEJvdW5kaW5nQm94IiBpZD0iYSI+PGZlT2Zmc2V0IGR5PSIyIiBpbj0iU291cmNlQWxwaGEiIHJlc3VsdD0ic2hhZG93T2Zmc2V0T3V0ZXIxIi8+PGZlR2F1c3NpYW5CbHVyIHN0ZERldmlhdGlvbj0iMiIgaW49InNoYWRvd09mZnNldE91dGVyMSIgcmVzdWx0PSJzaGFkb3dCbHVyT3V0ZXIxIi8+PGZlQ29tcG9zaXRlIGluPSJzaGFkb3dCbHVyT3V0ZXIxIiBpbjI9IlNvdXJjZUFscGhhIiBvcGVyYXRvcj0ib3V0IiByZXN1bHQ9InNoYWRvd0JsdXJPdXRlcjEiLz48ZmVDb2xvck1hdHJpeCB2YWx1ZXM9IjAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAuMDQgMCIgaW49InNoYWRvd0JsdXJPdXRlcjEiLz48L2ZpbHRlcj48L2RlZnM+PGcgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIj48ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSg0IDIpIj48dXNlIGZpbGw9IiMwMDAiIGZpbHRlcj0idXJsKCNhKSIgeGxpbms6aHJlZj0iI2IiLz48dXNlIGZpbGwtb3BhY2l0eT0iLjkyIiBmaWxsPSIjRTZGN0ZGIiB4bGluazpocmVmPSIjYiIvPjxyZWN0IHN0cm9rZT0iIzE4OTBGRiIgeD0iLjUiIHk9Ii41IiB3aWR0aD0iNzkiIGhlaWdodD0iNDciIHJ4PSI0Ii8+PC9nPjx0ZXh0IGZvbnQtZmFtaWx5PSJQaW5nRmFuZ1NDLVJlZ3VsYXIsIFBpbmdGYW5nIFNDIiBmb250LXNpemU9IjEyIiBmaWxsPSIjMDAwIiBmaWxsLW9wYWNpdHk9Ii42NSIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoNCAyKSI+PHRzcGFuIHg9IjIxIiB5PSIyOSI+Tm9ybWFsPC90c3Bhbj48L3RleHQ+PC9nPjwvc3ZnPg=="
src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iODgiIGhlaWdodD0iNTYiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiPjxkZWZzPjxyZWN0IGlkPSJiIiB4PSIwIiB5PSIwIiB3aWR0aD0iODAiIGhlaWdodD0iNDgiIHJ4PSI0Ii8+PGZpbHRlciB4PSItOC44JSIgeT0iLTEwLjQlIiB3aWR0aD0iMTE3LjUlIiBoZWlnaHQ9IjEyOS4yJSIgZmlsdGVyVW5pdHM9Im9iamVjdEJvdW5kaW5nQm94IiBpZD0iYSI+PGZlT2Zmc2V0IGR5PSIyIiBpbj0iU291cmNlQWxwaGEiIHJlc3VsdD0ic2hhZG93T2Zmc2V0T3V0ZXIxIi8+PGZlR2F1c3NpYW5CbHVyIHN0ZERldmlhdGlvbj0iMiIgaW49InNoYWRvd09mZnNldE91dGVyMSIgcmVzdWx0PSJzaGFkb3dCbHVyT3V0ZXIxIi8+PGZlQ29tcG9zaXRlIGluPSJzaGFkb3dCbHVyT3V0ZXIxIiBpbjI9IlNvdXJjZUFscGhhIiBvcGVyYXRvcj0ib3V0IiByZXN1bHQ9InNoYWRvd0JsdXJPdXRlcjEiLz48ZmVDb2xvck1hdHJpeCB2YWx1ZXM9IjAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAuMDQgMCIgaW49InNoYWRvd0JsdXJPdXRlcjEiLz48L2ZpbHRlcj48L2RlZnM+PGcgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIj48ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSg0IDIpIj48dXNlIGZpbGw9IiMwMDAiIGZpbHRlcj0idXJsKCNhKSIgeGxpbms6aHJlZj0iI2IiLz48dXNlIGZpbGwtb3BhY2l0eT0iLjkyIiBmaWxsPSIjRTZGN0ZGIiB4bGluazpocmVmPSIjYiIvPjxyZWN0IHN0cm9rZT0iIzE4OTBGRiIgeD0iLjUiIHk9Ii41IiB3aWR0aD0iNzkiIGhlaWdodD0iNDciIHJ4PSI0Ii8+PC9nPjx0ZXh0IGZvbnQtZmFtaWx5PSJQaW5nRmFuZ1NDLVJlZ3VsYXIsIFBpbmdGYW5nIFNDIiBmb250LXNpemU9IjEyIiBmaWxsPSIjMDAwIiBmaWxsLW9wYWNpdHk9Ii42NSIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoNCAyKSI+PHRzcGFuIHg9IjIxIiB5PSIyOSI+Tm9ybWFsPC90c3Bhbj48L3RleHQ+PC9nPjwvc3ZnPg==" />
/> <Item
<Item type="node"
type="node" size="80*72"
size="80*72" shape="flow-rhombus"
shape="flow-rhombus" model={{
model={{ color: '#13C2C2',
color: '#13C2C2', label: 'Decision',
label: 'Decision', }}
}} src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iODYiIGhlaWdodD0iNzgiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiPjxkZWZzPjxwYXRoIGQ9Ik00Mi42NyAxLjY3bDM0Ljk2NSAzMS4zNTJhNCA0IDAgMCAxIDAgNS45NTZMNDIuNjcgNzAuMzNhNCA0IDAgMCAxLTUuMzQgMEwyLjM2NSAzOC45NzhhNCA0IDAgMCAxIDAtNS45NTZMMzcuMzMgMS42N2E0IDQgMCAwIDEgNS4zNCAweiIgaWQ9ImIiLz48ZmlsdGVyIHg9Ii04LjglIiB5PSItNi45JSIgd2lkdGg9IjExNy41JSIgaGVpZ2h0PSIxMTkuNCUiIGZpbHRlclVuaXRzPSJvYmplY3RCb3VuZGluZ0JveCIgaWQ9ImEiPjxmZU9mZnNldCBkeT0iMiIgaW49IlNvdXJjZUFscGhhIiByZXN1bHQ9InNoYWRvd09mZnNldE91dGVyMSIvPjxmZUdhdXNzaWFuQmx1ciBzdGREZXZpYXRpb249IjIiIGluPSJzaGFkb3dPZmZzZXRPdXRlcjEiIHJlc3VsdD0ic2hhZG93Qmx1ck91dGVyMSIvPjxmZUNvbXBvc2l0ZSBpbj0ic2hhZG93Qmx1ck91dGVyMSIgaW4yPSJTb3VyY2VBbHBoYSIgb3BlcmF0b3I9Im91dCIgcmVzdWx0PSJzaGFkb3dCbHVyT3V0ZXIxIi8+PGZlQ29sb3JNYXRyaXggdmFsdWVzPSIwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwLjA0IDAiIGluPSJzaGFkb3dCbHVyT3V0ZXIxIi8+PC9maWx0ZXI+PC9kZWZzPjxnIGZpbGw9Im5vbmUiIGZpbGwtcnVsZT0iZXZlbm9kZCI+PGcgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMyAxKSI+PHVzZSBmaWxsPSIjMDAwIiBmaWx0ZXI9InVybCgjYSkiIHhsaW5rOmhyZWY9IiNiIi8+PHVzZSBmaWxsLW9wYWNpdHk9Ii45MiIgZmlsbD0iI0U2RkZGQiIgeGxpbms6aHJlZj0iI2IiLz48cGF0aCBzdHJva2U9IiM1Q0RCRDMiIGQ9Ik00Mi4zMzcgMi4wNDJhMy41IDMuNSAwIDAgMC00LjY3NCAwTDIuNjk4IDMzLjM5NGEzLjUgMy41IDAgMCAwIDAgNS4yMTJsMzQuOTY1IDMxLjM1MmEzLjUgMy41IDAgMCAwIDQuNjc0IDBsMzQuOTY1LTMxLjM1MmEzLjUgMy41IDAgMCAwIDAtNS4yMTJMNDIuMzM3IDIuMDQyeiIvPjwvZz48dGV4dCBmb250LWZhbWlseT0iUGluZ0ZhbmdTQy1SZWd1bGFyLCBQaW5nRmFuZyBTQyIgZm9udC1zaXplPSIxMiIgZmlsbD0iIzAwMCIgZmlsbC1vcGFjaXR5PSIuNjUiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDMgMSkiPjx0c3BhbiB4PSIxOCIgeT0iNDIiPkRlY2lzaW9uPC90c3Bhbj48L3RleHQ+PC9nPjwvc3ZnPg=="
src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iODYiIGhlaWdodD0iNzgiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiPjxkZWZzPjxwYXRoIGQ9Ik00Mi42NyAxLjY3bDM0Ljk2NSAzMS4zNTJhNCA0IDAgMCAxIDAgNS45NTZMNDIuNjcgNzAuMzNhNCA0IDAgMCAxLTUuMzQgMEwyLjM2NSAzOC45NzhhNCA0IDAgMCAxIDAtNS45NTZMMzcuMzMgMS42N2E0IDQgMCAwIDEgNS4zNCAweiIgaWQ9ImIiLz48ZmlsdGVyIHg9Ii04LjglIiB5PSItNi45JSIgd2lkdGg9IjExNy41JSIgaGVpZ2h0PSIxMTkuNCUiIGZpbHRlclVuaXRzPSJvYmplY3RCb3VuZGluZ0JveCIgaWQ9ImEiPjxmZU9mZnNldCBkeT0iMiIgaW49IlNvdXJjZUFscGhhIiByZXN1bHQ9InNoYWRvd09mZnNldE91dGVyMSIvPjxmZUdhdXNzaWFuQmx1ciBzdGREZXZpYXRpb249IjIiIGluPSJzaGFkb3dPZmZzZXRPdXRlcjEiIHJlc3VsdD0ic2hhZG93Qmx1ck91dGVyMSIvPjxmZUNvbXBvc2l0ZSBpbj0ic2hhZG93Qmx1ck91dGVyMSIgaW4yPSJTb3VyY2VBbHBoYSIgb3BlcmF0b3I9Im91dCIgcmVzdWx0PSJzaGFkb3dCbHVyT3V0ZXIxIi8+PGZlQ29sb3JNYXRyaXggdmFsdWVzPSIwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwLjA0IDAiIGluPSJzaGFkb3dCbHVyT3V0ZXIxIi8+PC9maWx0ZXI+PC9kZWZzPjxnIGZpbGw9Im5vbmUiIGZpbGwtcnVsZT0iZXZlbm9kZCI+PGcgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMyAxKSI+PHVzZSBmaWxsPSIjMDAwIiBmaWx0ZXI9InVybCgjYSkiIHhsaW5rOmhyZWY9IiNiIi8+PHVzZSBmaWxsLW9wYWNpdHk9Ii45MiIgZmlsbD0iI0U2RkZGQiIgeGxpbms6aHJlZj0iI2IiLz48cGF0aCBzdHJva2U9IiM1Q0RCRDMiIGQ9Ik00Mi4zMzcgMi4wNDJhMy41IDMuNSAwIDAgMC00LjY3NCAwTDIuNjk4IDMzLjM5NGEzLjUgMy41IDAgMCAwIDAgNS4yMTJsMzQuOTY1IDMxLjM1MmEzLjUgMy41IDAgMCAwIDQuNjc0IDBsMzQuOTY1LTMxLjM1MmEzLjUgMy41IDAgMCAwIDAtNS4yMTJMNDIuMzM3IDIuMDQyeiIvPjwvZz48dGV4dCBmb250LWZhbWlseT0iUGluZ0ZhbmdTQy1SZWd1bGFyLCBQaW5nRmFuZyBTQyIgZm9udC1zaXplPSIxMiIgZmlsbD0iIzAwMCIgZmlsbC1vcGFjaXR5PSIuNjUiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDMgMSkiPjx0c3BhbiB4PSIxOCIgeT0iNDIiPkRlY2lzaW9uPC90c3Bhbj48L3RleHQ+PC9nPjwvc3ZnPg==" />
/> <Item
<Item type="node"
type="node" size="80*48"
size="80*48" shape="flow-capsule"
shape="flow-capsule" model={{
model={{ color: '#722ED1',
color: '#722ED1', label: 'Model',
label: 'Model', }}
}} src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iODgiIGhlaWdodD0iNTYiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiPjxkZWZzPjxyZWN0IGlkPSJiIiB4PSIwIiB5PSIwIiB3aWR0aD0iODAiIGhlaWdodD0iNDgiIHJ4PSIyNCIvPjxmaWx0ZXIgeD0iLTguOCUiIHk9Ii0xMC40JSIgd2lkdGg9IjExNy41JSIgaGVpZ2h0PSIxMjkuMiUiIGZpbHRlclVuaXRzPSJvYmplY3RCb3VuZGluZ0JveCIgaWQ9ImEiPjxmZU9mZnNldCBkeT0iMiIgaW49IlNvdXJjZUFscGhhIiByZXN1bHQ9InNoYWRvd09mZnNldE91dGVyMSIvPjxmZUdhdXNzaWFuQmx1ciBzdGREZXZpYXRpb249IjIiIGluPSJzaGFkb3dPZmZzZXRPdXRlcjEiIHJlc3VsdD0ic2hhZG93Qmx1ck91dGVyMSIvPjxmZUNvbXBvc2l0ZSBpbj0ic2hhZG93Qmx1ck91dGVyMSIgaW4yPSJTb3VyY2VBbHBoYSIgb3BlcmF0b3I9Im91dCIgcmVzdWx0PSJzaGFkb3dCbHVyT3V0ZXIxIi8+PGZlQ29sb3JNYXRyaXggdmFsdWVzPSIwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwLjA0IDAiIGluPSJzaGFkb3dCbHVyT3V0ZXIxIi8+PC9maWx0ZXI+PC9kZWZzPjxnIGZpbGw9Im5vbmUiIGZpbGwtcnVsZT0iZXZlbm9kZCI+PGcgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoNCAyKSI+PHVzZSBmaWxsPSIjMDAwIiBmaWx0ZXI9InVybCgjYSkiIHhsaW5rOmhyZWY9IiNiIi8+PHVzZSBmaWxsLW9wYWNpdHk9Ii45MiIgZmlsbD0iI0Y5RjBGRiIgeGxpbms6aHJlZj0iI2IiLz48cmVjdCBzdHJva2U9IiNCMzdGRUIiIHg9Ii41IiB5PSIuNSIgd2lkdGg9Ijc5IiBoZWlnaHQ9IjQ3IiByeD0iMjMuNSIvPjwvZz48dGV4dCBmb250LWZhbWlseT0iUGluZ0ZhbmdTQy1SZWd1bGFyLCBQaW5nRmFuZyBTQyIgZm9udC1zaXplPSIxMiIgZmlsbD0iIzAwMCIgZmlsbC1vcGFjaXR5PSIuNjUiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDQgMikiPjx0c3BhbiB4PSIyNCIgeT0iMjkiPk1vZGVsPC90c3Bhbj48L3RleHQ+PC9nPjwvc3ZnPg=="
src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iODgiIGhlaWdodD0iNTYiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiPjxkZWZzPjxyZWN0IGlkPSJiIiB4PSIwIiB5PSIwIiB3aWR0aD0iODAiIGhlaWdodD0iNDgiIHJ4PSIyNCIvPjxmaWx0ZXIgeD0iLTguOCUiIHk9Ii0xMC40JSIgd2lkdGg9IjExNy41JSIgaGVpZ2h0PSIxMjkuMiUiIGZpbHRlclVuaXRzPSJvYmplY3RCb3VuZGluZ0JveCIgaWQ9ImEiPjxmZU9mZnNldCBkeT0iMiIgaW49IlNvdXJjZUFscGhhIiByZXN1bHQ9InNoYWRvd09mZnNldE91dGVyMSIvPjxmZUdhdXNzaWFuQmx1ciBzdGREZXZpYXRpb249IjIiIGluPSJzaGFkb3dPZmZzZXRPdXRlcjEiIHJlc3VsdD0ic2hhZG93Qmx1ck91dGVyMSIvPjxmZUNvbXBvc2l0ZSBpbj0ic2hhZG93Qmx1ck91dGVyMSIgaW4yPSJTb3VyY2VBbHBoYSIgb3BlcmF0b3I9Im91dCIgcmVzdWx0PSJzaGFkb3dCbHVyT3V0ZXIxIi8+PGZlQ29sb3JNYXRyaXggdmFsdWVzPSIwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwLjA0IDAiIGluPSJzaGFkb3dCbHVyT3V0ZXIxIi8+PC9maWx0ZXI+PC9kZWZzPjxnIGZpbGw9Im5vbmUiIGZpbGwtcnVsZT0iZXZlbm9kZCI+PGcgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoNCAyKSI+PHVzZSBmaWxsPSIjMDAwIiBmaWx0ZXI9InVybCgjYSkiIHhsaW5rOmhyZWY9IiNiIi8+PHVzZSBmaWxsLW9wYWNpdHk9Ii45MiIgZmlsbD0iI0Y5RjBGRiIgeGxpbms6aHJlZj0iI2IiLz48cmVjdCBzdHJva2U9IiNCMzdGRUIiIHg9Ii41IiB5PSIuNSIgd2lkdGg9Ijc5IiBoZWlnaHQ9IjQ3IiByeD0iMjMuNSIvPjwvZz48dGV4dCBmb250LWZhbWlseT0iUGluZ0ZhbmdTQy1SZWd1bGFyLCBQaW5nRmFuZyBTQyIgZm9udC1zaXplPSIxMiIgZmlsbD0iIzAwMCIgZmlsbC1vcGFjaXR5PSIuNjUiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDQgMikiPjx0c3BhbiB4PSIyNCIgeT0iMjkiPk1vZGVsPC90c3Bhbj48L3RleHQ+PC9nPjwvc3ZnPg==" />
/> </Card>
</Card> </ItemPanel>
</ItemPanel> );
);
};
export default FlowItemPanel; export default FlowItemPanel;
import React from 'react';
import { Card } from 'antd'; import { Card } from 'antd';
import { Minimap } from 'gg-editor'; import { Minimap } from 'gg-editor';
import React from 'react';
const EditorMinimap = () => { const EditorMinimap = () => (
return ( <Card type="inner" size="small" title="Minimap" bordered={false}>
<Card type="inner" size="small" title="Minimap" bordered={false}> <Minimap height={200} />
<Minimap height={200} /> </Card>
</Card> );
);
};
export default EditorMinimap; export default EditorMinimap;
import React from 'react';
import { Divider } from 'antd'; import { Divider } from 'antd';
import React from 'react';
import { Toolbar } from 'gg-editor'; import { Toolbar } from 'gg-editor';
import ToolbarButton from './ToolbarButton'; import ToolbarButton from './ToolbarButton';
import styles from './index.less'; import styles from './index.less';
const FlowToolbar = () => { const FlowToolbar = () => (
return ( <Toolbar className={styles.toolbar}>
<Toolbar className={styles.toolbar}> <ToolbarButton command="undo" />
<ToolbarButton command="undo" /> <ToolbarButton command="redo" />
<ToolbarButton command="redo" /> <Divider type="vertical" />
<Divider type="vertical" /> <ToolbarButton command="copy" />
<ToolbarButton command="copy" /> <ToolbarButton command="paste" />
<ToolbarButton command="paste" /> <ToolbarButton command="delete" />
<ToolbarButton command="delete" /> <Divider type="vertical" />
<Divider type="vertical" /> <ToolbarButton command="zoomIn" icon="zoom-in" text="Zoom In" />
<ToolbarButton command="zoomIn" icon="zoom-in" text="Zoom In" /> <ToolbarButton command="zoomOut" icon="zoom-out" text="Zoom Out" />
<ToolbarButton command="zoomOut" icon="zoom-out" text="Zoom Out" /> <ToolbarButton command="autoZoom" icon="fit-map" text="Fit Map" />
<ToolbarButton command="autoZoom" icon="fit-map" text="Fit Map" /> <ToolbarButton command="resetZoom" icon="actual-size" text="Actual Size" />
<ToolbarButton command="resetZoom" icon="actual-size" text="Actual Size" /> <Divider type="vertical" />
<Divider type="vertical" /> <ToolbarButton command="toBack" icon="to-back" text="To Back" />
<ToolbarButton command="toBack" icon="to-back" text="To Back" /> <ToolbarButton command="toFront" icon="to-front" text="To Front" />
<ToolbarButton command="toFront" icon="to-front" text="To Front" /> <Divider type="vertical" />
<Divider type="vertical" /> <ToolbarButton command="multiSelect" icon="multi-select" text="Multi Select" />
<ToolbarButton command="multiSelect" icon="multi-select" text="Multi Select" /> <ToolbarButton command="addGroup" icon="group" text="Add Group" />
<ToolbarButton command="addGroup" icon="group" text="Add Group" /> <ToolbarButton command="unGroup" icon="ungroup" text="Ungroup" />
<ToolbarButton command="unGroup" icon="ungroup" text="Ungroup" /> </Toolbar>
</Toolbar> );
);
};
export default FlowToolbar; export default FlowToolbar;
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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