This commit is contained in:
zuiidea
2017-04-13 18:31:48 +08:00
parent a9ff576958
commit 28efa1a67b
12 changed files with 234 additions and 184 deletions
-7
View File
@@ -18,7 +18,6 @@
},
"devDependencies": {
"antd": "^2.9.1",
"atool-build": "^0.7.6",
"axios": "^0.15.3",
"babel-eslint": "^6.1.2",
"babel-plugin-dev-expression": "^0.2.1",
@@ -27,18 +26,12 @@
"babel-plugin-transform-runtime": "^6.9.0",
"babel-polyfill": "^6.23.0",
"babel-runtime": "^6.9.2",
"dora": "^0.4.3",
"dora-plugin-browser-history": "^0.2.0",
"dora-plugin-proxy": "^0.8.5",
"dora-plugin-webpack": "^0.8.1",
"dora-plugin-webpack-hmr": "^0.2.1",
"draftjs-to-html": "^0.7.0",
"eslint": "^3.17.1",
"eslint-config-airbnb": "^9.0.1",
"eslint-plugin-import": "^1.16.0",
"eslint-plugin-jsx-a11y": "^1.4.2",
"eslint-plugin-react": "^5.1.1",
"glob": "^7.0.5",
"jsonp": "^0.2.1",
"less-vars-to-js": "^1.1.2",
"mockjs": "^1.0.1-beta3",
-81
View File
@@ -1,81 +0,0 @@
const qs = require('qs')
const userPermission = {
DEFAULT: ['dashboard', 'chart'],
ADMIN: ['dashboard', 'users', 'UIElement', 'UIElementIconfont', 'chart'],
DEVELOPER: ['dashboard', 'users', 'UIElement', 'UIElementIconfont', 'chart'],
}
const adminUsers = [
{
id: 0,
username: 'admin',
password: 'admin',
permissions: userPermission.ADMIN,
},
{
id: 1,
username: 'guest',
password: 'guest',
permissions: userPermission.DEFAULT,
},
{
id: 2,
username: '吴彦祖',
password: '123456',
permissions: userPermission.DEVELOPER,
},
]
module.exports = {
'POST /api/login' (req, res) {
const { username, password } = req.body
const user = adminUsers.filter((item) => item.username === username)
if (user && user[0].password === password) {
const now = new Date()
now.setDate(now.getDate() + 1)
res.cookie('token', JSON.stringify({
id: 2,
deadline: now.getTime(),
}), { maxAge: 900000, httpOnly: true })
res.json({
success: true,
message: '登录成功',
})
} else {
res.status(400).send({ message: 'Bad Request' })
}
},
'GET /api/userInfo' (req, res) {
const cookies = qs.parse(req.headers.cookie, { delimiter: ';' })
const response = {}
if (!cookies.token) {
res.json({
success: false,
})
return
}
const token = JSON.parse(cookies.token)
if (token) {
response.success = token.deadline > new Date().getTime()
}
if (response.success) {
const userItem = adminUsers.filter(_ => _.id === token.id)
if (userItem.length > 0) {
response.userPermissions = userItem[0].permissions
}
}
console.log(response)
res.json(response)
},
'POST /api/logout' (req, res) {
res.clearCookie('token')
res.json({
success: true,
message: '退出成功',
})
},
}
+88 -6
View File
@@ -1,5 +1,7 @@
const qs = require('qs')
const Mock = require('mockjs')
const config = require('../utils/config')
const { apiPrefix } = config
let antdAdminUsersList = Mock.mock({
'data|100': [
@@ -24,12 +26,86 @@ let antdAdminUsersList = Mock.mock({
},
})
const userPermission = {
DEFAULT: [
'dashboard', 'chart',
],
ADMIN: [
'dashboard', 'users', 'UIElement', 'UIElementIconfont', 'chart',
],
DEVELOPER: ['dashboard', 'users', 'UIElement', 'UIElementIconfont', 'chart'],
}
const adminUsers = [
{
id: 0,
username: 'admin',
password: 'admin',
permissions: userPermission.ADMIN,
}, {
id: 1,
username: 'guest',
password: 'guest',
permissions: userPermission.DEFAULT,
}, {
id: 2,
username: '吴彦祖',
password: '123456',
permissions: userPermission.DEVELOPER,
},
]
let usersListData = antdAdminUsersList
module.exports = {
'GET /api/users' (req, res) {
[`POST ${apiPrefix}/user/login`] (req, res) {
const { username, password } = req.body
const user = adminUsers.filter((item) => item.username === username)
if (user && user[0].password === password) {
const now = new Date()
now.setDate(now.getDate() + 1)
res.cookie('token', JSON.stringify({ id: 2, deadline: now.getTime() }), {
maxAge: 900000,
httpOnly: true,
})
res.json({ success: true, message: '登录成功' })
} else {
res.status(400).send({ message: 'Bad Request' })
}
},
[`GET ${apiPrefix}/user/logout`] (req, res) {
res.clearCookie('token')
res.status(200).send({ message: 'OK' })
},
[`GET ${apiPrefix}/userInfo`] (req, res) {
const cookies = qs.parse(req.headers.cookie, { delimiter: ';' })
const response = {}
const user = {}
if (!cookies.token) {
res.status(200).send({ message: 'Not Login' })
return
}
const token = JSON.parse(cookies.token)
if (token) {
response.success = token.deadline > new Date().getTime()
}
if (response.success) {
const userItem = adminUsers.filter(_ => _.id === token.id)
if (userItem.length > 0) {
user.permissions = userItem[0].permissions
user.username = userItem[0].username
user.id = userItem[0].id
}
}
response.user = user
res.json(response)
},
[`GET ${apiPrefix}/users`] (req, res) {
const page = qs.parse(req.query)
const pageSize = page.pageSize || 10
const currentPage = page.page || 1
@@ -55,10 +131,17 @@ module.exports = {
usersListData.page.current = currentPage * 1
newPage = usersListData.page
}
res.json({ success: true, data, page: { ...newPage, pageSize: Number(pageSize) } })
res.json({
success: true,
data,
page: {
...newPage,
pageSize: Number(pageSize),
},
})
},
'POST /api/users' (req, res) {
[`POST ${apiPrefix}/users`] (req, res) {
const newData = JSON.parse(req.body)
newData.createTime = Mock.mock('@now')
newData.avatar = Mock.Random.image('100x100', Mock.Random.color(), '#757575', 'png', newData.nickName.substr(0, 1))
@@ -74,7 +157,7 @@ module.exports = {
res.json({ success: true, data: usersListData.data, page: usersListData.page })
},
'DELETE /api/users' (req, res) {
[`DELETE ${apiPrefix}/users`] (req, res) {
const deleteItem = JSON.parse(req.body)
usersListData.data = usersListData.data.filter((item) => {
@@ -91,7 +174,7 @@ module.exports = {
res.json({ success: true, data: usersListData.data, page: usersListData.page })
},
'PUT /api/users' (req, res) {
[`PUT ${apiPrefix}/users`] (req, res) {
const editItem = JSON.parse(req.body)
editItem.createTime = Mock.mock('@now')
@@ -107,5 +190,4 @@ module.exports = {
antdAdminUsersList = usersListData
res.json({ success: true, data: usersListData.data, page: usersListData.page })
},
}
+19 -29
View File
@@ -1,4 +1,5 @@
import { login, userInfo, logout } from '../services/app'
import { getUserInfo, logout } from '../services/app'
import { routerRedux } from 'dva/router'
import { parse } from 'qs'
export default {
@@ -7,6 +8,7 @@ export default {
login: false,
user: {
name: '吴彦祖',
userPermissions: [],
},
loginButtonLoading: false,
menuPopoverVisible: false,
@@ -37,7 +39,6 @@ export default {
route: 'chart',
},
},
userPermissions: [],
},
subscriptions: {
setup ({ dispatch }) {
@@ -48,40 +49,20 @@ export default {
},
},
effects: {
*login ({
payload,
}, { call, put }) {
yield put({ type: 'showLoginButtonLoading' })
const { success, userPermissions, username } = yield call(login, parse(payload))
if (success) {
yield put({
type: 'loginSuccess',
payload: {
userPermissions,
user: {
name: username,
},
} })
} else {
yield put({
type: 'loginFail',
})
}
},
*queryUser ({
payload,
}, { call, put }) {
const { success, userPermissions, username } = yield call(userInfo, parse(payload))
if (success) {
const data = yield call(getUserInfo, parse(payload))
if (data.success && data.user) {
yield put({
type: 'loginSuccess',
type: 'queryUserSuccess',
payload: {
userPermissions,
user: {
name: username,
},
user: data.user,
},
})
yield put(routerRedux.push('/dashboard'))
} else {
throw (data)
}
},
*logout ({
@@ -92,6 +73,9 @@ export default {
yield put({
type: 'logoutSuccess',
})
yield put(routerRedux.push('/login'))
} else {
throw (data)
}
},
*switchSider ({
@@ -126,6 +110,12 @@ export default {
},
},
reducers: {
queryUserSuccess (state, action) {
return {
...state,
...action.payload,
}
},
loginSuccess (state, action) {
return {
...state,
+37
View File
@@ -0,0 +1,37 @@
import { login } from '../services/login'
import { routerRedux } from 'dva/router'
export default {
namespace: 'login',
state: {
loginLoading: false,
},
effects: {
*login ({
payload,
}, { put, call }) {
yield put({ type: 'showLoginLoading' })
const data = yield call(login, payload)
yield put({ type: 'hideLoginLoading' })
if (data.success) {
yield put(routerRedux.push('/dashboard'))
} else {
throw data
}
},
},
reducers: {
showLoginLoading (state) {
return {
...state,
loginLoading: true,
}
},
hideLoginLoading (state) {
return {
...state,
loginLoading: false,
}
},
},
}
+8
View File
@@ -45,6 +45,14 @@ const Routers = function ({ history, app }) {
cb(null, require('./routes/users/'))
}, 'users')
},
}, {
path: 'login',
getComponent (nextState, cb) {
require.ensure([], require => {
registerModel(app, require('./models/login'))
cb(null, require('./routes/login/'))
}, 'login')
},
}, {
path: 'request',
getComponent (nextState, cb) {
+21 -32
View File
@@ -1,23 +1,14 @@
import React, { PropTypes } from 'react'
import { connect } from 'dva'
import Login from './login'
import { Layout } from '../components'
import { Spin } from 'antd'
import { classnames, config } from '../utils'
import { Helmet } from 'react-helmet'
import '../components/skin.less'
const { Header, Bread, Footer, Sider, styles } = Layout
const App = ({ children, location, dispatch, app, loading }) => {
const { login, loginButtonLoading, user, siderFold, darkTheme, isNavbar, menuPopoverVisible, navOpenKeys } = app
const loginProps = {
loading,
loginButtonLoading,
onOk (data) {
dispatch({ type: 'app/login', payload: data })
},
}
const App = ({ children, location, dispatch, app }) => {
const { user, siderFold, darkTheme, isNavbar, menuPopoverVisible, navOpenKeys } = app
const headerProps = {
user,
@@ -54,34 +45,33 @@ const App = ({ children, location, dispatch, app, loading }) => {
},
}
if (config.openPages && config.openPages.indexOf(location.pathname) > -1) {
return <div>{children}</div>
}
return (
<div>
<Helmet>
<title>ANTD ADMIN</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="icon" href={config.logoSrc} type="image/x-icon" />
{config.iconFontUrl ? <script src={config.iconFontUrl}></script> : ''}
</Helmet>
{login
? <div className={classnames(styles.layout, { [styles.fold]: isNavbar ? false : siderFold }, { [styles.withnavbar]: isNavbar })}>
{!isNavbar ? <aside className={classnames(styles.sider, { [styles.light]: !darkTheme })}>
<Sider {...siderProps} />
</aside> : ''}
<div className={styles.main}>
<Header {...headerProps} />
<Bread location={location} />
<div className={styles.container}>
<div className={styles.content}>
{children}
</div>
<div className={classnames(styles.layout, { [styles.fold]: isNavbar ? false : siderFold }, { [styles.withnavbar]: isNavbar })}>
{!isNavbar ? <aside className={classnames(styles.sider, { [styles.light]: !darkTheme })}>
<Sider {...siderProps} />
</aside> : ''}
<div className={styles.main}>
<Header {...headerProps} />
<Bread location={location} />
<div className={styles.container}>
<div className={styles.content}>
{children}
</div>
<Footer />
</div>
</div> :
<div className={styles.spin}>
<Spin tip="加载用户信息..." spinning={loading} size="large">
<Login {...loginProps} />
</Spin>
</div>}
<Footer />
</div>
</div>
</div>
)
}
@@ -91,7 +81,6 @@ App.propTypes = {
location: PropTypes.object,
dispatch: PropTypes.func,
app: PropTypes.object,
loading: PropTypes.bool,
}
export default connect(({ app, loading }) => ({ app, loading: loading.models.app }))(App)
export default connect(({ app }) => ({ app }))(App)
+17 -13
View File
@@ -1,24 +1,27 @@
import React, { PropTypes } from 'react'
import { connect } from 'dva'
import { Button, Row, Form, Input } from 'antd'
import { config } from '../../utils'
import styles from './index.less'
const FormItem = Form.Item
const login = ({
loginButtonLoading,
onOk,
const Login = ({
login,
dispatch,
form: {
getFieldDecorator,
validateFieldsAndScroll,
},
}) => {
const { loginLoading } = login
function handleOk () {
validateFieldsAndScroll((errors, values) => {
if (errors) {
return
}
onOk(values)
dispatch({ type: 'login/login', payload: values })
})
}
@@ -50,23 +53,24 @@ const login = ({
})(<Input size="large" type="password" onPressEnter={handleOk} placeholder="密码" />)}
</FormItem>
<Row>
<Button type="primary" size="large" onClick={handleOk} loading={loginButtonLoading}>
<Button type="primary" size="large" onClick={handleOk} loading={loginLoading}>
登录
</Button>
<p>
<span>账号:guest</span>
<span>密码:guest</span>
</p>
</Row>
<p>
<span>账号:guest</span>
<span>密码:guest</span>
</p>
</form>
</div>
)
}
login.propTypes = {
Login.propTypes = {
form: PropTypes.object,
loginButtonLoading: PropTypes.bool,
onOk: PropTypes.func,
login: PropTypes.object,
dispatch: PropTypes.func,
}
export default Form.create()(login)
export default connect(({ login }) => ({ login }))(Form.create()(Login))
+8 -6
View File
@@ -1,5 +1,7 @@
import { request } from '../utils'
import { request, config } from '../utils'
const { api } = config
const { userInfo, userLogout } = api
console.log(userLogout)
export async function login (params) {
return request({
url: '/api/login',
@@ -10,15 +12,15 @@ export async function login (params) {
export async function logout (params) {
return request({
url: '/api/logout',
method: 'post',
url: userLogout,
method: 'get',
data: params,
})
}
export async function userInfo (params) {
export async function getUserInfo (params) {
return request({
url: '/api/userInfo',
url: userInfo,
method: 'get',
data: params,
})
+11
View File
@@ -0,0 +1,11 @@
import { request, config } from '../utils'
const { api } = config
const { userLogin } = api
export async function login (data) {
return request({
url: userLogin,
method: 'post',
data,
})
}
+8 -1
View File
@@ -4,7 +4,14 @@ module.exports = {
footerText: 'Ant Design Admin 版权所有 © 2016 由 zuiidea 支持',
logo: 'https://t.alipayobjects.com/images/T1QUBfXo4fXXXXXXXX.png',
iconFontUrl: '//at.alicdn.com/t/font_c4y7asse3q1cq5mi.js',
baseURL: 'http://47.92.30.98:7001/api',
baseURL: 'http://localhost:8000/api/v1',
YQL: ['http://www.zuimeitianqi.com'],
CORS: ['http://localhost:7001'],
openPages: ['/login'],
apiPrefix: '/api/v1',
api: {
userLogin: '/user/login',
userLogout: '/user/logout',
userInfo: '/userInfo',
},
}
+17 -9
View File
@@ -1,9 +1,11 @@
import axios from 'axios'
import qs from 'qs'
import { YQL, CORS } from './config'
import { YQL, CORS, baseURL } from './config'
import jsonp from 'jsonp'
import lodash from 'lodash'
axios.defaults.baseURL = baseURL
const fetch = (options) => {
let {
method = 'get',
@@ -66,17 +68,23 @@ export default function request (options) {
const { statusText, status } = response
let data = options.fetchType === 'YQL' ? response.data.query.results.json : response.data
return {
code: 0,
status,
success: true,
message: statusText,
status,
...data,
}
}).catch((error) => {
const {
response = {
statusText: error.message || 'Network Error',
},
} = error
return { code: 1, message: response.statusText }
const { response } = error
let message
let status
if (response) {
status = response.status
const { data, statusText } = response
message = data.message || statusText
} else {
status = 600
message = 'Network Error'
}
return { success: false, status, message }
})
}