Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
85e12caf12 | ||
|
|
b83c5e7819 | ||
|
|
9cff4e8dfe | ||
|
|
6ac7e5e815 | ||
|
|
e63dfc9291 | ||
|
|
81e7d2bdca | ||
|
|
1c46693246 | ||
|
|
4832a720e6 | ||
|
|
54964fabfb | ||
|
|
b60e593f09 | ||
|
|
5359efce36 | ||
|
|
3decccc87d | ||
|
|
d92eecb620 | ||
|
|
b4699e75f1 | ||
|
|
19e07aeb7a | ||
|
|
2c74295843 | ||
|
|
55ef9dfc0e | ||
|
|
255b0a95a7 | ||
|
|
bf260db940 | ||
|
|
3e1e782617 | ||
|
|
a1e8f2ed9b |
@@ -1,47 +1,48 @@
|
||||
# Antd Admin
|
||||
|
||||
[](https://github.com/facebook/react)
|
||||
[](https://github.com/ant-design/ant-design)
|
||||
[](https://github.com/dvajs/dva)
|
||||
[](https://github.com/facebook/react)
|
||||
[](https://github.com/ant-design/ant-design)
|
||||
[](https://github.com/dvajs/dva)
|
||||
|
||||
[](https://github.com/zuiidea/antd-admin)
|
||||
[](https://github.com/zuiidea/antd-admin/pulls)
|
||||
[](http://opensource.org/licenses/MIT)
|
||||
[](http://standardjs.com)
|
||||
|
||||
演示地址 <http://zuiidea.github.io/antd-admin/>
|
||||
|
||||
备用地址 <http://47.92.30.98:8000>
|
||||
演示地址 <http://zuiidea.github.io/antd-admin> \| [备用地址](http://47.92.30.98:8000)
|
||||
|
||||
## 特性
|
||||
|
||||
- 基于[react](https://github.com/facebook/react),[ant-design](https://github.com/ant-design/ant-design),[dva](https://github.com/dvajs/dva),[Mock](https://github.com/nuysoft/Mock) 企业级后台管理系统最佳实践
|
||||
- 基于[Mock](https://github.com/nuysoft/Mock)实现脱离后端独立开发
|
||||
- 基于Antd UI 设计语言,提供后台管理系统常见使用场景
|
||||
- 基于[dva](https://github.com/dvajs/dva)动态加载 Model 和路由,按需加载
|
||||
- 浅度响应式设计
|
||||
- 基于[react](https://github.com/facebook/react),[ant-design](https://github.com/ant-design/ant-design),[dva](https://github.com/dvajs/dva),[Mock](https://github.com/nuysoft/Mock) 企业级后台管理系统最佳实践。
|
||||
- 基于Antd UI 设计语言,提供后台管理系统常见使用场景。
|
||||
- 基于[dva](https://github.com/dvajs/dva)动态加载 Model 和路由,按需加载。
|
||||
- 使用[roadhog](https://github.com/sorrycc/roadhog)本地调试和构建,其中Mock功能实现脱离后端独立开发。
|
||||
- 浅度响应式设计。
|
||||
|
||||
## 更新日志
|
||||
|
||||
### 4.2.2
|
||||
|
||||
`2017-06-01`
|
||||
|
||||
- 新增用户管理批量删除。[#320](https://github.com/zuiidea/antd-admin/issues/320)
|
||||
|
||||
### 4.2.1
|
||||
|
||||
`2017-05-12`
|
||||
|
||||
- 新增IconFont扩展方案,本地使用方案。[#270](https://github.com/zuiidea/antd-admin/issues/270) [Live](http://47.92.30.98:666/UIElement/iconfont)
|
||||
- 新增常见场景使用loading。 [dva-loading](https://github.com/dvajs/dva-loading)
|
||||
|
||||
### 4.2
|
||||
|
||||
`2017-04-28`
|
||||
|
||||
- 修改user相关API使用`Restful`风格
|
||||
- 增加user页面多条件查询[#266](https://github.com/zuiidea/antd-admin/issues/226)
|
||||
- 修复菜单默认高亮[#201](https://github.com/zuiidea/antd-admin/issues/201)
|
||||
- 修改user相关API使用`Restful`风格。
|
||||
- 增加user页面多条件查询。[#266](https://github.com/zuiidea/antd-admin/issues/226)
|
||||
- 修复菜单默认高亮。[#201](https://github.com/zuiidea/antd-admin/issues/201)
|
||||
|
||||
`2017-04-21`
|
||||
|
||||
- 重写Menu,Bread组件及配置文件,[说明](https://github.com/zuiidea/antd-admin/wiki/%E8%8F%9C%E5%8D%95%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6)
|
||||
|
||||
### 4.1
|
||||
|
||||
`2017-04-14`
|
||||
|
||||
- 升级开发工具为[roadhog](https://github.com/sorrycc/roadhog)
|
||||
- 使用`roadhog`的mock功能
|
||||
- 增强`utils/request.js`跨域处理能力
|
||||
[More Change Log](https://github.com/zuiidea/antd-admin/wiki/Change-Log)
|
||||
|
||||
## 开发构建
|
||||
|
||||
@@ -75,8 +76,8 @@
|
||||
|
||||
文件夹命名说明:
|
||||
|
||||
- components:组件(方法)为单位以文件夹保存,文件夹名组件首字母大写(如`DataTable`),方法首字母小写(如`layer`),文件夹内主文件与文件夹同名,多文件以`index.js`导出对象(如`./src/components/Layout`)
|
||||
- routes:页面为单位以文件夹保存,文件夹名首字母小写(特殊除外,如`UIElement`),文件夹内主文件以`index.js`导出,多文件时可建立`components`文件夹(如`./src/routes/dashboard`),如果有子路由,依次按照路由层次建立文件夹(如`./src/routes/UIElement`)
|
||||
- components:组件(方法)为单位以文件夹保存,文件夹名组件首字母大写(如`DataTable`),方法首字母小写(如`layer`),文件夹内主文件与文件夹同名,多文件以`index.js`导出对象(如`./src/components/Layout`)。
|
||||
- routes:页面为单位以文件夹保存,文件夹名首字母小写(特殊除外,如`UIElement`),文件夹内主文件以`index.js`导出,多文件时可建立`components`文件夹(如`./src/routes/dashboard`),如果有子路由,依次按照路由层次建立文件夹(如`./src/routes/UIElement`)。
|
||||
|
||||
### 快速开始
|
||||
|
||||
@@ -87,7 +88,6 @@
|
||||
进入目录安装依赖:
|
||||
|
||||
npm i 或者 yarn install
|
||||
npm i roadhog@0.6.0-beta.6 -g
|
||||
|
||||
开发:
|
||||
|
||||
@@ -110,6 +110,8 @@ npm run build
|
||||
npm run lint
|
||||
```
|
||||
|
||||
项目部署 [#269](https://github.com/zuiidea/antd-admin/issues/269)
|
||||
|
||||
## 参考
|
||||
|
||||
用户列表:<https://github.com/dvajs/dva/tree/master/examples/user-dashboard>
|
||||
@@ -120,8 +122,8 @@ dashboard设计稿:<https://dribbble.com/shots/3108122-Dashboard-Admin> (已
|
||||
|
||||
web
|
||||
|
||||

|
||||

|
||||
|
||||
移动
|
||||
|
||||

|
||||

|
||||
|
||||
|
After Width: | Height: | Size: 3.7 MiB |
|
After Width: | Height: | Size: 1.0 MiB |
|
Before Width: | Height: | Size: 262 KiB |
|
Before Width: | Height: | Size: 36 KiB |
|
Before Width: | Height: | Size: 1.8 MiB |
|
Before Width: | Height: | Size: 3.1 MiB |
|
Before Width: | Height: | Size: 1.3 MiB |
|
Before Width: | Height: | Size: 2.6 MiB |
@@ -1,15 +1,15 @@
|
||||
{
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"antd": "^2.9.1",
|
||||
"antd": "^2.10.0",
|
||||
"classnames": "^2.2.5",
|
||||
"draftjs-to-markdown": "^0.4.0",
|
||||
"dva": "^1.1.0",
|
||||
"dva": "^1.2.0",
|
||||
"dva-loading": "^0.2.0",
|
||||
"lodash": "^4.17.4",
|
||||
"nprogress": "^0.2.0",
|
||||
"qs": "^6.2.0",
|
||||
"react": "^15.4.1",
|
||||
"react": "^15.4.4",
|
||||
"react-countup": "1.3.0",
|
||||
"react-dom": "^15.4.1",
|
||||
"react-draft-wysiwyg": "^1.8.1",
|
||||
@@ -37,7 +37,7 @@
|
||||
"path-to-regexp": "^1.7.0",
|
||||
"rc-tween-one": "^1.0.0",
|
||||
"redbox-react": "^1.2.10",
|
||||
"roadhog": "^0.6.0-beta.6"
|
||||
"roadhog": "0.6.0-beta.6"
|
||||
},
|
||||
"pre-commit": [
|
||||
"lint"
|
||||
@@ -45,6 +45,6 @@
|
||||
"scripts": {
|
||||
"dev": "set BROWSER=none&&set HOST=0.0.0.0&&roadhog server",
|
||||
"lint": "eslint --fix --ext .js src",
|
||||
"build": "roadhog build --analyze"
|
||||
"build": "roadhog build"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ class Search extends React.Component {
|
||||
clearVisible: e.target.value !== '',
|
||||
})
|
||||
}
|
||||
handeleSelectChange = value => {
|
||||
handleSelectChange = value => {
|
||||
this.setState({
|
||||
...this.state,
|
||||
selectValue: value,
|
||||
@@ -42,7 +42,7 @@ class Search extends React.Component {
|
||||
const { clearVisible } = this.state
|
||||
return (
|
||||
<Input.Group compact size={size} className={styles.search} style={style}>
|
||||
{select && <Select ref="searchSelect" onChange={this.handeleSelectChange} size={size} {...selectProps}>
|
||||
{select && <Select ref="searchSelect" onChange={this.handleSelectChange} size={size} {...selectProps}>
|
||||
{selectOptions && selectOptions.map((item, key) => <Select.Option value={item.value} key={key}>{item.name || item.value}</Select.Option>)}
|
||||
</Select>}
|
||||
<Input ref="searchInput" size={size} onChange={this.handleInputChange} onPressEnter={this.handleSearch} defaultValue={keyword} />
|
||||
|
||||
@@ -14,6 +14,18 @@
|
||||
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<script type="text/javascript">
|
||||
(function() {
|
||||
var __oldConsoleError = window.console.error.bind(console)
|
||||
window.console.error = function(message, b) {
|
||||
if (message === "Warning: Accessing PropTypes via the main React package is deprecated. Use the prop-types package from npm instead." ||
|
||||
"Warning: A Component: React.createClass is deprecated and will be removed in version 16. Use plain JavaScript classes instead. If you're not yet ready to migrate, create-react-class is available on npm as a drop-in replacement.") {
|
||||
return false
|
||||
}
|
||||
__oldConsoleError(message)
|
||||
}
|
||||
})()
|
||||
</script>
|
||||
<script src="/index.js"></script>
|
||||
</body>
|
||||
|
||||
|
||||
@@ -163,6 +163,13 @@ module.exports = {
|
||||
})
|
||||
},
|
||||
|
||||
[`DELETE ${apiPrefix}/users`] (req, res) {
|
||||
const { ids } = req.body
|
||||
database = database.filter((item) => !ids.some(_ => _ === item.id))
|
||||
res.status(204).end()
|
||||
},
|
||||
|
||||
|
||||
[`POST ${apiPrefix}/user`] (req, res) {
|
||||
const newData = req.body
|
||||
newData.createTime = Mock.mock('@now')
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import { create, remove, update } from '../services/user'
|
||||
import { query } from '../services/users'
|
||||
import * as usersService from '../services/users'
|
||||
import { parse } from 'qs'
|
||||
|
||||
const { query } = usersService
|
||||
|
||||
export default {
|
||||
|
||||
namespace: 'user',
|
||||
@@ -11,6 +13,7 @@ export default {
|
||||
currentItem: {},
|
||||
modalVisible: false,
|
||||
modalType: 'create',
|
||||
selectedRowKeys: [],
|
||||
isMotion: localStorage.getItem('antdAdminUserIsMotion') === 'true',
|
||||
pagination: {
|
||||
showSizeChanger: true,
|
||||
@@ -54,9 +57,21 @@ export default {
|
||||
}
|
||||
},
|
||||
|
||||
*'delete' ({ payload }, { call, put }) {
|
||||
*'delete' ({ payload }, { call, put, select }) {
|
||||
const data = yield call(remove, { id: payload })
|
||||
const { selectedRowKeys } = yield select(_ => _.user)
|
||||
if (data.success) {
|
||||
yield put({ type: 'updateState', payload: { selectedRowKeys: selectedRowKeys.filter(_ => _ !== payload) } })
|
||||
yield put({ type: 'query' })
|
||||
} else {
|
||||
throw data
|
||||
}
|
||||
},
|
||||
|
||||
*'multiDelete' ({ payload }, { call, put }) {
|
||||
const data = yield call(usersService.remove, payload)
|
||||
if (data.success) {
|
||||
yield put({ type: 'updateState', payload: { selectedRowKeys: [] } })
|
||||
yield put({ type: 'query' })
|
||||
} else {
|
||||
throw data
|
||||
@@ -99,6 +114,13 @@ export default {
|
||||
} }
|
||||
},
|
||||
|
||||
updateState (state, { payload }) {
|
||||
return {
|
||||
...state,
|
||||
...payload,
|
||||
}
|
||||
},
|
||||
|
||||
showModal (state, action) {
|
||||
return { ...state, ...action.payload, modalVisible: true }
|
||||
},
|
||||
|
||||
@@ -90,7 +90,7 @@ const List = ({ onDeleteItem, onEditItem, isMotion, location, ...tableProps }) =
|
||||
{...tableProps}
|
||||
className={classnames({ [styles.table]: true, [styles.motion]: isMotion })}
|
||||
bordered
|
||||
scroll={{ x: 1200 }}
|
||||
scroll={{ x: 1250 }}
|
||||
columns={columns}
|
||||
simple
|
||||
rowKey={record => record.id}
|
||||
|
||||
@@ -17,11 +17,11 @@
|
||||
.ant-table-tbody > tr > td,
|
||||
.ant-table-thead > tr > th {
|
||||
&:nth-child(1) {
|
||||
width: 6%;
|
||||
width: 5%;
|
||||
}
|
||||
|
||||
&:nth-child(2) {
|
||||
width: 8%;
|
||||
width: 6%;
|
||||
}
|
||||
|
||||
&:nth-child(3) {
|
||||
@@ -29,7 +29,7 @@
|
||||
}
|
||||
|
||||
&:nth-child(4) {
|
||||
width: 6%;
|
||||
width: 8%;
|
||||
}
|
||||
|
||||
&:nth-child(5) {
|
||||
@@ -37,22 +37,26 @@
|
||||
}
|
||||
|
||||
&:nth-child(6) {
|
||||
width: 8%;
|
||||
width: 6%;
|
||||
}
|
||||
|
||||
&:nth-child(7) {
|
||||
width: 16%;
|
||||
width: 8%;
|
||||
}
|
||||
|
||||
&:nth-child(8) {
|
||||
width: 20%;
|
||||
width: 15%;
|
||||
}
|
||||
|
||||
&:nth-child(9) {
|
||||
width: 14%;
|
||||
width: 17%;
|
||||
}
|
||||
|
||||
&:nth-child(10) {
|
||||
width: 13%;
|
||||
}
|
||||
|
||||
&:nth-child(11) {
|
||||
width: 8%;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,12 +2,13 @@ import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { routerRedux } from 'dva/router'
|
||||
import { connect } from 'dva'
|
||||
import { Row, Col, Button, Popconfirm } from 'antd'
|
||||
import List from './List'
|
||||
import Filter from './Filter'
|
||||
import Modal from './Modal'
|
||||
|
||||
const User = ({ location, dispatch, user, loading }) => {
|
||||
const { list, pagination, currentItem, modalVisible, modalType, isMotion } = user
|
||||
const { list, pagination, currentItem, modalVisible, modalType, isMotion, selectedRowKeys } = user
|
||||
const { pageSize } = pagination
|
||||
|
||||
const modalProps = {
|
||||
@@ -62,6 +63,17 @@ const User = ({ location, dispatch, user, loading }) => {
|
||||
},
|
||||
})
|
||||
},
|
||||
rowSelection: {
|
||||
selectedRowKeys,
|
||||
onChange: (keys) => {
|
||||
dispatch({
|
||||
type: 'user/updateState',
|
||||
payload: {
|
||||
selectedRowKeys: keys,
|
||||
},
|
||||
})
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
const filterProps = {
|
||||
@@ -103,9 +115,29 @@ const User = ({ location, dispatch, user, loading }) => {
|
||||
},
|
||||
}
|
||||
|
||||
const handleDeleteItems = () => {
|
||||
dispatch({
|
||||
type: 'user/multiDelete',
|
||||
payload: {
|
||||
ids: selectedRowKeys,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="content-inner">
|
||||
<Filter {...filterProps} />
|
||||
{
|
||||
selectedRowKeys.length > 0 &&
|
||||
<Row style={{ marginBottom: 24, textAlign: 'right', fontSize: 13 }}>
|
||||
<Col>
|
||||
{`Selected ${selectedRowKeys.length} items `}
|
||||
<Popconfirm title={'Are you sure delete these items?'} placement="left" onConfirm={handleDeleteItems}>
|
||||
<Button type="primary" size="large" style={{ marginLeft: 8 }}>Remove</Button>
|
||||
</Popconfirm>
|
||||
</Col>
|
||||
</Row>
|
||||
}
|
||||
<List {...listProps} />
|
||||
{modalVisible && <Modal {...modalProps} />}
|
||||
</div>
|
||||
|
||||
@@ -9,3 +9,11 @@ export async function query (params) {
|
||||
data: params,
|
||||
})
|
||||
}
|
||||
|
||||
export async function remove (params) {
|
||||
return request({
|
||||
url: users,
|
||||
method: 'delete',
|
||||
data: params,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
module.exports = () => {
|
||||
return {
|
||||
'@border-radius-base': '3px',
|
||||
'@border-radius-sm': '2px',
|
||||
'@shadow-color': 'rgba(0,0,0,0.05)',
|
||||
'@shadow-1-down': '4px 4px 40px @shadow-color',
|
||||
'@border-color-split': '#f4f4f4',
|
||||
'@border-color-base': '#e5e5e5',
|
||||
'@menu-dark-bg': '#3e3e3e',
|
||||
'@text-color': '#666',
|
||||
'@font-family': '"AvenirNext-Regular", "Helvetica Neue", "lucida grande", "PingFangHK-Light", "STHeiti", "Heiti SC", "Hiragino Sans GB", "Microsoft JhengHei", "Microsoft Yahei", SimHei, "WenQuanYi Micro Hei", "Droid Sans", "Roboto", Helvetica, Tahoma, Arial, "sans-serif"',
|
||||
}
|
||||
}
|
||||
@@ -50,7 +50,7 @@ const fetch = (options) => {
|
||||
})
|
||||
})
|
||||
} else if (fetchType === 'YQL') {
|
||||
url = `http://query.yahooapis.com/v1/public/yql?q=select * from json where url='${options.url}?${qs.stringify(options.data)}'&format=json`
|
||||
url = `http://query.yahooapis.com/v1/public/yql?q=select * from json where url='${options.url}?${encodeURIComponent(qs.stringify(options.data))}'&format=json`
|
||||
data = null
|
||||
}
|
||||
|
||||
|
||||