6 changed files with 54 additions and 465 deletions
@ -1,7 +0,0 @@ |
|||||
// Use require.context to require reducers automatically
|
|
||||
// Ref: https://webpack.js.org/guides/dependency-management/#require-context
|
|
||||
const context = require.context('./', false, /\.js$/); |
|
||||
export default context |
|
||||
.keys() |
|
||||
.filter(item => item !== './index.js') |
|
||||
.map(key => context(key)); |
|
||||
@ -1,414 +0,0 @@ |
|||||
import React, { PureComponent } from 'react'; |
|
||||
import { connect } from 'dva'; |
|
||||
import { Link } from 'dva/router'; |
|
||||
import moment from 'moment'; |
|
||||
import numeral from 'numeral'; |
|
||||
import { |
|
||||
List, |
|
||||
Card, |
|
||||
Row, |
|
||||
Col, |
|
||||
Icon, |
|
||||
Dropdown, |
|
||||
Menu, |
|
||||
Avatar, |
|
||||
Tag, |
|
||||
Divider, |
|
||||
Tooltip, |
|
||||
Spin, |
|
||||
Input, |
|
||||
} from 'antd'; |
|
||||
import AvatarList from '../../components/AvatarList'; |
|
||||
import { formatWan } from '../../utils/utils'; |
|
||||
import stylesProjects from '../List/Projects.less'; |
|
||||
import styles from './Center.less'; |
|
||||
import stylesArticles from '../List/Articles.less'; |
|
||||
import stylesApplications from '../List/Applications.less'; |
|
||||
import GridContent from '../../layouts/GridContent'; |
|
||||
|
|
||||
@connect(({ list, loading, user, project }) => ({ |
|
||||
list, |
|
||||
listLoading: loading.effects['list/fetch'], |
|
||||
currentUser: user.currentUser, |
|
||||
currentUserLoading: loading.effects['user/fetchCurrent'], |
|
||||
project, |
|
||||
projectLoading: loading.effects['project/fetchNotice'], |
|
||||
})) |
|
||||
export default class Center extends PureComponent { |
|
||||
state = { |
|
||||
key: 'article', |
|
||||
newTags: [], |
|
||||
inputVisible: false, |
|
||||
inputValue: '', |
|
||||
}; |
|
||||
|
|
||||
componentDidMount() { |
|
||||
const { dispatch } = this.props; |
|
||||
dispatch({ |
|
||||
type: 'user/fetchCurrent', |
|
||||
}); |
|
||||
dispatch({ |
|
||||
type: 'list/fetch', |
|
||||
payload: { |
|
||||
count: 8, |
|
||||
}, |
|
||||
}); |
|
||||
dispatch({ |
|
||||
type: 'project/fetchNotice', |
|
||||
}); |
|
||||
} |
|
||||
|
|
||||
onTabChange = key => { |
|
||||
this.setState({ key }); |
|
||||
}; |
|
||||
|
|
||||
showInput = () => { |
|
||||
this.setState({ inputVisible: true }, () => this.input.focus()); |
|
||||
}; |
|
||||
|
|
||||
saveInputRef = input => { |
|
||||
this.input = input; |
|
||||
}; |
|
||||
|
|
||||
handleInputChange = e => { |
|
||||
this.setState({ inputValue: e.target.value }); |
|
||||
}; |
|
||||
|
|
||||
handleInputConfirm = () => { |
|
||||
const { state } = this; |
|
||||
const { inputValue } = state; |
|
||||
let { newTags } = state; |
|
||||
if (inputValue && newTags.filter(tag => tag.label === inputValue).length === 0) { |
|
||||
newTags = [...newTags, { key: `new-${newTags.length}`, label: inputValue }]; |
|
||||
} |
|
||||
this.setState({ |
|
||||
newTags, |
|
||||
inputVisible: false, |
|
||||
inputValue: '', |
|
||||
}); |
|
||||
}; |
|
||||
|
|
||||
renderArticles = (list, loading) => { |
|
||||
const IconText = ({ type, text }) => ( |
|
||||
<span> |
|
||||
<Icon type={type} style={{ marginRight: 8 }} /> |
|
||||
{text} |
|
||||
</span> |
|
||||
); |
|
||||
const ListContent = ({ data: { content, updatedAt, avatar, owner, href } }) => ( |
|
||||
<div className={stylesArticles.listContent}> |
|
||||
<div className={stylesArticles.description}>{content}</div> |
|
||||
<div className={stylesArticles.extra}> |
|
||||
<Avatar src={avatar} size="small" /> |
|
||||
<a href={href}>{owner}</a> 发布在 <a href={href}>{href}</a> |
|
||||
<em>{moment(updatedAt).format('YYYY-MM-DD HH:mm')}</em> |
|
||||
</div> |
|
||||
</div> |
|
||||
); |
|
||||
return ( |
|
||||
<List |
|
||||
size="large" |
|
||||
className={styles.articleList} |
|
||||
loading={loading} |
|
||||
rowKey="id" |
|
||||
itemLayout="vertical" |
|
||||
dataSource={list} |
|
||||
renderItem={item => ( |
|
||||
<List.Item |
|
||||
key={item.id} |
|
||||
actions={[ |
|
||||
<IconText type="star-o" text={item.star} />, |
|
||||
<IconText type="like-o" text={item.like} />, |
|
||||
<IconText type="message" text={item.message} />, |
|
||||
]} |
|
||||
> |
|
||||
<List.Item.Meta |
|
||||
title={ |
|
||||
<a className={stylesArticles.listItemMetaTitle} href={item.href}> |
|
||||
{item.title} |
|
||||
</a> |
|
||||
} |
|
||||
description={ |
|
||||
<span> |
|
||||
<Tag>Ant Design</Tag> |
|
||||
<Tag>设计语言</Tag> |
|
||||
<Tag>蚂蚁金服</Tag> |
|
||||
</span> |
|
||||
} |
|
||||
/> |
|
||||
<ListContent data={item} /> |
|
||||
</List.Item> |
|
||||
)} |
|
||||
/> |
|
||||
); |
|
||||
}; |
|
||||
|
|
||||
renderApplications = (list, loading) => { |
|
||||
const itemMenu = ( |
|
||||
<Menu> |
|
||||
<Menu.Item> |
|
||||
<a target="_blank" rel="noopener noreferrer" href="http://www.alipay.com/"> |
|
||||
1st menu item |
|
||||
</a> |
|
||||
</Menu.Item> |
|
||||
<Menu.Item> |
|
||||
<a target="_blank" rel="noopener noreferrer" href="http://www.taobao.com/"> |
|
||||
2nd menu item |
|
||||
</a> |
|
||||
</Menu.Item> |
|
||||
<Menu.Item> |
|
||||
<a target="_blank" rel="noopener noreferrer" href="http://www.tmall.com/"> |
|
||||
3d menu item |
|
||||
</a> |
|
||||
</Menu.Item> |
|
||||
</Menu> |
|
||||
); |
|
||||
const CardInfo = ({ activeUser, newUser }) => ( |
|
||||
<div className={stylesApplications.cardInfo}> |
|
||||
<div> |
|
||||
<p>活跃用户</p> |
|
||||
<p>{activeUser}</p> |
|
||||
</div> |
|
||||
<div> |
|
||||
<p>新增用户</p> |
|
||||
<p>{newUser}</p> |
|
||||
</div> |
|
||||
</div> |
|
||||
); |
|
||||
return ( |
|
||||
<List |
|
||||
rowKey="id" |
|
||||
className={stylesApplications.filterCardList} |
|
||||
grid={{ gutter: 24, xxl: 3, xl: 2, lg: 2, md: 2, sm: 2, xs: 1 }} |
|
||||
loading={loading} |
|
||||
dataSource={list} |
|
||||
renderItem={item => ( |
|
||||
<List.Item key={item.id}> |
|
||||
<Card |
|
||||
hoverable |
|
||||
bodyStyle={{ paddingBottom: 20 }} |
|
||||
actions={[ |
|
||||
<Tooltip title="下载"> |
|
||||
<Icon type="download" /> |
|
||||
</Tooltip>, |
|
||||
<Tooltip title="编辑"> |
|
||||
<Icon type="edit" /> |
|
||||
</Tooltip>, |
|
||||
<Tooltip title="分享"> |
|
||||
<Icon type="share-alt" /> |
|
||||
</Tooltip>, |
|
||||
<Dropdown overlay={itemMenu}> |
|
||||
<Icon type="ellipsis" /> |
|
||||
</Dropdown>, |
|
||||
]} |
|
||||
> |
|
||||
<Card.Meta avatar={<Avatar size="small" src={item.avatar} />} title={item.title} /> |
|
||||
<div className={stylesApplications.cardItemContent}> |
|
||||
<CardInfo |
|
||||
activeUser={formatWan(item.activeUser)} |
|
||||
newUser={numeral(item.newUser).format('0,0')} |
|
||||
/> |
|
||||
</div> |
|
||||
</Card> |
|
||||
</List.Item> |
|
||||
)} |
|
||||
/> |
|
||||
); |
|
||||
}; |
|
||||
|
|
||||
renderProjects = (list, loading) => { |
|
||||
return ( |
|
||||
<List |
|
||||
className={stylesProjects.coverCardList} |
|
||||
rowKey="id" |
|
||||
loading={loading} |
|
||||
grid={{ gutter: 24, xxl: 3, xl: 2, lg: 2, md: 2, sm: 2, xs: 1 }} |
|
||||
dataSource={list} |
|
||||
renderItem={item => ( |
|
||||
<List.Item> |
|
||||
<Card |
|
||||
className={stylesProjects.card} |
|
||||
hoverable |
|
||||
cover={<img alt={item.title} src={item.cover} />} |
|
||||
> |
|
||||
<Card.Meta title={<a href="#">{item.title}</a>} description={item.subDescription} /> |
|
||||
<div className={stylesProjects.cardItemContent}> |
|
||||
<span>{moment(item.updatedAt).fromNow()}</span> |
|
||||
<div className={stylesProjects.avatarList}> |
|
||||
<AvatarList size="mini"> |
|
||||
{item.members.map(member => ( |
|
||||
<AvatarList.Item |
|
||||
key={`${item.id}-avatar-${member.id}`} |
|
||||
src={member.avatar} |
|
||||
tips={member.name} |
|
||||
/> |
|
||||
))} |
|
||||
</AvatarList> |
|
||||
</div> |
|
||||
</div> |
|
||||
</Card> |
|
||||
</List.Item> |
|
||||
)} |
|
||||
/> |
|
||||
); |
|
||||
}; |
|
||||
|
|
||||
renderContent() { |
|
||||
const { newTags, inputVisible, inputValue } = this.state; |
|
||||
const { |
|
||||
currentUser, |
|
||||
project: { notice }, |
|
||||
projectLoading, |
|
||||
} = this.props; |
|
||||
return ( |
|
||||
<div> |
|
||||
<div className={styles.avatarHolder}> |
|
||||
<img alt="" src={currentUser.avatar} /> |
|
||||
<div className={styles.name}>{currentUser.name}</div> |
|
||||
<div>{currentUser.signature}</div> |
|
||||
</div> |
|
||||
<div className={styles.detail}> |
|
||||
<p> |
|
||||
<i className={styles.title} /> |
|
||||
{currentUser.title} |
|
||||
</p> |
|
||||
<p> |
|
||||
<i className={styles.group} /> |
|
||||
{currentUser.group} |
|
||||
</p> |
|
||||
<p> |
|
||||
<i className={styles.address} /> |
|
||||
{currentUser.geographic.province.label} |
|
||||
{currentUser.geographic.city.label} |
|
||||
</p> |
|
||||
</div> |
|
||||
<Divider dashed /> |
|
||||
<div className={styles.tags}> |
|
||||
<div className={styles.tagsTitle}>标签</div> |
|
||||
{currentUser.tags.map(item => <Tag key={item.key}>{item.label}</Tag>)} |
|
||||
<Tag style={{ background: '#fff', borderStyle: 'dashed' }}> |
|
||||
<Icon type="plus" /> |
|
||||
</Tag> |
|
||||
</div> |
|
||||
<Divider dashed /> |
|
||||
<div className={styles.team}> |
|
||||
<div className={styles.teamTitle}>团队</div> |
|
||||
<Spin spinning={projectLoading}> |
|
||||
<Row gutter={36}> |
|
||||
{notice.map(item => ( |
|
||||
<Col key={item.id} className={styles.item} lg={24} xl={12}> |
|
||||
<Avatar size="small" src={item.logo} /> |
|
||||
{item.member} |
|
||||
</Col> |
|
||||
))} |
|
||||
</Row> |
|
||||
</Spin> |
|
||||
</div> |
|
||||
<Divider dashed /> |
|
||||
<div className={styles.tags}> |
|
||||
<div className={styles.tagsTitle}>标签</div> |
|
||||
{currentUser.tags.concat(newTags).map(item => <Tag key={item.key}>{item.label}</Tag>)} |
|
||||
{inputVisible && ( |
|
||||
<Input |
|
||||
ref={this.saveInputRef} |
|
||||
type="text" |
|
||||
size="small" |
|
||||
style={{ width: 78 }} |
|
||||
value={inputValue} |
|
||||
onChange={this.handleInputChange} |
|
||||
onBlur={this.handleInputConfirm} |
|
||||
onPressEnter={this.handleInputConfirm} |
|
||||
/> |
|
||||
)} |
|
||||
{!inputVisible && ( |
|
||||
<Tag onClick={this.showInput} style={{ background: '#fff', borderStyle: 'dashed' }}> |
|
||||
<Icon type="plus" /> |
|
||||
</Tag> |
|
||||
)} |
|
||||
</div> |
|
||||
<Divider style={{ marginTop: 16 }} dashed /> |
|
||||
<div className={styles.team}> |
|
||||
<div className={styles.teamTitle}>团队</div> |
|
||||
<Spin spinning={projectLoading}> |
|
||||
<Row gutter={36}> |
|
||||
{notice.map(item => ( |
|
||||
<Col key={item.id} lg={24} xl={12}> |
|
||||
<Link to={item.href}> |
|
||||
<Avatar size="small" src={item.logo} /> |
|
||||
{item.member} |
|
||||
</Link> |
|
||||
</Col> |
|
||||
))} |
|
||||
</Row> |
|
||||
</Spin> |
|
||||
</div> |
|
||||
</div> |
|
||||
); |
|
||||
} |
|
||||
|
|
||||
render() { |
|
||||
const { |
|
||||
list: { list }, |
|
||||
listLoading, |
|
||||
currentUser, |
|
||||
currentUserLoading, |
|
||||
} = this.props; |
|
||||
const operationTabList = [ |
|
||||
{ |
|
||||
key: 'article', |
|
||||
tab: ( |
|
||||
<span> |
|
||||
文章 <span style={{ fontSize: 14 }}>(8)</span> |
|
||||
</span> |
|
||||
), |
|
||||
}, |
|
||||
{ |
|
||||
key: 'application', |
|
||||
tab: ( |
|
||||
<span> |
|
||||
应用 <span style={{ fontSize: 14 }}>(8)</span> |
|
||||
</span> |
|
||||
), |
|
||||
}, |
|
||||
{ |
|
||||
key: 'project', |
|
||||
tab: ( |
|
||||
<span> |
|
||||
项目 <span style={{ fontSize: 14 }}>(8)</span> |
|
||||
</span> |
|
||||
), |
|
||||
}, |
|
||||
]; |
|
||||
const contentMap = { |
|
||||
article: this.renderArticles(list, listLoading), |
|
||||
application: this.renderApplications(list, listLoading), |
|
||||
project: this.renderProjects(list, listLoading), |
|
||||
}; |
|
||||
const { key } = this.state; |
|
||||
return ( |
|
||||
<GridContent> |
|
||||
<div className={styles.userCenter}> |
|
||||
<Row gutter={24}> |
|
||||
<Col lg={7} md={24}> |
|
||||
<Card bordered={false} style={{ marginBottom: 24 }} loading={currentUserLoading}> |
|
||||
{currentUser && Object.keys(currentUser).length |
|
||||
? this.renderContent() |
|
||||
: 'loading...'} |
|
||||
</Card> |
|
||||
</Col> |
|
||||
<Col lg={17} md={24}> |
|
||||
<Card |
|
||||
className={styles.tabsCard} |
|
||||
bordered={false} |
|
||||
tabList={operationTabList} |
|
||||
onTabChange={this.onTabChange} |
|
||||
> |
|
||||
{contentMap[key]} |
|
||||
</Card> |
|
||||
</Col> |
|
||||
</Row> |
|
||||
</div> |
|
||||
</GridContent> |
|
||||
); |
|
||||
} |
|
||||
} |
|
||||
Loading…
Reference in new issue