|
|
|
@ -3,14 +3,28 @@ 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 { |
|
|
|
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 styles from './UserCenter.less'; |
|
|
|
import stylesArticles from '../List/Articles.less'; |
|
|
|
import stylesApplications from '../List/Applications.less'; |
|
|
|
import stylesProjects from '../List/Projects.less'; |
|
|
|
import stylesArticles from './List/Articles.less'; |
|
|
|
import stylesApplications from './List/Applications.less'; |
|
|
|
import GridContent from '../layouts/GridContent'; |
|
|
|
|
|
|
|
@connect(({ list, loading, user, project }) => ({ |
|
|
|
list, |
|
|
|
@ -26,7 +40,7 @@ export default class UserCenter extends PureComponent { |
|
|
|
newTags: [], |
|
|
|
inputVisible: false, |
|
|
|
inputValue: '', |
|
|
|
} |
|
|
|
}; |
|
|
|
|
|
|
|
componentDidMount() { |
|
|
|
const { dispatch } = this.props; |
|
|
|
@ -46,33 +60,39 @@ export default class UserCenter extends PureComponent { |
|
|
|
|
|
|
|
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 }]; |
|
|
|
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 }) => ( |
|
|
|
@ -81,11 +101,14 @@ export default class UserCenter extends PureComponent { |
|
|
|
{text} |
|
|
|
</span> |
|
|
|
); |
|
|
|
const ListContent = ({ data: { content, updatedAt, avatar, owner, href } }) => ( |
|
|
|
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> |
|
|
|
<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> |
|
|
|
@ -108,9 +131,14 @@ export default class UserCenter extends PureComponent { |
|
|
|
]} |
|
|
|
> |
|
|
|
<List.Item.Meta |
|
|
|
title={( |
|
|
|
<a className={stylesArticles.listItemMetaTitle} href={item.href}>{item.title}</a> |
|
|
|
)} |
|
|
|
title={ |
|
|
|
<a |
|
|
|
className={stylesArticles.listItemMetaTitle} |
|
|
|
href={item.href} |
|
|
|
> |
|
|
|
{item.title} |
|
|
|
</a> |
|
|
|
} |
|
|
|
description={ |
|
|
|
<span> |
|
|
|
<Tag>Ant Design</Tag> |
|
|
|
@ -124,19 +152,37 @@ export default class UserCenter extends PureComponent { |
|
|
|
)} |
|
|
|
/> |
|
|
|
); |
|
|
|
} |
|
|
|
}; |
|
|
|
|
|
|
|
renderApplications = (list, loading) => { |
|
|
|
const itemMenu = ( |
|
|
|
<Menu> |
|
|
|
<Menu.Item> |
|
|
|
<a target="_blank" rel="noopener noreferrer" href="http://www.alipay.com/">1st menu item</a> |
|
|
|
<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> |
|
|
|
<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> |
|
|
|
<a |
|
|
|
target="_blank" |
|
|
|
rel="noopener noreferrer" |
|
|
|
href="http://www.tmall.com/" |
|
|
|
> |
|
|
|
3d menu item |
|
|
|
</a> |
|
|
|
</Menu.Item> |
|
|
|
</Menu> |
|
|
|
); |
|
|
|
@ -165,10 +211,18 @@ export default class UserCenter extends PureComponent { |
|
|
|
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>, |
|
|
|
<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 |
|
|
|
@ -186,7 +240,7 @@ export default class UserCenter extends PureComponent { |
|
|
|
)} |
|
|
|
/> |
|
|
|
); |
|
|
|
} |
|
|
|
}; |
|
|
|
|
|
|
|
renderProjects = (list, loading) => { |
|
|
|
return ( |
|
|
|
@ -211,15 +265,13 @@ export default class UserCenter extends PureComponent { |
|
|
|
<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} |
|
|
|
/> |
|
|
|
)) |
|
|
|
} |
|
|
|
{item.members.map(member => ( |
|
|
|
<AvatarList.Item |
|
|
|
key={`${item.id}-avatar-${member.id}`} |
|
|
|
src={member.avatar} |
|
|
|
tips={member.name} |
|
|
|
/> |
|
|
|
))} |
|
|
|
</AvatarList> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
@ -228,22 +280,137 @@ export default class UserCenter extends PureComponent { |
|
|
|
)} |
|
|
|
/> |
|
|
|
); |
|
|
|
}; |
|
|
|
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 { key, newTags, inputVisible, inputValue } = this.state; |
|
|
|
const { list: { list }, listLoading, currentUser, currentUserLoading, |
|
|
|
project: { notice }, projectLoading } = 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 { |
|
|
|
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), |
|
|
|
@ -251,94 +418,33 @@ export default class UserCenter extends PureComponent { |
|
|
|
}; |
|
|
|
|
|
|
|
return ( |
|
|
|
<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 ? |
|
|
|
( |
|
|
|
<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.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> |
|
|
|
) : '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> |
|
|
|
<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[this.state.key]} |
|
|
|
</Card> |
|
|
|
</Col> |
|
|
|
</Row> |
|
|
|
</div> |
|
|
|
</GridContent> |
|
|
|
); |
|
|
|
} |
|
|
|
} |
|
|
|
|