Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in
Toggle navigation
S
shuniu-admin-react
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
superman
shuniu-admin-react
Commits
11ac5abf
Commit
11ac5abf
authored
Jul 27, 2016
by
superman
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
update
parent
e404de17
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
649 additions
and
299 deletions
+649
-299
workspace.xml
.idea/workspace.xml
+209
-212
proxy.config.js
proxy.config.js
+2
-74
App.jsx
src/containers/App/App.jsx
+10
-0
App.less
src/containers/App/App.less
+1
-0
Additem.jsx
src/containers/Users/Additem.jsx
+89
-0
List.jsx
src/containers/Users/List.jsx
+238
-0
index.js
src/containers/index.js
+3
-0
user.js
src/reducers/user.js
+23
-3
index.js
src/routes/index.js
+10
-2
user.js
src/sagas/user.js
+45
-3
user.js
src/services/user.js
+11
-0
xFetch.js
src/services/xFetch.js
+8
-5
No files found.
.idea/workspace.xml
View file @
11ac5abf
This diff is collapsed.
Click to expand it.
proxy.config.js
View file @
11ac5abf
...
...
@@ -2,78 +2,6 @@
// - https://github.com/dora-js/dora-plugin-proxy#规则定义
module
.
exports
=
{
'/api/todos'
:
function
(
req
,
res
)
{
setTimeout
(
function
()
{
res
.
json
({
status
:
1
,
result
:
[
{
id
:
1
,
text
:
'Learn antd'
,
isComplete
:
true
,
},
{
id
:
2
,
text
:
'Learn ant-tool'
,
},
{
id
:
3
,
text
:
'Learn dora'
,
},
],
});
},
500
);
},
'/api/catessddsd'
:
function
(
req
,
res
)
{
setTimeout
(()
=>
{
res
.
json
({
status
:
1
,
result
:[
{
value
:
1
,
label
:
'信托'
,
children
:[
{
value
:
101
,
label
:
'房产'
},{
value
:
102
,
label
:
'政府'
},{
value
:
103
,
label
:
'企业流贷'
}
]
},{
value
:
2
,
label
:
'资管'
,
children
:[
{
value
:
201
,
label
:
'房产'
},{
value
:
202
,
label
:
'政府'
},{
value
:
203
,
label
:
'企业流贷'
}
]
},{
value
:
3
,
label
:
'私募'
,
children
:[
{
value
:
301
,
label
:
'契约型'
}
]
}
]
})
},
100
);
},
'/api/*'
:
'http://react.yanky.cn/'
,
// '/api/*': 'http://192.168.1.126:8080/'
// '/api/*': 'http://react.yanky.cn/',
'/api/*'
:
'http://192.168.1.126:8080/'
};
src/containers/App/App.jsx
View file @
11ac5abf
...
...
@@ -107,6 +107,16 @@ export default class App extends Component {
<
MenuItemContent
to=
"/upload"
cn=
"图片上传"
en=
"Upload Images"
/>
</
Menu
.
Item
>
</
SubMenu
>
<
SubMenu
key=
"sub3"
title=
{
<
span
><
Icon
type=
"folder"
/><
span
>
管理员
</
span
></
span
>
}
>
<
MenuItemGroup
title=
'用户管理'
key=
'users'
>
<
Menu
.
Item
>
<
MenuItemContent
to=
"/admin/users"
cn=
"用户列表"
en=
"Users"
/>
</
Menu
.
Item
>
<
Menu
.
Item
>
<
MenuItemContent
to=
"/admin/users/create"
cn=
"创建用户"
en=
"Create users"
/>
</
Menu
.
Item
>
</
MenuItemGroup
>
</
SubMenu
>
</
Menu
>
</
section
>
<
footer
>
...
...
src/containers/App/App.less
View file @
11ac5abf
...
...
@@ -29,6 +29,7 @@
}
& > section {
flex: 1;
overflow: auto;
}
:global {
...
...
src/containers/Users/Additem.jsx
0 → 100644
View file @
11ac5abf
import
React
,
{
Component
,
PropTypes
}
from
'react'
;
import
{
connect
}
from
'react-redux'
;
import
{
Row
,
Col
,
Form
,
Input
,
Button
,
Checkbox
,
Select
,
message
,
Tabs
,
Cascader
,
Radio
,
Upload
,
Icon
,
Modal
,
DatePicker
,
Table
,
Spin
}
from
'antd'
;
import
Layout
from
'../../components/Layout/Layout'
;
import
MainHeader
from
'../../components/MainHeader/MainHeader'
;
import
{
formItemLayout
,
footerFormSubmitLayout
}
from
'../../utils'
;
@
connect
(
state
=>
({
loading
:
state
.
user
.
loading
,
}))
@
Form
.
create
()
export
default
class
AddItem
extends
Component
{
constructor
(
props
,
content
)
{
super
(
props
,
content
);
}
handleSubmit
(
e
)
{
e
.
preventDefault
();
const
data
=
this
.
props
.
form
.
getFieldsValue
();
console
.
log
(
data
);
this
.
props
.
dispatch
({
type
:
'CREATE_USER_ITEM'
,
data
});
}
render
=
()
=>
{
const
{
loading
,
form
:{
getFieldProps
},
location
:{
query
}}
=
this
.
props
;
const
operation
=
(
<
div
style=
{
{
textAlign
:
'right'
}
}
>
<
Button
.
Group
>
<
Button
type=
"ghost"
onClick=
{
e
=>
{
e
.
preventDefault
();
this
.
props
.
history
.
goBack
();}
}
>
<
Icon
type=
"rollback"
/>
</
Button
>
</
Button
.
Group
>
</
div
>
);
const
header
=
(
<
MainHeader
breadcrumb=
{
[
'用户管理'
,
'添加用户'
]
}
title=
"添加用户"
operation=
{
operation
}
/>
);
return
(
<
Layout
header=
{
header
}
>
<
Spin
spinning=
{
loading
}
>
<
Form
className=
"main-form"
horizontal
onSubmit=
{
this
.
handleSubmit
.
bind
(
this
)
}
>
<
Form
.
Item
label=
"用户名"
help=
"请使用手机号"
{
...
formItemLayout
}
>
<
Input
placeholder=
"用户名"
{
...
getFieldProps
('
username
')}
/>
</
Form
.
Item
>
<
Form
.
Item
label=
"密码"
{
...
formItemLayout
}
>
<
Input
placeholder=
"密码"
type=
"password"
{
...
getFieldProps
('
password
')}
/>
</
Form
.
Item
>
<
Form
.
Item
{
...
footerFormSubmitLayout
}
style=
{
{
marginTop
:
30
}
}
>
<
Button
type=
"primary"
htmlType=
"submit"
loading=
{
loading
}
><
Icon
type=
"save"
/>
创建
</
Button
>
<
Button
onClick=
{
e
=>
{
e
.
preventDefault
();
this
.
props
.
history
.
goBack
();}
}
style=
{
{
marginLeft
:
'1em'
}
}
>
<
Icon
type=
"rollback"
/>
返回
</
Button
>
</
Form
.
Item
>
</
Form
>
</
Spin
>
</
Layout
>
);
}
}
src/containers/Users/List.jsx
0 → 100644
View file @
11ac5abf
import
React
,
{
Component
,
PropTypes
}
from
'react'
;
import
{
connect
}
from
'react-redux'
;
import
{
Table
,
Icon
,
Row
,
Col
,
Button
,
Form
,
Input
,
Cascader
,
Select
}
from
'antd'
;
import
{
Link
}
from
'react-router'
;
import
{
serialize
,
formatDateTime
,
tradeStatusToString
}
from
'../../utils'
;
import
Layout
from
'../../components/Layout/Layout'
;
import
MainHeader
from
'../../components/MainHeader/MainHeader'
;
const
columns
=
[
{
title
:
'用户ID'
,
dataIndex
:
'id'
,
key
:
'id'
,
width
:
70
,
// fixed:'left'
},
{
title
:
'用户名'
,
dataIndex
:
'shortTitle'
,
key
:
'shortTitle'
,
render
:
(
shortTitle
,
record
)
=>
(<
span
title=
{
shortTitle
}
>
{
(
shortTitle
+
''
).
substring
(
0
,
15
)
}
</
span
>)
},
{
title
:
'预约时间'
,
dataIndex
:
'reservationTime'
,
key
:
'reservationTime'
,
width
:
150
,
className
:
'tac'
,
render
:
(
reservationTime
,
record
)
=>
(
<
span
>
{
reservationTime
&&
formatDateTime
(
reservationTime
)
}
</
span
>
)
},
{
title
:
'投资人'
,
dataIndex
:
'buyerName'
,
key
:
'buyerName'
,
width
:
80
,
className
:
'tac'
,
},
{
title
:
'预约额度'
,
dataIndex
:
'reservationAmount'
,
key
:
'reservationAmount'
,
width
:
100
,
className
:
'tac'
,
},
{
title
:
'实际打款'
,
dataIndex
:
'remittanceAmount'
,
key
:
'remittanceAmount'
,
width
:
100
,
className
:
'tac'
,
},
{
title
:
'状态'
,
dataIndex
:
'status'
,
key
:
'status'
,
width
:
160
,
className
:
'tac'
,
render
:
(
status
,
record
)
=>
(<
span
data
-
status=
{
status
}
>
{
tradeStatusToString
(
status
)
}
</
span
>)
},
{
title
:
'操作'
,
key
:
'operation'
,
width
:
140
,
// fixed:'right',
className
:
'tac'
,
render
:
(
text
,
record
)
=>
(
<
span
>
<
Link
to=
{
'/trades/contract/'
+
record
.
id
}
onClick=
{
e
=>
e
.
stopPropagation
()
}
>
合同
</
Link
>
{
(
record
.
status
==
11
||
record
.
status
==
21
)
&&
<
span
>
<
span
className=
"ant-divider"
></
span
>
<
Link
to=
{
'/trades/commission/'
+
record
.
id
}
onClick=
{
e
=>
e
.
stopPropagation
()
}
>
佣金
</
Link
>
</
span
>
}
</
span
>
)
}
];
@
connect
(
state
=>
({
items
:
state
.
user
.
items
,
loading
:
state
.
user
.
loading
,
total
:
state
.
user
.
total
,
}))
@
Form
.
create
()
export
default
class
List
extends
Component
{
constructor
(
props
,
context
)
{
super
(
props
,
context
);
this
.
state
=
{
filterVisible
:
false
,
}
}
componentWillMount
()
{
this
.
fetchList
(
this
.
props
.
location
.
query
);
};
fetchList
(
query
)
{
this
.
props
.
dispatch
({
type
:
'FETCH_USER_LIST'
,
query
});
}
handleRowClick
({
id
})
{
this
.
props
.
history
.
push
(
'/admin/users/'
+
id
);
}
handleFilterVisible
()
{
this
.
setState
({
filterVisible
:
!
this
.
state
.
filterVisible
});
}
handleFilterSubmit
(
e
)
{
e
.
preventDefault
();
// const formData = this.props.form.getFieldsValue();
// if (formData.categoryId && formData.categoryId[1]) {
// formData.categoryId = formData.categoryId[1];
// }
// const searchQuery = {...this.props.location.query, ...formData};
// console.log(searchQuery);
// this.props.history.replace(this.props.location.pathname + '?' + serialize(searchQuery));
// this.fetchList(searchQuery);
}
handleResetFilterForm
(
e
)
{
e
.
preventDefault
();
// this.props.form.setFieldsValue({
// id: undefined,
// status: undefined,
// categoryId: undefined,
// title: undefined
// });
}
render
()
{
const
{
total
,
items
,
loading
,
history
:{
replace
},
form
:{
getFieldProps
},
location
:{
pathname
,
query
}
}
=
this
.
props
;
const
pagination
=
{
total
:
total
,
pageSize
:
parseInt
(
query
.
s
,
10
)
||
10
,
current
:
parseInt
(
query
.
p
,
10
)
||
1
,
showSizeChanger
:
true
,
onShowSizeChange
:
(
current
,
pageSize
)
=>
{
console
.
log
(
'Current: '
,
current
,
'; PageSize: '
,
pageSize
);
query
.
p
=
current
;
query
.
s
=
pageSize
;
replace
(
pathname
+
'?'
+
serialize
(
query
));
this
.
fetchList
(
query
);
},
onChange
:
(
current
)
=>
{
console
.
log
(
'Current: '
,
current
);
query
.
p
=
current
;
replace
(
pathname
+
'?'
+
serialize
(
query
));
this
.
fetchList
(
query
);
}
};
const
operation
=
(
<
div
style=
{
{
textAlign
:
'right'
}
}
>
<
Button
.
Group
>
<
Button
type=
"ghost"
onClick=
{
this
.
handleFilterVisible
.
bind
(
this
)
}
>
<
Icon
type=
"filter"
/>
</
Button
>
</
Button
.
Group
>
</
div
>
);
const
header
=
(
<
MainHeader
breadcrumb=
{
[
'用户管理'
,
'用户列表'
]
}
operation=
{
operation
}
title=
"用户列表"
>
{
this
.
state
.
filterVisible
&&
<
Form
className=
"filterForm"
inline
onSubmit=
{
this
.
handleFilterSubmit
.
bind
(
this
)
}
>
<
Form
.
Item
label=
"ID"
>
<
Input
placeholder=
"请输入搜索ID"
{
...
searchStyle
}
{
...
getFieldProps
('
id
')}
/>
</
Form
.
Item
>
<
Form
.
Item
label=
"类目"
>
{
cates
&&
<
Cascader
options=
{
cates
}
placeholder=
"请选产品类目"
{
...
searchStyle
}
{
...
getFieldProps
('
categoryId
')}
/>
}
</
Form
.
Item
>
<
Form
.
Item
label=
"标题"
>
<
Input
placeholder=
"请输入搜索标题"
{
...
searchStyle
}
{
...
getFieldProps
('
title
')}
/>
</
Form
.
Item
>
<
Form
.
Item
label=
"状态"
>
<
Select
placeholder=
"请选择状态"
{
...
searchStyle
}
{
...
getFieldProps
('
status
')}
>
<
Select
.
Option
key=
"status-option-default"
value=
{
null
}
>
请选择
</
Select
.
Option
>
</
Select
>
</
Form
.
Item
>
<
Form
.
Item
>
<
Button
.
Group
size=
"default"
>
<
Button
type=
"primary"
size=
"default"
htmlType=
"submit"
loading=
{
loading
}
><
Icon
type=
"search"
/>
筛选
</
Button
>
<
Button
type=
"ghost"
size=
"default"
htmlType=
"reset"
onClick=
{
this
.
handleResetFilterForm
.
bind
(
this
)
}
><
Icon
type=
"cross-circle-o"
/>
清空
</
Button
>
</
Button
.
Group
>
</
Form
.
Item
>
</
Form
>
}
</
MainHeader
>
);
return
(
<
Layout
header=
{
header
}
>
<
Table
className=
"list-table"
columns=
{
columns
}
dataSource=
{
Array
.
isArray
(
items
)?
items
:[]
}
loading=
{
loading
}
pagination=
{
pagination
}
scroll=
{
{
y
:
window
.
innerHeight
-
(
this
.
state
.
filterVisible
?
203
:
150
)
}
}
onRowClick=
{
this
.
handleRowClick
.
bind
(
this
)
}
/>
</
Layout
>
);
}
}
src/containers/index.js
View file @
11ac5abf
...
...
@@ -21,3 +21,6 @@ export CustomMessageList from './CustomMessage/List';
export
CustomMessageAddItem
from
'./CustomMessage/AddItem'
;
export
CustomMessageItem
from
'./CustomMessage/Item'
;
export
BaseUpload
from
'./BaseFunction/BaseUpload'
;
export
UsersAddItem
from
'./Users/Additem'
;
export
UsersList
from
'./Users/List'
;
src/reducers/user.js
View file @
11ac5abf
...
...
@@ -2,9 +2,9 @@ import {handleActions} from 'redux-actions';
import
{
combineReducer
}
from
'redux'
;
let
_user
=
sessionStorage
.
getItem
(
'user'
);
try
{
try
{
_user
=
JSON
.
parse
(
_user
);
}
catch
(
ex
)
{
}
catch
(
ex
)
{
_user
=
{};
}
...
...
@@ -21,10 +21,30 @@ const user = handleActions({
},
[
'LOGOUT'
](
state
)
{
return
{...
state
,
auth
:
{},
loading
:
false
};
},
[
'CREATE_USER_ITEM'
](
state
){
return
{...
state
,
loading
:
true
};
},
[
'CREATE_USER_ITEM_SUCCESS'
](
state
,
action
){
return
{...
state
,
loading
:
false
};
},
[
'CREATE_USER_ITEM_FAILED'
](
state
,
action
){
return
{...
state
,
loading
:
false
,
err
:
action
.
err
};
},
[
'FETCH_USER_LIST'
](
state
){
return
{...
state
,
loading
:
true
};
},
[
'FETCH_USER_LIST_SUCCESS'
](
state
,
action
){
return
{...
state
,
loading
:
false
,
items
:
action
.
items
,
total
:
action
.
total
};
},
[
'FETCH_USER_LIST_FAILED'
](
state
,
action
){
return
{...
state
,
loading
:
false
,
err
:
action
.
err
};
}
},
{
...
_user
,
loading
:
false
loading
:
false
,
});
export
default
user
;
src/routes/index.js
View file @
11ac5abf
...
...
@@ -23,7 +23,9 @@ import {
CustomMessageList
,
CustomMessageAddItem
,
CustomMessageItem
,
BaseUpload
BaseUpload
,
UsersAddItem
,
UsersList
}
from
'../containers/index'
;
export
default
(
store
)
=>
{
...
...
@@ -72,7 +74,13 @@ export default (store)=> {
<
Route
path
=
"create"
component
=
{
CustomMessageAddItem
}
/
>
<
Route
path
=
":id"
component
=
{
CustomMessageItem
}
/
>
<
/Route
>
<
Route
path
=
"upload"
component
=
{
BaseUpload
}
/
>
<
Route
path
=
"upload"
component
=
{
BaseUpload
}
/
>
<
Route
path
=
"admin"
>
<
Route
path
=
"users"
>
<
IndexRoute
component
=
{
UsersList
}
/
>
<
Route
path
=
"create"
component
=
{
UsersAddItem
}
/
>
<
/Route
>
<
/Route
>
<
/Route
>
<
Route
path
=
"/login"
component
=
{
Login
}
/
>
<
Route
path
=
"*"
component
=
{
NotFound
}
/
>
...
...
src/sagas/user.js
View file @
11ac5abf
import
{
takeLatest
}
from
'redux-saga'
;
import
{
take
,
call
,
put
,
fork
,
cancel
}
from
'redux-saga/effects'
;
import
{
fetch
,
clear
,
save
}
from
'../services/user'
;
import
{
fetch
,
clear
,
save
,
create
,
fetchList
}
from
'../services/user'
;
import
{
message
}
from
'antd'
;
function
*
authorize
(
username
,
password
,
push
)
{
...
...
@@ -10,8 +10,8 @@ function* authorize(username, password, push) {
yield
put
({
type
:
'LOGIN_SUCCESS'
,
user
});
console
.
log
(
'login ok'
);
push
(
'/'
);
}
catch
(
err
or
)
{
yield
put
({
type
:
'LOGIN_ERROR'
,
err
or
})
}
catch
(
err
)
{
yield
put
({
type
:
'LOGIN_ERROR'
,
err
})
}
}
...
...
@@ -25,7 +25,49 @@ function* loginFlow() {
}
}
function
*
addItem
(
data
)
{
try
{
yield
call
(
create
,
data
);
yield
put
({
type
:
'CREATE_USER_ITEM_SUCCESS'
});
}
catch
(
err
){
console
.
log
(
err
);
message
.
error
(
err
);
yield
put
({
type
:
'CREATE_USER_ITEM_FAILED'
,
err
});
}
}
function
*
watchAddItem
(){
while
(
true
){
const
{
data
}
=
yield
take
(
'CREATE_USER_ITEM'
);
yield
fork
(
addItem
,
data
);
}
}
function
*
getList
(
query
){
try
{
const
{
items
,
total
}
=
yield
call
(
fetchList
,
query
);
yield
put
({
type
:
'FETCH_USER_LIST_SUCCESS'
,
items
:
items
,
total
});
}
catch
(
err
){
console
.
log
(
err
);
message
.
error
(
err
);
yield
put
({
type
:
'FETCH_USER_LIST_FAILED'
,
err
});
}
}
function
*
watchList
()
{
while
(
true
){
const
{
query
}
=
yield
take
(
'FETCH_USER_LIST'
);
yield
fork
(
getList
,
query
);
}
}
export
default
function
*
()
{
yield
fork
(
loginFlow
);
yield
fork
(
watchAddItem
);
yield
fork
(
watchList
);
}
src/services/user.js
View file @
11ac5abf
...
...
@@ -8,6 +8,17 @@ export async function fetch(username, password) {
});
}
export
async
function
create
(
data
)
{
return
xFetch
(
'/api/users'
,
{
method
:
'POST'
,
body
:
serialize
(
data
)
});
}
export
async
function
fetchList
(
query
){
return
xFetch
(
'/api/admin/users'
+
'?'
+
serialize
(
query
));
}
export
async
function
clear
()
{
sessionStorage
.
clear
();
return
Promise
.
resolve
();
...
...
src/services/xFetch.js
View file @
11ac5abf
...
...
@@ -20,7 +20,11 @@ function check404(res) {
}
function
jsonParse
(
res
)
{
try
{
return
res
.
json
().
then
(
json
=>
({...
res
,
json
}));
}
catch
(
err
){
return
Promise
.
reject
(
err
);
}
}
function
errorMessageParse
(
res
)
{
...
...
@@ -34,21 +38,20 @@ function errorMessageParse(res) {
function
xFetch
(
url
,
options
)
{
const
opts
=
{...
options
};
let
user
;
try
{
try
{
user
=
JSON
.
parse
(
sessionStorage
.
getItem
(
'user'
))
||
{};
}
catch
(
ex
)
{
}
catch
(
ex
)
{
user
=
{};
}
opts
.
headers
=
{
...
opts
.
headers
,
authorization
:
user
.
token
||
''
,
};
if
(
opts
.
method
!=
'GET'
)
{
if
(
opts
.
method
!=
'GET'
)
{
opts
.
headers
[
'content-type'
]
=
'application/x-www-form-urlencoded'
;
}
return
fetch
(
url
,
opts
)
.
then
(
check401
)
.
then
(
check404
)
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment