mirror of
https://github.com/zuiidea/antd-admin.git
synced 2026-10-19 16:14:37 +00:00
Translation user and post page.
This commit is contained in:
+8
-1
@@ -17,17 +17,24 @@ export function randomNumber(min, max) {
|
||||
}
|
||||
|
||||
export function randomAvatar() {
|
||||
// https://uifaces.co
|
||||
const avatarList = [
|
||||
'https://randomuser.me/api/portraits/men/32.jpg',
|
||||
'https://images.pexels.com/photos/415829/pexels-photo-415829.jpeg?h=350&auto=compress&cs=tinysrgb',
|
||||
'https://d3iw72m71ie81c.cloudfront.net/female-17.jpg',
|
||||
'https://randomuser.me/api/portraits/men/35.jpg',
|
||||
'https://pbs.twimg.com/profile_images/835224725815246848/jdMBCxHS.jpg',
|
||||
'https://pbs.twimg.com/profile_images/1010888664732200962/OmFg5TO0.jpg',
|
||||
'https://pbs.twimg.com/profile_images/584098247641300992/N25WgvW_.png',
|
||||
'https://d3iw72m71ie81c.cloudfront.net/male-5.jpg',
|
||||
'https://images.pexels.com/photos/413723/pexels-photo-413723.jpeg?h=350&auto=compress&cs=tinysrgb',
|
||||
'https://images.pexels.com/photos/61100/pexels-photo-61100.jpeg?h=350&auto=compress&cs=tinysrgb',
|
||||
'https://randomuser.me/api/portraits/women/44.jpg',
|
||||
'https://randomuser.me/api/portraits/women/68.jpg',
|
||||
'https://randomuser.me/api/portraits/women/65.jpg',
|
||||
'https://randomuser.me/api/portraits/men/43.jpg',
|
||||
'https://tinyfac.es/data/avatars/475605E3-69C5-4D2B-8727-61B7BB8C4699-500w.jpeg',
|
||||
'https://pbs.twimg.com/profile_images/943227488292962306/teiNNAiy.jpg',
|
||||
'https://randomuser.me/api/portraits/men/46.jpg'
|
||||
]
|
||||
return avatarList[randomNumber(0, avatarList.length - 1)]
|
||||
}
|
||||
|
||||
+1
-7
@@ -15,13 +15,7 @@ let usersListData = Mock.mock({
|
||||
email: '@email',
|
||||
createTime: '@datetime',
|
||||
avatar() {
|
||||
return Mock.Random.image(
|
||||
'100x100',
|
||||
Mock.Random.color(),
|
||||
'#757575',
|
||||
'png',
|
||||
this.nickName.substr(0, 1)
|
||||
)
|
||||
return randomAvatar()
|
||||
},
|
||||
},
|
||||
],
|
||||
|
||||
@@ -1,14 +1,54 @@
|
||||
{
|
||||
"/dashboard": "/dashboard",
|
||||
"Add Param": "Add Param",
|
||||
"Address": "Address",
|
||||
"Age": "Age",
|
||||
"Are you sure delete this record?": "Are you sure delete this record?",
|
||||
"Author": "Author",
|
||||
"Avatar": "Avatar",
|
||||
"Categories": "Categories",
|
||||
"Clear notifications": "Clear notifications",
|
||||
"Comments": "Comments",
|
||||
"Create": "Create",
|
||||
"Create User": "Create User",
|
||||
"CreateTime": "CreateTime",
|
||||
"Dark": "Dark",
|
||||
"Delete": "Delete",
|
||||
"Email": "Email",
|
||||
"Female": "Female",
|
||||
"Gender": "Gender",
|
||||
"Hi,": "Hi,",
|
||||
"Image": "Image",
|
||||
"Light": "Light",
|
||||
"Male": "Male",
|
||||
"Name": "Name",
|
||||
"NickName": "NickName",
|
||||
"Not Found": "Not Found",
|
||||
"Operation": "Operation",
|
||||
"Params": "Params",
|
||||
"Password": "Password",
|
||||
"Phone": "Phone",
|
||||
"Pick an address": "Pick an address",
|
||||
"Please pick an address": "Please pick an address",
|
||||
"Publised": "Publised",
|
||||
"Publish Date": "Publish Date",
|
||||
"Reset": "Reset",
|
||||
"Search": "Search",
|
||||
"Search Name": "Search Name",
|
||||
"Send": "Send",
|
||||
"Sign in": "Sign in",
|
||||
"Sign out": "Sign out",
|
||||
"Switch Theme": "Switch Theme",
|
||||
"Tags": "Tags",
|
||||
"The input is not valid E-mail!": "The input is not valid E-mail!",
|
||||
"The input is not valid phone!": "The input is not valid phone!",
|
||||
"Title": "Title",
|
||||
"Total {total} Items": "Total {total} Items",
|
||||
"Unpublished": "Unpublished",
|
||||
"Update": "Update",
|
||||
"Update User": "Update User",
|
||||
"Username": "Username",
|
||||
"Views": "Views",
|
||||
"Visibility": "Visibility",
|
||||
"You have viewed all notifications.": "You have viewed all notifications."
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,54 @@
|
||||
{
|
||||
"/dashboard": "/zh/dashboard",
|
||||
"Add Param": "添加参数",
|
||||
"Address": "地址",
|
||||
"Age": "年龄",
|
||||
"Are you sure delete this record?": "您确定要删除这条记录吗?",
|
||||
"Author": "作者",
|
||||
"Avatar": "头像",
|
||||
"Categories": "类别",
|
||||
"Clear notifications": "清空消息",
|
||||
"Comments": "评论数",
|
||||
"Create": "创建",
|
||||
"Create User": "创建用户",
|
||||
"CreateTime": "创建时间",
|
||||
"Dark": "暗",
|
||||
"Delete": "删除",
|
||||
"Email": "电子邮件",
|
||||
"Female": "女",
|
||||
"Gender": "性别",
|
||||
"Hi,": "你好,",
|
||||
"Image": "图像",
|
||||
"Light": "明",
|
||||
"Male": "男性",
|
||||
"Name": "名字",
|
||||
"NickName": "昵称",
|
||||
"Not Found": "未找到",
|
||||
"Operation": "操作",
|
||||
"Params": "参数",
|
||||
"Password": "密码",
|
||||
"Phone": "电话",
|
||||
"Pick an address": "选择地址",
|
||||
"Please pick an address": "选择地址",
|
||||
"Publised": "已发布",
|
||||
"Publish Date": "发布日期",
|
||||
"Reset": "重置",
|
||||
"Search": "搜索",
|
||||
"Search Name": "搜索名字",
|
||||
"Send": "发送",
|
||||
"Sign in": "登录",
|
||||
"Sign out": "退出登录",
|
||||
"Switch Theme": "切换主题",
|
||||
"Tags": "标签",
|
||||
"The input is not valid E-mail!": "输入的电子邮件无效!",
|
||||
"The input is not valid phone!": "输入无效的手机!",
|
||||
"Title": "标题",
|
||||
"Total {total} Items": "总共 {total} 条记录",
|
||||
"Unpublished": "未发布",
|
||||
"Update": "更新",
|
||||
"Update User": "更新用户",
|
||||
"Username": "用户名",
|
||||
"Views": "浏览数",
|
||||
"Visibility": "可见性",
|
||||
"You have viewed all notifications.": "您已查看所有通知"
|
||||
}
|
||||
}
|
||||
@@ -1,63 +1,69 @@
|
||||
import React from 'react'
|
||||
import { Table } from 'antd'
|
||||
import styles from './List.less'
|
||||
import React, { PureComponent } from 'react'
|
||||
import { Table, Avatar } from 'antd'
|
||||
import { withI18n } from '@lingui/react'
|
||||
|
||||
const List = ({ ...tableProps }) => {
|
||||
const columns = [
|
||||
{
|
||||
title: 'Image',
|
||||
dataIndex: 'image',
|
||||
className: styles.image,
|
||||
width: 64,
|
||||
render: text => <img alt="Feture" width={26} src={text} />,
|
||||
},
|
||||
{
|
||||
title: 'Title',
|
||||
dataIndex: 'title',
|
||||
},
|
||||
{
|
||||
title: 'Author',
|
||||
dataIndex: 'author',
|
||||
},
|
||||
{
|
||||
title: 'Categories',
|
||||
dataIndex: 'categories',
|
||||
},
|
||||
{
|
||||
title: 'Tags',
|
||||
dataIndex: 'tags',
|
||||
},
|
||||
{
|
||||
title: 'Visibility',
|
||||
dataIndex: 'visibility',
|
||||
},
|
||||
{
|
||||
title: 'Comments',
|
||||
dataIndex: 'comments',
|
||||
},
|
||||
{
|
||||
title: 'Views',
|
||||
dataIndex: 'views',
|
||||
},
|
||||
{
|
||||
title: 'Date',
|
||||
dataIndex: 'date',
|
||||
},
|
||||
]
|
||||
@withI18n()
|
||||
class List extends PureComponent {
|
||||
render() {
|
||||
const { i18n, ...tableProps } = this.props
|
||||
const columns = [
|
||||
{
|
||||
title: i18n.t`Image`,
|
||||
dataIndex: 'image',
|
||||
width: 100,
|
||||
render: text => <Avatar shape="square" src={text} />,
|
||||
},
|
||||
{
|
||||
title: i18n.t`Title`,
|
||||
dataIndex: 'title',
|
||||
},
|
||||
{
|
||||
title: i18n.t`Author`,
|
||||
dataIndex: 'author',
|
||||
},
|
||||
{
|
||||
title: i18n.t`Categories`,
|
||||
dataIndex: 'categories',
|
||||
},
|
||||
{
|
||||
title: i18n.t`Tags`,
|
||||
dataIndex: 'tags',
|
||||
},
|
||||
{
|
||||
title: i18n.t`Visibility`,
|
||||
dataIndex: 'visibility',
|
||||
},
|
||||
{
|
||||
title: i18n.t`Comments`,
|
||||
dataIndex: 'comments',
|
||||
},
|
||||
{
|
||||
title: i18n.t`Views`,
|
||||
dataIndex: 'views',
|
||||
},
|
||||
{
|
||||
title: i18n.t`Publish Date`,
|
||||
dataIndex: 'date',
|
||||
},
|
||||
]
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Table
|
||||
{...tableProps}
|
||||
bordered
|
||||
scroll={{ x: 1200 }}
|
||||
columns={columns}
|
||||
simple
|
||||
className={styles.table}
|
||||
rowKey={record => record.id}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
return (
|
||||
<div>
|
||||
<Table
|
||||
{...tableProps}
|
||||
pagination={{
|
||||
...tableProps.pagination,
|
||||
showTotal: total => i18n.t`Total ${total} Items`,
|
||||
}}
|
||||
bordered
|
||||
scroll={{ x: 1200 }}
|
||||
columns={columns}
|
||||
simple
|
||||
rowKey={record => record.id}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default List
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
.table {
|
||||
td.image {
|
||||
line-height: 1;
|
||||
|
||||
img {
|
||||
border-radius: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
:global {
|
||||
.ant-table-tbody > tr > td,
|
||||
.ant-table-thead > tr > th {
|
||||
height: 60px;
|
||||
}
|
||||
}
|
||||
}
|
||||
+11
-3
@@ -4,6 +4,7 @@ import { connect } from 'dva'
|
||||
import { Tabs } from 'antd'
|
||||
import { router } from 'utils'
|
||||
import { stringify } from 'qs'
|
||||
import { withI18n } from '@lingui/react'
|
||||
import { Page } from 'components'
|
||||
import List from './components/List'
|
||||
|
||||
@@ -14,10 +15,11 @@ const EnumPostStatus = {
|
||||
PUBLISHED: 2,
|
||||
}
|
||||
|
||||
@withI18n()
|
||||
@connect(({ post, loading }) => ({ post, loading }))
|
||||
class Post extends PureComponent {
|
||||
render() {
|
||||
const { post, loading, location } = this.props
|
||||
const { post, loading, location, i18n } = this.props
|
||||
const { list, pagination } = post
|
||||
const { query, pathname } = location
|
||||
|
||||
@@ -56,10 +58,16 @@ class Post extends PureComponent {
|
||||
}
|
||||
onTabClick={handleTabClick}
|
||||
>
|
||||
<TabPane tab="Publised" key={String(EnumPostStatus.PUBLISHED)}>
|
||||
<TabPane
|
||||
tab={i18n.t`Publised`}
|
||||
key={String(EnumPostStatus.PUBLISHED)}
|
||||
>
|
||||
<List {...listProps} />
|
||||
</TabPane>
|
||||
<TabPane tab="Unpublish" key={String(EnumPostStatus.UNPUBLISH)}>
|
||||
<TabPane
|
||||
tab={i18n.t`Unpublished`}
|
||||
key={String(EnumPostStatus.UNPUBLISH)}
|
||||
>
|
||||
<List {...listProps} />
|
||||
</TabPane>
|
||||
</Tabs>
|
||||
|
||||
@@ -237,7 +237,9 @@ class RequestPage extends React.Component {
|
||||
))}
|
||||
|
||||
<Row style={{ marginTop: 8 }}>
|
||||
<Button onClick={this.handleAddField}>Add Param</Button>
|
||||
<Button onClick={this.handleAddField}>
|
||||
<Trans>Add Param</Trans>
|
||||
</Button>
|
||||
</Row>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import React, { PureComponent } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { connect } from 'dva'
|
||||
import { Page } from 'components'
|
||||
import styles from './index.less'
|
||||
|
||||
@connect(({ userDetail }) => ({ userDetail }))
|
||||
@@ -20,9 +21,9 @@ class UserDetail extends PureComponent {
|
||||
}
|
||||
}
|
||||
return (
|
||||
<div className="content-inner">
|
||||
<Page inner>
|
||||
<div className={styles.content}>{content}</div>
|
||||
</div>
|
||||
</Page>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
/* global document */
|
||||
import React from 'react'
|
||||
import React, { PureComponent } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import moment from 'moment'
|
||||
import { FilterItem } from 'components'
|
||||
import { Trans, withI18n } from '@lingui/react'
|
||||
import { Form, Button, Row, Col, DatePicker, Input, Cascader } from 'antd'
|
||||
import city from 'utils/city'
|
||||
|
||||
@@ -22,13 +23,10 @@ const TwoColProps = {
|
||||
xl: 96,
|
||||
}
|
||||
|
||||
const Filter = ({
|
||||
onAdd,
|
||||
onFilterChange,
|
||||
filter,
|
||||
form: { getFieldDecorator, getFieldsValue, setFieldsValue },
|
||||
}) => {
|
||||
const handleFields = fields => {
|
||||
@withI18n()
|
||||
@Form.create()
|
||||
class Filter extends PureComponent {
|
||||
handleFields = fields => {
|
||||
const { createTime } = fields
|
||||
if (createTime.length) {
|
||||
fields.createTime = [
|
||||
@@ -39,13 +37,19 @@ const Filter = ({
|
||||
return fields
|
||||
}
|
||||
|
||||
const handleSubmit = () => {
|
||||
handleSubmit = () => {
|
||||
const { onFilterChange, form } = this.props
|
||||
const { getFieldsValue } = form
|
||||
|
||||
let fields = getFieldsValue()
|
||||
fields = handleFields(fields)
|
||||
fields = this.handleFields(fields)
|
||||
onFilterChange(fields)
|
||||
}
|
||||
|
||||
const handleReset = () => {
|
||||
handleReset = () => {
|
||||
const { form } = this.props
|
||||
const { getFieldsValue, setFieldsValue } = form
|
||||
|
||||
const fields = getFieldsValue()
|
||||
for (let item in fields) {
|
||||
if ({}.hasOwnProperty.call(fields, item)) {
|
||||
@@ -57,86 +61,107 @@ const Filter = ({
|
||||
}
|
||||
}
|
||||
setFieldsValue(fields)
|
||||
handleSubmit()
|
||||
this.handleSubmit()
|
||||
}
|
||||
handleChange = (key, values) => {
|
||||
const { form, onFilterChange } = this.props
|
||||
const { getFieldsValue } = form
|
||||
|
||||
const handleChange = (key, values) => {
|
||||
let fields = getFieldsValue()
|
||||
fields[key] = values
|
||||
fields = handleFields(fields)
|
||||
fields = this.handleFields(fields)
|
||||
onFilterChange(fields)
|
||||
}
|
||||
const { name, address } = filter
|
||||
|
||||
let initialCreateTime = []
|
||||
if (filter.createTime && filter.createTime[0]) {
|
||||
initialCreateTime[0] = moment(filter.createTime[0])
|
||||
}
|
||||
if (filter.createTime && filter.createTime[1]) {
|
||||
initialCreateTime[1] = moment(filter.createTime[1])
|
||||
}
|
||||
render() {
|
||||
const { onAdd, filter, form, i18n } = this.props
|
||||
const { getFieldDecorator } = form
|
||||
const { name, address } = filter
|
||||
|
||||
return (
|
||||
<Row gutter={24}>
|
||||
<Col {...ColProps} xl={{ span: 4 }} md={{ span: 8 }}>
|
||||
{getFieldDecorator('name', { initialValue: name })(
|
||||
<Search placeholder="Search Name" onSearch={handleSubmit} />
|
||||
)}
|
||||
</Col>
|
||||
<Col {...ColProps} xl={{ span: 4 }} md={{ span: 8 }} id="addressCascader">
|
||||
{getFieldDecorator('address', { initialValue: address })(
|
||||
<Cascader
|
||||
style={{ width: '100%' }}
|
||||
options={city}
|
||||
placeholder="Please pick an address"
|
||||
onChange={handleChange.bind(null, 'address')}
|
||||
getPopupContainer={() => document.getElementById('addressCascader')}
|
||||
/>
|
||||
)}
|
||||
</Col>
|
||||
<Col
|
||||
{...ColProps}
|
||||
xl={{ span: 6 }}
|
||||
md={{ span: 8 }}
|
||||
sm={{ span: 12 }}
|
||||
id="createTimeRangePicker"
|
||||
>
|
||||
<FilterItem label="Createtime">
|
||||
{getFieldDecorator('createTime', { initialValue: initialCreateTime })(
|
||||
<RangePicker
|
||||
style={{ width: '100%' }}
|
||||
onChange={handleChange.bind(null, 'createTime')}
|
||||
getCalendarContainer={() => {
|
||||
return document.getElementById('createTimeRangePicker')
|
||||
}}
|
||||
let initialCreateTime = []
|
||||
if (filter.createTime && filter.createTime[0]) {
|
||||
initialCreateTime[0] = moment(filter.createTime[0])
|
||||
}
|
||||
if (filter.createTime && filter.createTime[1]) {
|
||||
initialCreateTime[1] = moment(filter.createTime[1])
|
||||
}
|
||||
|
||||
return (
|
||||
<Row gutter={24}>
|
||||
<Col {...ColProps} xl={{ span: 4 }} md={{ span: 8 }}>
|
||||
{getFieldDecorator('name', { initialValue: name })(
|
||||
<Search
|
||||
placeholder={i18n.t`Search Name`}
|
||||
onSearch={this.handleSubmit}
|
||||
/>
|
||||
)}
|
||||
</FilterItem>
|
||||
</Col>
|
||||
<Col
|
||||
{...TwoColProps}
|
||||
xl={{ span: 10 }}
|
||||
md={{ span: 24 }}
|
||||
sm={{ span: 24 }}
|
||||
>
|
||||
<Row type="flex" align="middle" justify="space-between">
|
||||
<div>
|
||||
<Button
|
||||
type="primary"
|
||||
className="margin-right"
|
||||
onClick={handleSubmit}
|
||||
>
|
||||
Search
|
||||
</Col>
|
||||
<Col
|
||||
{...ColProps}
|
||||
xl={{ span: 4 }}
|
||||
md={{ span: 8 }}
|
||||
id="addressCascader"
|
||||
>
|
||||
{getFieldDecorator('address', { initialValue: address })(
|
||||
<Cascader
|
||||
style={{ width: '100%' }}
|
||||
options={city}
|
||||
placeholder={i18n.t`Please pick an address`}
|
||||
onChange={this.handleChange.bind(this, 'address')}
|
||||
getPopupContainer={() =>
|
||||
document.getElementById('addressCascader')
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</Col>
|
||||
<Col
|
||||
{...ColProps}
|
||||
xl={{ span: 6 }}
|
||||
md={{ span: 8 }}
|
||||
sm={{ span: 12 }}
|
||||
id="createTimeRangePicker"
|
||||
>
|
||||
<FilterItem label={i18n.t`CreateTime`}>
|
||||
{getFieldDecorator('createTime', {
|
||||
initialValue: initialCreateTime,
|
||||
})(
|
||||
<RangePicker
|
||||
style={{ width: '100%' }}
|
||||
onChange={this.handleChange.bind(this, 'createTime')}
|
||||
getCalendarContainer={() => {
|
||||
return document.getElementById('createTimeRangePicker')
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</FilterItem>
|
||||
</Col>
|
||||
<Col
|
||||
{...TwoColProps}
|
||||
xl={{ span: 10 }}
|
||||
md={{ span: 24 }}
|
||||
sm={{ span: 24 }}
|
||||
>
|
||||
<Row type="flex" align="middle" justify="space-between">
|
||||
<div>
|
||||
<Button
|
||||
type="primary"
|
||||
className="margin-right"
|
||||
onClick={this.handleSubmit}
|
||||
>
|
||||
<Trans>Search</Trans>
|
||||
</Button>
|
||||
<Button onClick={this.handleReset}>
|
||||
<Trans>Reset</Trans>
|
||||
</Button>
|
||||
</div>
|
||||
<Button type="ghost" onClick={onAdd}>
|
||||
<Trans>Create</Trans>
|
||||
</Button>
|
||||
<Button onClick={handleReset}>Reset</Button>
|
||||
</div>
|
||||
<Button type="ghost" onClick={onAdd}>
|
||||
Create
|
||||
</Button>
|
||||
</Row>
|
||||
</Col>
|
||||
</Row>
|
||||
)
|
||||
</Row>
|
||||
</Col>
|
||||
</Row>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Filter.propTypes = {
|
||||
@@ -146,4 +171,4 @@ Filter.propTypes = {
|
||||
onFilterChange: PropTypes.func,
|
||||
}
|
||||
|
||||
export default Form.create()(Filter)
|
||||
export default Filter
|
||||
|
||||
@@ -1,19 +1,22 @@
|
||||
import React from 'react'
|
||||
import React, { PureComponent } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { Table, Modal } from 'antd'
|
||||
import { Table, Modal, Avatar } from 'antd'
|
||||
import { DropOption } from 'components'
|
||||
import { Trans, withI18n } from '@lingui/react'
|
||||
import Link from 'umi/link'
|
||||
import styles from './List.less'
|
||||
|
||||
const { confirm } = Modal
|
||||
|
||||
const List = ({ onDeleteItem, onEditItem, location, ...tableProps }) => {
|
||||
const handleMenuClick = (record, e) => {
|
||||
@withI18n()
|
||||
class List extends PureComponent {
|
||||
handleMenuClick = (record, e) => {
|
||||
const { onDeleteItem, onEditItem, i18n } = this.props
|
||||
|
||||
if (e.key === '1') {
|
||||
onEditItem(record)
|
||||
} else if (e.key === '2') {
|
||||
confirm({
|
||||
title: 'Are you sure delete this record?',
|
||||
title: i18n.t`Are you sure delete this record?`,
|
||||
onOk() {
|
||||
onDeleteItem(record.id)
|
||||
},
|
||||
@@ -21,86 +24,98 @@ const List = ({ onDeleteItem, onEditItem, location, ...tableProps }) => {
|
||||
}
|
||||
}
|
||||
|
||||
const columns = [
|
||||
{
|
||||
title: 'Avatar',
|
||||
dataIndex: 'avatar',
|
||||
key: 'avatar',
|
||||
width: 64,
|
||||
className: styles.avatar,
|
||||
render: text => <img alt="avatar" width={24} src={text} />,
|
||||
},
|
||||
{
|
||||
title: 'Name',
|
||||
dataIndex: 'name',
|
||||
key: 'name',
|
||||
render: (text, record) => <Link to={`user/${record.id}`}>{text}</Link>,
|
||||
},
|
||||
{
|
||||
title: 'NickName',
|
||||
dataIndex: 'nickName',
|
||||
key: 'nickName',
|
||||
},
|
||||
{
|
||||
title: 'Age',
|
||||
dataIndex: 'age',
|
||||
key: 'age',
|
||||
},
|
||||
{
|
||||
title: 'Gender',
|
||||
dataIndex: 'isMale',
|
||||
key: 'isMale',
|
||||
render: text => <span>{text ? 'Male' : 'Female'}</span>,
|
||||
},
|
||||
{
|
||||
title: 'Phone',
|
||||
dataIndex: 'phone',
|
||||
key: 'phone',
|
||||
},
|
||||
{
|
||||
title: 'Email',
|
||||
dataIndex: 'email',
|
||||
key: 'email',
|
||||
},
|
||||
{
|
||||
title: 'Address',
|
||||
dataIndex: 'address',
|
||||
key: 'address',
|
||||
},
|
||||
{
|
||||
title: 'CreateTime',
|
||||
dataIndex: 'createTime',
|
||||
key: 'createTime',
|
||||
},
|
||||
{
|
||||
title: 'Operation',
|
||||
key: 'operation',
|
||||
width: 100,
|
||||
render: (text, record) => {
|
||||
return (
|
||||
<DropOption
|
||||
onMenuClick={e => handleMenuClick(record, e)}
|
||||
menuOptions={[
|
||||
{ key: '1', name: 'Update' },
|
||||
{ key: '2', name: 'Delete' },
|
||||
]}
|
||||
/>
|
||||
)
|
||||
},
|
||||
},
|
||||
]
|
||||
render() {
|
||||
const {
|
||||
handleMenuClick,
|
||||
onDeleteItem,
|
||||
onEditItem,
|
||||
i18n,
|
||||
...tableProps
|
||||
} = this.props
|
||||
|
||||
return (
|
||||
<Table
|
||||
{...tableProps}
|
||||
className={styles.table}
|
||||
bordered
|
||||
scroll={{ x: 1250 }}
|
||||
columns={columns}
|
||||
simple
|
||||
rowKey={record => record.id}
|
||||
/>
|
||||
)
|
||||
const columns = [
|
||||
{
|
||||
title: <Trans>Avatar</Trans>,
|
||||
dataIndex: 'avatar',
|
||||
key: 'avatar',
|
||||
width: 100,
|
||||
render: text => <Avatar style={{ marginLeft: 8 }} src={text} />,
|
||||
},
|
||||
{
|
||||
title: <Trans>Name</Trans>,
|
||||
dataIndex: 'name',
|
||||
key: 'name',
|
||||
render: (text, record) => <Link to={`user/${record.id}`}>{text}</Link>,
|
||||
},
|
||||
{
|
||||
title: <Trans>NickName</Trans>,
|
||||
dataIndex: 'nickName',
|
||||
key: 'nickName',
|
||||
},
|
||||
{
|
||||
title: <Trans>Age</Trans>,
|
||||
dataIndex: 'age',
|
||||
key: 'age',
|
||||
},
|
||||
{
|
||||
title: <Trans>Gender</Trans>,
|
||||
dataIndex: 'isMale',
|
||||
key: 'isMale',
|
||||
render: text => <span>{text ? 'Male' : 'Female'}</span>,
|
||||
},
|
||||
{
|
||||
title: <Trans>Phone</Trans>,
|
||||
dataIndex: 'phone',
|
||||
key: 'phone',
|
||||
},
|
||||
{
|
||||
title: <Trans>Email</Trans>,
|
||||
dataIndex: 'email',
|
||||
key: 'email',
|
||||
},
|
||||
{
|
||||
title: <Trans>Address</Trans>,
|
||||
dataIndex: 'address',
|
||||
key: 'address',
|
||||
},
|
||||
{
|
||||
title: <Trans>CreateTime</Trans>,
|
||||
dataIndex: 'createTime',
|
||||
key: 'createTime',
|
||||
},
|
||||
{
|
||||
title: <Trans>Operation</Trans>,
|
||||
key: 'operation',
|
||||
width: 100,
|
||||
render: (text, record) => {
|
||||
return (
|
||||
<DropOption
|
||||
onMenuClick={e => handleMenuClick(record, e)}
|
||||
menuOptions={[
|
||||
{ key: '1', name: i18n.t`Update` },
|
||||
{ key: '2', name: i18n.t`Delete` },
|
||||
]}
|
||||
/>
|
||||
)
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
return (
|
||||
<Table
|
||||
{...tableProps}
|
||||
pagination={{
|
||||
...tableProps.pagination,
|
||||
showTotal: total => i18n.t`Total ${total} Items`,
|
||||
}}
|
||||
bordered
|
||||
scroll={{ x: 1250 }}
|
||||
columns={columns}
|
||||
simple
|
||||
rowKey={record => record.id}
|
||||
/>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
List.propTypes = {
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
.table {
|
||||
td.avatar {
|
||||
img {
|
||||
border-radius: 50%;
|
||||
}
|
||||
}
|
||||
|
||||
:global {
|
||||
.ant-table-tbody > tr > td,
|
||||
.ant-table-thead > tr > th {
|
||||
height: 62px;
|
||||
}
|
||||
}
|
||||
}
|
||||
+111
-107
@@ -1,6 +1,7 @@
|
||||
import React from 'react'
|
||||
import React, { PureComponent } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { Form, Input, InputNumber, Radio, Modal, Cascader } from 'antd'
|
||||
import { Trans, withI18n } from '@lingui/react'
|
||||
import city from 'utils/city'
|
||||
|
||||
const FormItem = Form.Item
|
||||
@@ -13,14 +14,13 @@ const formItemLayout = {
|
||||
span: 14,
|
||||
},
|
||||
}
|
||||
@withI18n()
|
||||
@Form.create()
|
||||
class UserModal extends PureComponent {
|
||||
handleOk = () => {
|
||||
const { item = {}, onOk, form } = this.props
|
||||
const { validateFields, getFieldsValue } = form
|
||||
|
||||
const modal = ({
|
||||
item = {},
|
||||
onOk,
|
||||
form: { getFieldDecorator, validateFields, getFieldsValue },
|
||||
...modalProps
|
||||
}) => {
|
||||
const handleOk = () => {
|
||||
validateFields(errors => {
|
||||
if (errors) {
|
||||
return
|
||||
@@ -34,111 +34,115 @@ const modal = ({
|
||||
})
|
||||
}
|
||||
|
||||
const modalOpts = {
|
||||
...modalProps,
|
||||
onOk: handleOk,
|
||||
}
|
||||
render() {
|
||||
const { item = {}, onOk, form, i18n, ...modalProps } = this.props
|
||||
const { getFieldDecorator } = form
|
||||
|
||||
return (
|
||||
<Modal {...modalOpts}>
|
||||
<Form layout="horizontal">
|
||||
<FormItem label="Name" hasFeedback {...formItemLayout}>
|
||||
{getFieldDecorator('name', {
|
||||
initialValue: item.name,
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
})(<Input />)}
|
||||
</FormItem>
|
||||
<FormItem label="NickName" hasFeedback {...formItemLayout}>
|
||||
{getFieldDecorator('nickName', {
|
||||
initialValue: item.nickName,
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
})(<Input />)}
|
||||
</FormItem>
|
||||
<FormItem label="Gender" hasFeedback {...formItemLayout}>
|
||||
{getFieldDecorator('isMale', {
|
||||
initialValue: item.isMale,
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
type: 'boolean',
|
||||
},
|
||||
],
|
||||
})(
|
||||
<Radio.Group>
|
||||
<Radio value>Male</Radio>
|
||||
<Radio value={false}>Female</Radio>
|
||||
</Radio.Group>
|
||||
)}
|
||||
</FormItem>
|
||||
<FormItem label="Age" hasFeedback {...formItemLayout}>
|
||||
{getFieldDecorator('age', {
|
||||
initialValue: item.age,
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
type: 'number',
|
||||
},
|
||||
],
|
||||
})(<InputNumber min={18} max={100} />)}
|
||||
</FormItem>
|
||||
<FormItem label="Phone" hasFeedback {...formItemLayout}>
|
||||
{getFieldDecorator('phone', {
|
||||
initialValue: item.phone,
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
pattern: /^1[34578]\d{9}$/,
|
||||
message: 'The input is not valid phone!',
|
||||
},
|
||||
],
|
||||
})(<Input />)}
|
||||
</FormItem>
|
||||
<FormItem label="E-mail" hasFeedback {...formItemLayout}>
|
||||
{getFieldDecorator('email', {
|
||||
initialValue: item.email,
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
pattern: /^([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+(.[a-zA-Z0-9_-])+/,
|
||||
message: 'The input is not valid E-mail!',
|
||||
},
|
||||
],
|
||||
})(<Input />)}
|
||||
</FormItem>
|
||||
<FormItem label="Address" hasFeedback {...formItemLayout}>
|
||||
{getFieldDecorator('address', {
|
||||
initialValue: item.address && item.address.split(' '),
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
})(
|
||||
<Cascader
|
||||
style={{ width: '100%' }}
|
||||
options={city}
|
||||
placeholder="Pick an address"
|
||||
/>
|
||||
)}
|
||||
</FormItem>
|
||||
</Form>
|
||||
</Modal>
|
||||
)
|
||||
return (
|
||||
<Modal {...modalProps} onOk={this.handleOk}>
|
||||
<Form layout="horizontal">
|
||||
<FormItem label={i18n.t`Name`} hasFeedback {...formItemLayout}>
|
||||
{getFieldDecorator('name', {
|
||||
initialValue: item.name,
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
})(<Input />)}
|
||||
</FormItem>
|
||||
<FormItem label={i18n.t`NickName`} hasFeedback {...formItemLayout}>
|
||||
{getFieldDecorator('nickName', {
|
||||
initialValue: item.nickName,
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
})(<Input />)}
|
||||
</FormItem>
|
||||
<FormItem label={i18n.t`Gender`} hasFeedback {...formItemLayout}>
|
||||
{getFieldDecorator('isMale', {
|
||||
initialValue: item.isMale,
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
type: 'boolean',
|
||||
},
|
||||
],
|
||||
})(
|
||||
<Radio.Group>
|
||||
<Radio value>
|
||||
<Trans>Male</Trans>
|
||||
</Radio>
|
||||
<Radio value={false}>
|
||||
<Trans>Female</Trans>
|
||||
</Radio>
|
||||
</Radio.Group>
|
||||
)}
|
||||
</FormItem>
|
||||
<FormItem label={i18n.t`Age`} hasFeedback {...formItemLayout}>
|
||||
{getFieldDecorator('age', {
|
||||
initialValue: item.age,
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
type: 'number',
|
||||
},
|
||||
],
|
||||
})(<InputNumber min={18} max={100} />)}
|
||||
</FormItem>
|
||||
<FormItem label={i18n.t`Phone`} hasFeedback {...formItemLayout}>
|
||||
{getFieldDecorator('phone', {
|
||||
initialValue: item.phone,
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
pattern: /^1[34578]\d{9}$/,
|
||||
message: i18n.t`The input is not valid phone!`,
|
||||
},
|
||||
],
|
||||
})(<Input />)}
|
||||
</FormItem>
|
||||
<FormItem label={i18n.t`Email`} hasFeedback {...formItemLayout}>
|
||||
{getFieldDecorator('email', {
|
||||
initialValue: item.email,
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
pattern: /^([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+(.[a-zA-Z0-9_-])+/,
|
||||
message: i18n.t`The input is not valid E-mail!`,
|
||||
},
|
||||
],
|
||||
})(<Input />)}
|
||||
</FormItem>
|
||||
<FormItem label={i18n.t`Address`} hasFeedback {...formItemLayout}>
|
||||
{getFieldDecorator('address', {
|
||||
initialValue: item.address && item.address.split(' '),
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
})(
|
||||
<Cascader
|
||||
style={{ width: '100%' }}
|
||||
options={city}
|
||||
placeholder={i18n.t`Pick an address`}
|
||||
/>
|
||||
)}
|
||||
</FormItem>
|
||||
</Form>
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
modal.propTypes = {
|
||||
UserModal.propTypes = {
|
||||
form: PropTypes.object.isRequired,
|
||||
type: PropTypes.string,
|
||||
item: PropTypes.object,
|
||||
onOk: PropTypes.func,
|
||||
}
|
||||
|
||||
export default Form.create()(modal)
|
||||
export default UserModal
|
||||
|
||||
@@ -3,16 +3,18 @@ import PropTypes from 'prop-types'
|
||||
import { router } from 'utils'
|
||||
import { connect } from 'dva'
|
||||
import { Row, Col, Button, Popconfirm } from 'antd'
|
||||
import { withI18n } from '@lingui/react'
|
||||
import { Page } from 'components'
|
||||
import { stringify } from 'qs'
|
||||
import List from './components/List'
|
||||
import Filter from './components/Filter'
|
||||
import Modal from './components/Modal'
|
||||
|
||||
@withI18n()
|
||||
@connect(({ user, loading }) => ({ user, loading }))
|
||||
class User extends PureComponent {
|
||||
render() {
|
||||
const { location, dispatch, user, loading } = this.props
|
||||
const { location, dispatch, user, loading, i18n } = this.props
|
||||
const { query, pathname } = location
|
||||
const {
|
||||
list,
|
||||
@@ -41,7 +43,9 @@ class User extends PureComponent {
|
||||
visible: modalVisible,
|
||||
maskClosable: false,
|
||||
confirmLoading: loading.effects[`user/${modalType}`],
|
||||
title: `${modalType === 'create' ? 'Create User' : 'Update User'}`,
|
||||
title: `${
|
||||
modalType === 'create' ? i18n.t`Create User` : i18n.t`Update User`
|
||||
}`,
|
||||
wrapClassName: 'vertical-center-modal',
|
||||
onOk(data) {
|
||||
dispatch({
|
||||
@@ -62,7 +66,6 @@ class User extends PureComponent {
|
||||
dataSource: list,
|
||||
loading: loading.effects['user/query'],
|
||||
pagination,
|
||||
location,
|
||||
onChange(page) {
|
||||
handleRefresh({
|
||||
page: page.current,
|
||||
|
||||
@@ -17,7 +17,6 @@ export const pageModel = modelExtend(model, {
|
||||
pagination: {
|
||||
showSizeChanger: true,
|
||||
showQuickJumper: true,
|
||||
showTotal: total => `Total ${total} Items`,
|
||||
current: 1,
|
||||
total: 0,
|
||||
pageSize: 10,
|
||||
|
||||
Reference in New Issue
Block a user