Unverified Commit c08aa5ba authored by 陈帅's avatar 陈帅 Committed by GitHub

Merge pull request #14 from ant-design/feat/workplacetots

feat: Workplace migrate to TypeScript
parents 40ac8b52 3b803cb7
...@@ -3,7 +3,7 @@ export default { ...@@ -3,7 +3,7 @@ export default {
[ [
'umi-plugin-block-dev', 'umi-plugin-block-dev',
{ {
layout: 'ant-design-pro-user', layout: 'ant-design-pro',
menu: { menu: {
name: '主页', name: '主页',
icon: 'home', icon: 'home',
......
...@@ -3,7 +3,6 @@ import ChartCard from './ChartCard'; ...@@ -3,7 +3,6 @@ import ChartCard from './ChartCard';
import Field from './Field'; import Field from './Field';
import Bar from './Bar'; import Bar from './Bar';
import Pie from './Pie'; import Pie from './Pie';
import Radar from './Radar';
import Gauge from './Gauge'; import Gauge from './Gauge';
import MiniArea from './MiniArea'; import MiniArea from './MiniArea';
import MiniBar from './MiniBar'; import MiniBar from './MiniBar';
...@@ -19,7 +18,6 @@ const Charts = { ...@@ -19,7 +18,6 @@ const Charts = {
Bar, Bar,
Pie, Pie,
Gauge, Gauge,
Radar,
MiniBar, MiniBar,
MiniArea, MiniArea,
MiniProgress, MiniProgress,
...@@ -36,7 +34,6 @@ export { ...@@ -36,7 +34,6 @@ export {
Bar, Bar,
Pie, Pie,
Gauge, Gauge,
Radar,
MiniBar, MiniBar,
MiniArea, MiniArea,
MiniProgress, MiniProgress,
......
...@@ -16,7 +16,8 @@ ...@@ -16,7 +16,8 @@
"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" "umi-request": "^1.0.0",
"bizcharts": "^3.5.2"
}, },
"devDependencies": { "devDependencies": {
"umi": "^2.6.9", "umi": "^2.6.9",
...@@ -24,4 +25,4 @@ ...@@ -24,4 +25,4 @@
"umi-plugin-react": "^1.3.0-beta.1" "umi-plugin-react": "^1.3.0-beta.1"
}, },
"license": "MIT" "license": "MIT"
} }
\ No newline at end of file
import React, { PureComponent, createElement } from 'react'; import React, { PureComponent, createElement } from 'react';
import PropTypes from 'prop-types'; import PropTypes, { string } from 'prop-types';
import { Button } from 'antd'; import { Button } from 'antd';
import styles from './index.less'; import styles from './index.less';
// TODO: 添加逻辑 export interface EditableLink {
title: string;
href: string;
}
interface EditableLinkGroupProps {
onAdd: () => void;
links: EditableLink[];
linkElement: React.Component;
}
class EditableLinkGroup extends PureComponent { class EditableLinkGroup extends PureComponent<EditableLinkGroupProps> {
static propTypes = { static propTypes = {
links: PropTypes.array, links: PropTypes.array,
onAdd: PropTypes.func, onAdd: PropTypes.func,
......
import React from 'react';
import { FormattedMessage } from 'umi-plugin-react/locale';
import Link from 'umi/link';
import { PageHeader } from 'ant-design-pro';
import styles from './index.less';
const PageHeaderWrapper = ({ children, contentWidth, wrapperClassName, ...restProps }) => (
<div style={{ margin: '-24px -24px 0' }} className={wrapperClassName}>
<PageHeader
wide={contentWidth === 'Fixed'}
home={<FormattedMessage id="BLOCK_NAME.menu.home" defaultMessage="Home" />}
key="pageheader"
{...restProps}
linkElement={Link}
itemRender={item => {
if (item.locale) {
return <FormattedMessage id={item.locale} defaultMessage={item.title} />;
}
return item.title;
}}
/>
{children ? <div className={styles.content}>{children}</div> : null}
</div>
);
export default PageHeaderWrapper;
@import '~antd/lib/style/themes/default.less'; @import '~antd/lib/style/themes/default.less';
.content { .children-content {
margin: 24px 24px 0; margin: 24px 24px 0;
} }
@media screen and (max-width: @screen-sm) { .main {
.detail {
display: flex;
}
.row {
display: flex;
width: 100%;
}
.title-content {
margin-bottom: 16px;
}
@media screen and (max-width: @screen-sm) {
.content {
margin: 24px 0 0;
}
}
.title,
.content { .content {
margin: 24px 0 0; flex: auto;
}
.extraContent,
.main {
flex: 0 1 auto;
}
.main {
width: 100%;
}
.title {
margin-bottom: 16px;
}
.logo,
.content,
.extraContent {
margin-bottom: 16px;
}
.extraContent {
min-width: 242px;
margin-left: 88px;
text-align: right;
}
}
@media screen and (max-width: @screen-xl) {
.extraContent {
margin-left: 44px;
}
}
@media screen and (max-width: @screen-lg) {
.extraContent {
margin-left: 20px;
}
}
@media screen and (max-width: @screen-md) {
.row {
display: block;
}
.action,
.extraContent {
margin-left: 0;
text-align: left;
}
}
@media screen and (max-width: @screen-sm) {
.detail {
display: block;
} }
} }
import React from 'react';
import { RouteContext } from '@ant-design/pro-layout';
import { PageHeader, Typography } from 'antd';
import styles from './index.less';
import { GridContent } from '@ant-design/pro-layout';
interface IPageHeaderWrapperProps {
content?: React.ReactNode;
title?: React.ReactNode;
extraContent?: React.ReactNode;
}
const PageHeaderWrapper: React.SFC<IPageHeaderWrapperProps> = ({
children,
content,
title,
extraContent,
...restProps
}) => (
<RouteContext.Consumer>
{value => (
<div style={{ margin: '-24px -24px 0' }}>
<PageHeader
title={title}
{...restProps}
{...value}
>
<div className={styles.detail}>
<div className={styles.main}>
<div className={styles.row}>
{content && <div className={styles.content}>{content}</div>}
{extraContent && <div className={styles.extraContent}>{extraContent}</div>}
</div>
</div>
</div>
</PageHeader>
{children ? (
<GridContent>
<div className={styles['children-content']}>{children}</div>
</GridContent>
) : null}
</div>
)}
</RouteContext.Consumer>
);
export default PageHeaderWrapper;
import React from 'react';
export type IReactComponent<P = any> =
| React.StatelessComponent<P>
| React.ComponentClass<P>
| React.ClassicComponentClass<P>;
function computeHeight(node: HTMLDivElement) {
node.style.height = '100%';
const totalHeight = parseInt(getComputedStyle(node).height + '', 10);
const padding =
parseInt(getComputedStyle(node).paddingTop + '', 10) +
parseInt(getComputedStyle(node).paddingBottom + '', 10);
return totalHeight - padding;
}
function getAutoHeight(n: HTMLDivElement) {
if (!n) {
return 0;
}
let node = n;
let height = computeHeight(node);
const parentNode = node.parentNode as HTMLDivElement;
if (parentNode) {
height = computeHeight(parentNode);
}
return height;
}
interface IAutoHeightProps {
height?: number;
}
function autoHeight() {
return function<P extends IAutoHeightProps>(
WrappedComponent: React.ComponentClass<P> | React.SFC<P>
): React.ComponentClass<P> {
class AutoHeightComponent extends React.Component<P & IAutoHeightProps> {
state = {
computedHeight: 0,
};
root!: HTMLDivElement;
componentDidMount() {
const { height } = this.props;
if (!height) {
const h = getAutoHeight(this.root);
// eslint-disable-next-line
this.setState({ computedHeight: h });
if (h < 1) {
const h = getAutoHeight(this.root);
this.setState({ computedHeight: h });
}
}
}
handleRoot = (node: HTMLDivElement) => {
this.root = node;
};
render() {
const { height } = this.props;
const { computedHeight } = this.state;
const h = height || computedHeight;
return (
<div ref={this.handleRoot}>
{h > 0 && <WrappedComponent {...this.props} height={h} />}
</div>
);
}
}
return AutoHeightComponent;
};
}
export default autoHeight;
import React, { Component } from 'react'; import React, { Component } from 'react';
import { Chart, G2, Tooltip, Geom, Coord, Axis } from 'bizcharts'; import { Chart, Tooltip, Geom, Coord, Axis } from 'bizcharts';
import { Row, Col } from 'antd'; 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 IRadarProps {
......
export interface ITag {
key: string;
label: string;
}
export interface Province {
label: string;
key: string;
}
export interface City {
label: string;
key: string;
}
export interface Geographic {
province: Province;
city: City;
}
export interface Notice {
id: string;
title: string;
logo: string;
description: string;
updatedAt: string;
member: string;
href: string;
memberLink: string;
}
export interface CurrentUser {
name: string;
avatar: string;
userid: string;
notice: Notice[];
email: string;
signature: string;
title: string;
group: string;
tags: ITag[];
notifyCount: number;
unreadCount: number;
country: string;
geographic: Geographic;
address: string;
phone: string;
}
export interface Member {
avatar: string;
name: string;
id: string;
}
export interface Activeties {
id: string,
updatedAt: string,
user: {
name: string,
avatar: string,
},
group: {
name: string,
link: string,
},
project: {
name: string,
link: string,
},
template: string,
}
export interface RadarData {
label: string;
name: string;
value: number;
}
...@@ -3,15 +3,17 @@ import moment from 'moment'; ...@@ -3,15 +3,17 @@ import moment from 'moment';
import { connect } from 'dva'; import { connect } from 'dva';
import Link from 'umi/link'; import Link from 'umi/link';
import { Row, Col, Card, List, Avatar } from 'antd'; import { Row, Col, Card, List, Avatar } from 'antd';
import { Dispatch } from 'redux';
import { Charts } from 'ant-design-pro';
import EditableLinkGroup from './components/EditableLinkGroup'; import EditableLinkGroup from './components/EditableLinkGroup';
import PageHeaderWrapper from './components/PageHeaderWrapper'; import PageHeaderWrapper from './components/PageHeaderWrapper';
import Radar from './components/Radar';
import { ModalState } from './model';
import { CurrentUser, Activeties, RadarData, Notice } from './data';
import styles from './style.less'; import styles from './style.less';
const { Radar } = Charts;
const links = [ const links = [
{ {
title: '操作一', title: '操作一',
...@@ -39,16 +41,33 @@ const links = [ ...@@ -39,16 +41,33 @@ const links = [
}, },
]; ];
@connect(({ BLOCK_NAME_CAMEL_CASE: { user, project, activities, chart }, loading }) => ({ interface BLOCK_NAME_CAMEL_CASEProps {
currentUser: user.currentUser, currentUser: CurrentUser;
project, projectNotice: Notice[];
activities: Activeties[];
radarData: RadarData[];
dispatch: Dispatch;
currentUserLoading: boolean;
projectLoading: boolean;
activitiesLoading: boolean;
}
@connect(({
BLOCK_NAME_CAMEL_CASE: { currentUser, projectNotice, activities, radarData },
loading,
}: {
BLOCK_NAME_CAMEL_CASE: ModalState,
loading: { effects: any },
}) => ({
currentUser,
projectNotice,
activities, activities,
chart, radarData,
currentUserLoading: loading.effects['BLOCK_NAME_CAMEL_CASE/fetchUserCurrent'], currentUserLoading: loading.effects['BLOCK_NAME_CAMEL_CASE/fetchUserCurrent'],
projectLoading: loading.effects['BLOCK_NAME_CAMEL_CASE/fetchProjectNotice'], projectLoading: loading.effects['BLOCK_NAME_CAMEL_CASE/fetchProjectNotice'],
activitiesLoading: loading.effects['BLOCK_NAME_CAMEL_CASE/fetchActivitiesList'], activitiesLoading: loading.effects['BLOCK_NAME_CAMEL_CASE/fetchActivitiesList'],
})) }))
class PAGE_NAME_UPPER_CAMEL_CASE extends PureComponent { class PAGE_NAME_UPPER_CAMEL_CASE extends PureComponent<BLOCK_NAME_CAMEL_CASEProps> {
componentDidMount() { componentDidMount() {
const { dispatch } = this.props; const { dispatch } = this.props;
dispatch({ dispatch({
...@@ -65,9 +84,9 @@ class PAGE_NAME_UPPER_CAMEL_CASE extends PureComponent { ...@@ -65,9 +84,9 @@ class PAGE_NAME_UPPER_CAMEL_CASE extends PureComponent {
renderActivities() { renderActivities() {
const { const {
activities: { list }, activities,
} = this.props; } = this.props;
return list.map(item => { return activities.map(item => {
const events = item.template.split(/@\{([^{}]*)\}/gi).map(key => { const events = item.template.split(/@\{([^{}]*)\}/gi).map(key => {
if (item[key]) { if (item[key]) {
return ( return (
...@@ -103,11 +122,10 @@ class PAGE_NAME_UPPER_CAMEL_CASE extends PureComponent { ...@@ -103,11 +122,10 @@ class PAGE_NAME_UPPER_CAMEL_CASE extends PureComponent {
render() { render() {
const { const {
currentUser, currentUser,
currentUserLoading, projectNotice,
project: { notice },
projectLoading, projectLoading,
activitiesLoading, activitiesLoading,
chart: { radarData }, radarData,
} = this.props; } = this.props;
const pageHeaderContent = const pageHeaderContent =
...@@ -150,7 +168,6 @@ class PAGE_NAME_UPPER_CAMEL_CASE extends PureComponent { ...@@ -150,7 +168,6 @@ class PAGE_NAME_UPPER_CAMEL_CASE extends PureComponent {
return ( return (
<PageHeaderWrapper <PageHeaderWrapper
loading={currentUserLoading}
content={pageHeaderContent} content={pageHeaderContent}
extraContent={extraContent} extraContent={extraContent}
> >
...@@ -165,7 +182,7 @@ class PAGE_NAME_UPPER_CAMEL_CASE extends PureComponent { ...@@ -165,7 +182,7 @@ class PAGE_NAME_UPPER_CAMEL_CASE extends PureComponent {
loading={projectLoading} loading={projectLoading}
bodyStyle={{ padding: 0 }} bodyStyle={{ padding: 0 }}
> >
{notice.map(item => ( {projectNotice.map(item => (
<Card.Grid className={styles.projectGrid} key={item.id}> <Card.Grid className={styles.projectGrid} key={item.id}>
<Card bodyStyle={{ padding: 0 }} bordered={false}> <Card bodyStyle={{ padding: 0 }} bordered={false}>
<Card.Meta <Card.Meta
...@@ -228,7 +245,7 @@ class PAGE_NAME_UPPER_CAMEL_CASE extends PureComponent { ...@@ -228,7 +245,7 @@ class PAGE_NAME_UPPER_CAMEL_CASE extends PureComponent {
> >
<div className={styles.members}> <div className={styles.members}>
<Row gutter={48}> <Row gutter={48}>
{notice.map(item => ( {projectNotice.map(item => (
<Col span={12} key={`members-item-${item.id}`}> <Col span={12} key={`members-item-${item.id}`}>
<Link to={item.href}> <Link to={item.href}>
<Avatar src={item.logo} size="small" /> <Avatar src={item.logo} size="small" />
......
import { EffectsCommandMap } from 'dva';
import { Reducer, AnyAction } from 'redux';
import { queryCurrent, queryProjectNotice, queryActivities, fakeChartData } from './service'; import { queryCurrent, queryProjectNotice, queryActivities, fakeChartData } from './service';
import { CurrentUser, Notice, Activeties, RadarData } from './data';
export default { export interface ModalState {
currentUser: Partial<CurrentUser>;
projectNotice: Notice[];
activities: Activeties[];
radarData: RadarData[];
}
export type Effect = (
action: AnyAction,
effects: EffectsCommandMap & { select: <T>(func: (state: ModalState) => T) => T }
) => void;
export interface ModelType {
namespace: string;
state: ModalState;
reducers: {
save: Reducer<ModalState>;
clear: Reducer<ModalState>;
};
effects: {
init: Effect;
fetchUserCurrent: Effect;
fetchProjectNotice: Effect;
fetchActivitiesList: Effect;
fetchChart: Effect;
};
}
const Model: ModelType = {
namespace: 'BLOCK_NAME_CAMEL_CASE', namespace: 'BLOCK_NAME_CAMEL_CASE',
state: { state: {
user: { currentUser: {},
currentUser: {}, projectNotice: [],
}, activities: [],
project: { radarData: [],
notice: [],
},
activities: {
list: [],
},
chart: {
visitData: [],
visitData2: [],
salesData: [],
searchData: [],
offlineData: [],
offlineChartData: [],
salesTypeData: [],
salesTypeDataOnline: [],
salesTypeDataOffline: [],
radarData: [],
loading: false,
},
},
reducers: {
saveCurrentUser(state, action) {
return {
...state,
user: {
currentUser: action.payload || {},
},
};
},
saveNotice(state, action) {
return {
...state,
project: {
notice: action.payload,
},
};
},
saveList(state, action) {
return {
...state,
activities: {
list: action.payload,
},
};
},
saveChart(state, { payload }) {
return {
...state,
chart: {
...payload,
},
};
},
clear(state) {
return {
...state,
chart: {
visitData: [],
visitData2: [],
salesData: [],
searchData: [],
offlineData: [],
offlineChartData: [],
salesTypeData: [],
salesTypeDataOnline: [],
salesTypeDataOffline: [],
radarData: [],
},
};
},
}, },
effects: { effects: {
*init(_, { put }) { *init(_, { put }) {
...@@ -87,30 +49,56 @@ export default { ...@@ -87,30 +49,56 @@ export default {
*fetchUserCurrent(_, { call, put }) { *fetchUserCurrent(_, { call, put }) {
const response = yield call(queryCurrent); const response = yield call(queryCurrent);
yield put({ yield put({
type: 'saveCurrentUser', type: 'save',
payload: response, payload: {
currentUser: response,
},
}); });
}, },
*fetchProjectNotice(_, { call, put }) { *fetchProjectNotice(_, { call, put }) {
const response = yield call(queryProjectNotice); const response = yield call(queryProjectNotice);
yield put({ yield put({
type: 'saveNotice', type: 'save',
payload: Array.isArray(response) ? response : [], payload: {
projectNotice: Array.isArray(response) ? response : [],
}
}); });
}, },
*fetchActivitiesList(_, { call, put }) { *fetchActivitiesList(_, { call, put }) {
const response = yield call(queryActivities); const response = yield call(queryActivities);
yield put({ yield put({
type: 'saveList', type: 'save',
payload: Array.isArray(response) ? response : [], payload: {
activities: Array.isArray(response) ? response : [],
}
}); });
}, },
*fetchChart(_, { call, put }) { *fetchChart(_, { call, put }) {
const response = yield call(fakeChartData); const { radarData } = yield call(fakeChartData);
yield put({ yield put({
type: 'saveChart', type: 'save',
payload: response, payload: {
radarData,
},
}); });
}, },
}, },
reducers: {
save(state, { payload }) {
return {
...state,
...payload,
};
},
clear() {
return {
currentUser: {},
projectNotice: [],
activities: [],
radarData: [],
};
},
},
}; };
export default Model;
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