Merge branch 'master' into remote

This commit is contained in:
rengised
2017-07-05 15:08:43 +08:00
committed by GitHub
44 changed files with 386 additions and 69 deletions
+1 -1
View File
@@ -1,7 +1,7 @@
import React from 'react'
import PropTypes from 'prop-types'
import { Table } from 'antd'
import { request } from '../../utils'
import { request } from 'utils'
import lodash from 'lodash'
import './DataTable.less'
+6 -2
View File
@@ -4,7 +4,7 @@ import { Breadcrumb, Icon } from 'antd'
import { Link } from 'dva/router'
import styles from './Bread.less'
import pathToRegexp from 'path-to-regexp'
import { queryArray } from '../../utils'
import { queryArray } from 'utils'
const Bread = ({ menu }) => {
// 匹配当前路由
@@ -25,7 +25,11 @@ const Bread = ({ menu }) => {
}
if (!current) {
pathArray.push(menu[0])
pathArray.push(menu[0] || {
id: 1,
icon: 'laptop',
name: 'Dashboard',
})
pathArray.push({
id: 404,
name: 'Not Found',
+1 -1
View File
@@ -1,6 +1,6 @@
import React from 'react'
import styles from './Footer.less'
import { config } from '../../utils'
import { config } from 'utils'
const Footer = () => <div className={styles.footer}>
{config.footerText}
+1
View File
@@ -14,6 +14,7 @@
justify-content: space-between;
height: 47px;
background-color: #fff;
z-index: 999;
.rightWarpper {
display: flex;
+7 -8
View File
@@ -2,12 +2,12 @@ import React from 'react'
import PropTypes from 'prop-types'
import { Menu, Icon } from 'antd'
import { Link } from 'dva/router'
import { arrayToTree, queryArray } from '../../utils'
import { arrayToTree, queryArray } from 'utils'
import pathToRegexp from 'path-to-regexp'
const Menus = ({ siderFold, darkTheme, location, handleClickNavMenu, navOpenKeys, changeOpenKeys, menu }) => {
const Menus = ({ siderFold, darkTheme, handleClickNavMenu, navOpenKeys, changeOpenKeys, menu }) => {
// 生成树状
const menuTree = arrayToTree(menu.filter(_ => _.mpid !== -1), 'id', 'mpid')
const menuTree = arrayToTree(menu.filter(_ => _.mpid !== '-1'), 'id', 'mpid')
const levelMap = {}
// 递归生成菜单
@@ -22,7 +22,7 @@ const Menus = ({ siderFold, darkTheme, location, handleClickNavMenu, navOpenKeys
key={item.id}
title={<span>
{item.icon && <Icon type={item.icon} />}
{(!siderFoldN || menuTree.indexOf(item) < 0) && item.name}
{(!siderFoldN || !menuTree.includes(item)) && item.name}
</span>}
>
{getMenus(item.children, siderFoldN)}
@@ -33,7 +33,7 @@ const Menus = ({ siderFold, darkTheme, location, handleClickNavMenu, navOpenKeys
<Menu.Item key={item.id}>
<Link to={item.router}>
{item.icon && <Icon type={item.icon} />}
{(!siderFoldN || menuTree.indexOf(item) < 0) && item.name}
{(!siderFoldN || !menuTree.includes(item)) && item.name}
</Link>
</Menu.Item>
)
@@ -60,8 +60,8 @@ const Menus = ({ siderFold, darkTheme, location, handleClickNavMenu, navOpenKeys
}
const onOpenChange = (openKeys) => {
const latestOpenKey = openKeys.find(key => !(navOpenKeys.indexOf(key) > -1))
const latestCloseKey = navOpenKeys.find(key => !(openKeys.indexOf(key) > -1))
const latestOpenKey = openKeys.find(key => !navOpenKeys.includes(key))
const latestCloseKey = navOpenKeys.find(key => !openKeys.includes(key))
let nextOpenKeys = []
if (latestOpenKey) {
nextOpenKeys = getAncestorKeys(latestOpenKey).concat(latestOpenKey)
@@ -120,7 +120,6 @@ Menus.propTypes = {
menu: PropTypes.array,
siderFold: PropTypes.bool,
darkTheme: PropTypes.bool,
location: PropTypes.object,
isNavbar: PropTypes.bool,
handleClickNavMenu: PropTypes.func,
navOpenKeys: PropTypes.array,
+1 -1
View File
@@ -2,7 +2,7 @@ import React from 'react'
import PropTypes from 'prop-types'
import { Icon, Switch } from 'antd'
import styles from './Layout.less'
import { config } from '../../utils'
import { config } from 'utils'
import Menus from './Menu'
const Sider = ({ siderFold, darkTheme, location, changeTheme, navOpenKeys, changeOpenKeys, menu }) => {
+20
View File
@@ -0,0 +1,20 @@
import React from 'react'
import PropTypes from 'prop-types'
import classNames from 'classnames'
import styles from './Loader.less'
const Loader = ({ spinning }) => {
return (<div className={classNames(styles.loader, { [styles.hidden]: !spinning })}>
<div className={styles.warpper}>
<div className={styles.inner} />
<div className={styles.text} >LOADING</div>
</div>
</div>)
}
Loader.propTypes = {
spinning: PropTypes.bool,
}
export default Loader
+64
View File
@@ -0,0 +1,64 @@
.loader {
display: block;
background-color: #fff;
width: 100%;
position: fixed;
top: 0;
bottom: 0;
left: 0;
z-index: 100000;
display: flex;
justify-content: center;
align-items: center;
opacity: 1;
text-align: center;
.warpper {
width: 100px;
height: 100px;
display: inline-flex;
flex-direction: column;
justify-content: space-around;
}
.inner {
width: 48px;
height: 48px;
margin: 0 auto;
text-indent: -12345px;
border-top: 1px solid rgba(0, 0, 0, 0.08);
border-right: 1px solid rgba(0, 0, 0, 0.08);
border-bottom: 1px solid rgba(0, 0, 0, 0.08);
border-left: 1px solid rgba(0, 0, 0, 0.7);
border-radius: 50%;
z-index: 100001;
:local {
animation: spinner 600ms infinite linear;
}
}
.text {
width: 100px;
height: 20px;
text-align: center;
font-size: 12px;
letter-spacing: 4px;
color: #000;
}
&.hidden {
z-index: -1;
opacity: 0;
transition: opacity 1s ease 0.5s, z-index 0.1s ease 1.5s;
}
}
@keyframes spinner {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
+6
View File
@@ -0,0 +1,6 @@
{
"name": "Loader",
"version": "0.0.0",
"private": true,
"main": "./Loader.js"
}
+2
View File
@@ -4,6 +4,7 @@ import Iconfont from './Iconfont'
import Search from './Search'
import Editor from './Editor'
import FilterItem from './FilterItem'
import Loader from './Loader'
import * as Layout from './Layout/index.js'
import layer from './layer'
@@ -16,5 +17,6 @@ export {
Search,
Editor,
FilterItem,
Loader,
layer,
}
+164
View File
@@ -0,0 +1,164 @@
const { config, posts } = require('./common')
const { apiPrefix } = config
let database = [
{
id: '1',
icon: 'laptop',
name: 'Dashboard',
router: '/dashboard',
},
{
id: '2',
bpid: '1',
name: 'Users',
icon: 'user',
router: '/user',
},
{
id: '7',
bpid: '1',
name: 'Posts',
icon: 'shopping-cart',
router: '/post',
},
{
id: '21',
mpid: '-1',
bpid: '2',
name: 'User Detail',
router: '/user/:id',
},
{
id: '3',
bpid: '1',
name: 'Request',
icon: 'api',
router: '/request',
},
{
id: '4',
bpid: '1',
name: 'UI Element',
icon: 'camera-o',
},
{
id: '41',
bpid: '4',
mpid: '4',
name: 'IconFont',
icon: 'heart-o',
router: '/UIElement/iconfont',
},
{
id: '42',
bpid: '4',
mpid: '4',
name: 'DataTable',
icon: 'database',
router: '/UIElement/dataTable',
},
{
id: '43',
bpid: '4',
mpid: '4',
name: 'DropOption',
icon: 'bars',
router: '/UIElement/dropOption',
},
{
id: '44',
bpid: '4',
mpid: '4',
name: 'Search',
icon: 'search',
router: '/UIElement/search',
},
{
id: '45',
bpid: '4',
mpid: '4',
name: 'Editor',
icon: 'edit',
router: '/UIElement/editor',
},
{
id: '46',
bpid: '4',
mpid: '4',
name: 'layer (Function)',
icon: 'credit-card',
router: '/UIElement/layer',
},
{
id: '5',
bpid: '1',
name: 'Recharts',
icon: 'code-o',
},
{
id: '51',
bpid: '5',
mpid: '5',
name: 'LineChart',
icon: 'line-chart',
router: '/chart/lineChart',
},
{
id: '52',
bpid: '5',
mpid: '5',
name: 'BarChart',
icon: 'bar-chart',
router: '/chart/barChart',
},
{
id: '53',
bpid: '5',
mpid: '5',
name: 'AreaChart',
icon: 'area-chart',
router: '/chart/areaChart',
},
{
id: '6',
bpid: '1',
name: 'Test Navigation',
icon: 'setting',
},
{
id: '61',
bpid: '6',
mpid: '6',
name: 'Test Navigation1',
router: '/navigation/navigation1',
},
{
id: '62',
bpid: '6',
mpid: '6',
name: 'Test Navigation2',
router: '/navigation/navigation2',
},
{
id: '621',
bpid: '62',
mpid: '62',
name: 'Test Navigation21',
router: '/navigation/navigation2/navigation1',
},
{
id: '622',
bpid: '62',
mpid: '62',
name: 'Test Navigation22',
router: '/navigation/navigation2/navigation2',
},
]
module.exports = {
[`GET ${apiPrefix}/menus`] (req, res) {
res.status(200).json(database)
},
}
+9 -7
View File
@@ -26,13 +26,15 @@ let usersListData = Mock.mock({
let database = usersListData.data
const userPermission = {
DEFAULT: [
'dashboard', 'chart',
],
ADMIN: [
'dashboard', 'users', 'UIElement', 'UIElementIconfont', 'chart',
],
DEVELOPER: ['dashboard', 'users', 'UIElement', 'UIElementIconfont', 'chart'],
DEFAULT: {
visit: ['1', '2', '21', '7', '5', '51', '52', '53'],
},
ADMIN: {
visit: ['1', '2', '7', '21', '3', '4', '41', '42', '43', '44', '45', '46', '5', '51', '52', '53', '6', '61', '62', '621', '622'],
},
DEVELOPER: {
visit: ['1', '2', '7', '21', '3', '4', '41', '42', '43', '44', '45', '46', '5', '51', '52', '53', '6', '61', '62', '621', '622'],
},
}
const adminUsers = [
+33 -7
View File
@@ -1,13 +1,25 @@
import { query, logout } from '../services/app'
import * as menusService from '../services/menus'
import { routerRedux } from 'dva/router'
import { parse } from 'qs'
import { config } from '../utils'
import { config } from 'utils'
const { prefix } = config
export default {
namespace: 'app',
state: {
user: {},
permissions: {
visit: [],
},
menu: [
{
id: 1,
icon: 'laptop',
name: 'Dashboard',
router: '/dashboard',
},
],
menuPopoverVisible: false,
siderFold: localStorage.getItem(`${prefix}siderFold`) === 'true',
darkTheme: localStorage.getItem(`${prefix}darkTheme`) === 'true',
@@ -33,11 +45,25 @@ export default {
*query ({
payload,
}, { call, put }) {
const data = yield call(query, parse(payload))
if (data.success && data.user) {
const { success, user } = yield call(query, payload)
if (success && user) {
const { list } = yield call(menusService.query)
const { permissions } = user
yield put({
type: 'querySuccess',
payload: data.user,
type: 'updateState',
payload: {
user,
permissions,
menu: list.filter(item => {
const cases = [
permissions.visit.includes(item.id),
item.mpid ? permissions.visit.includes(item.mpid) || item.mpid === '-1' : true,
item.bpid ? permissions.visit.includes(item.bpid) : true,
]
return cases.every(_ => _)
}
),
},
})
if (location.pathname === '/login') {
yield put(routerRedux.push('/dashboard'))
@@ -73,10 +99,10 @@ export default {
},
reducers: {
querySuccess (state, { payload: user }) {
updateState (state, { payload }) {
return {
...state,
user,
...payload,
}
},
+1 -1
View File
@@ -1,6 +1,6 @@
import { login } from '../services/login'
import { routerRedux } from 'dva/router'
import { queryURL } from '../utils'
import { queryURL } from 'utils'
export default {
namespace: 'login',
+1 -1
View File
@@ -2,7 +2,7 @@ import modelExtend from 'dva-model-extend'
import { create, remove, update } from '../services/user'
import * as usersService from '../services/users'
import { pageModel } from './common'
import { config } from '../utils'
import { config } from 'utils'
const { query } = usersService
const { prefix } = config
+1 -1
View File
@@ -1,5 +1,5 @@
import React from 'react'
import { DataTable } from '../../../components'
import { DataTable } from 'components'
import { Table, Row, Col, Card, Select } from 'antd'
class DataTablePage extends React.Component {
+1 -1
View File
@@ -1,5 +1,5 @@
import React from 'react'
import { DropOption } from '../../../components'
import { DropOption } from 'components'
import { Table, Row, Col, Card, message } from 'antd'
const DropOptionPage = () => <div className="content-inner">
+1 -1
View File
@@ -1,5 +1,5 @@
import React from 'react'
import { Editor } from '../../../components'
import { Editor } from 'components'
import { convertToRaw } from 'draft-js'
import { Row, Col, Card } from 'antd'
import draftToHtml from 'draftjs-to-html'
+1 -1
View File
@@ -1,5 +1,5 @@
import React from 'react'
import { Iconfont } from '../../../components'
import { Iconfont } from 'components'
import { Table, Row, Col, Icon } from 'antd'
import styles from './index.less'
import './emoji.js'
+1 -1
View File
@@ -1,5 +1,5 @@
import React from 'react'
import { layer } from '../../../components'
import { layer } from 'components'
import { Table, Row, Col, Button, Card } from 'antd'
let Enum = {
+1 -1
View File
@@ -1,5 +1,5 @@
import React from 'react'
import { Search } from '../../../components'
import { Search } from 'components'
import { Table, Row, Col, Card } from 'antd'
const SearchPage = () => <div className="content-inner">
+19 -15
View File
@@ -1,19 +1,26 @@
import React from 'react'
import PropTypes from 'prop-types'
import pathToRegexp from 'path-to-regexp'
import { connect } from 'dva'
import { Layout } from '../components'
import { classnames, config, menu } from '../utils'
import { Layout, Loader } from 'components'
import { classnames, config } from 'utils'
import { Helmet } from 'react-helmet'
import '../themes/index.less'
import './app.less'
import NProgress from 'nprogress'
const { prefix } = config
import Error from './error'
const { prefix, openPages } = config
const { Header, Bread, Footer, Sider, styles } = Layout
let lastHref
const App = ({ children, location, dispatch, app, loading }) => {
const { user, siderFold, darkTheme, isNavbar, menuPopoverVisible, navOpenKeys } = app
const App = ({ children, dispatch, app, loading, location }) => {
const { user, siderFold, darkTheme, isNavbar, menuPopoverVisible, navOpenKeys, menu, permissions } = app
let { pathname } = location
pathname = pathname.startsWith('/') ? pathname : `/${pathname}`
const { iconFontJS, iconFontCSS, logo } = config
const current = menu.filter(item => pathToRegexp(item.router || '').exec(pathname))
const hasPermission = current.length ? permissions.visit.includes(current[0].id) : false
const href = window.location.href
if (lastHref !== href) {
@@ -28,7 +35,6 @@ const App = ({ children, location, dispatch, app, loading }) => {
menu,
user,
siderFold,
location,
isNavbar,
menuPopoverVisible,
navOpenKeys,
@@ -50,7 +56,6 @@ const App = ({ children, location, dispatch, app, loading }) => {
menu,
siderFold,
darkTheme,
location,
navOpenKeys,
changeTheme () {
dispatch({ type: 'app/switchTheme' })
@@ -64,13 +69,12 @@ const App = ({ children, location, dispatch, app, loading }) => {
const breadProps = {
menu,
}
if (config.openPages && config.openPages.indexOf(location.pathname) > -1) {
return <div>{children}</div>
if (openPages && openPages.includes(pathname)) {
return (<div>
<Loader spinning={loading.effects['app/query']} />
{children}
</div>)
}
const { iconFontJS, iconFontCSS, logo } = config
return (
<div>
<Helmet>
@@ -86,10 +90,10 @@ const App = ({ children, location, dispatch, app, loading }) => {
</aside> : ''}
<div className={styles.main}>
<Header {...headerProps} />
<Bread {...breadProps} location={location} />
<Bread {...breadProps} />
<div className={styles.container}>
<div className={styles.content}>
{children}
{hasPermission ? children : <Error />}
</div>
</div>
<Footer />
+1 -1
View File
@@ -2,7 +2,7 @@ import React from 'react'
import PropTypes from 'prop-types'
import { Table, Tag } from 'antd'
import styles from './browser.less'
import { color } from '../../../utils'
import { color } from 'utils'
const status = {
1: {
+1 -1
View File
@@ -2,7 +2,7 @@ import React from 'react'
import PropTypes from 'prop-types'
import { Table, Tag } from 'antd'
import styles from './comments.less'
import { color } from '../../../utils'
import { color } from 'utils'
const status = {
1: {
+1 -1
View File
@@ -2,7 +2,7 @@ import React from 'react'
import PropTypes from 'prop-types'
import styles from './completed.less'
import classnames from 'classnames'
import { color } from '../../../utils'
import { color } from 'utils'
import { AreaChart, Area, XAxis, YAxis, CartesianGrid, Tooltip, Legend, ResponsiveContainer } from 'recharts'
function Completed ({ data }) {
+1 -1
View File
@@ -1,7 +1,7 @@
import React from 'react'
import PropTypes from 'prop-types'
import styles from './cpu.less'
import { color } from '../../../utils'
import { color } from 'utils'
import CountUp from 'react-countup'
import { LineChart, Line, XAxis, YAxis, CartesianGrid, ResponsiveContainer } from 'recharts'
@@ -2,7 +2,7 @@ import React from 'react'
import PropTypes from 'prop-types'
import { Table, Tag } from 'antd'
import styles from './recentSales.less'
import { color } from '../../../utils'
import { color } from 'utils'
const status = {
1: {
+1 -1
View File
@@ -2,7 +2,7 @@ import React from 'react'
import PropTypes from 'prop-types'
import styles from './sales.less'
import classnames from 'classnames'
import { color } from '../../../utils'
import { color } from 'utils'
import { LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, Legend, ResponsiveContainer } from 'recharts'
function Sales ({ data }) {
+1 -1
View File
@@ -3,7 +3,7 @@ import PropTypes from 'prop-types'
import { Button } from 'antd'
import styles from './user.less'
import CountUp from 'react-countup'
import { color } from '../../../utils'
import { color } from 'utils'
const countUpProps = {
start: 0,
duration: 2.75,
+1 -1
View File
@@ -4,7 +4,7 @@ import { connect } from 'dva'
import { Row, Col, Card } from 'antd'
import { NumberCard, Quote, Sales, Weather, RecentSales, Comments, Completed, Browser, Cpu, User } from './components'
import styles from './index.less'
import { color } from '../../utils'
import { color } from 'utils'
const bodyStyle = {
bodyStyle: {
+1 -1
View File
@@ -2,7 +2,7 @@ import React from 'react'
import PropTypes from 'prop-types'
import { connect } from 'dva'
import { Button, Row, Form, Input } from 'antd'
import { config } from '../../utils'
import { config } from 'utils'
import styles from './index.less'
const FormItem = Form.Item
+1 -1
View File
@@ -1,7 +1,7 @@
import React from 'react'
import styles from './index.less'
import Mock from 'mockjs'
import { request, config } from '../../utils'
import { request, config } from 'utils'
import {
Row,
Col,
+1 -1
View File
@@ -1,7 +1,7 @@
import React from 'react'
import PropTypes from 'prop-types'
import moment from 'moment'
import { FilterItem } from '../../components'
import { FilterItem } from 'components'
import { Form, Button, Row, Col, DatePicker, Input, Cascader, Switch } from 'antd'
import city from '../../utils/city'
+1 -1
View File
@@ -4,7 +4,7 @@ import { Table, Modal } from 'antd'
import styles from './List.less'
import classnames from 'classnames'
import AnimTableBody from '../../components/DataTable/AnimTableBody'
import { DropOption } from '../../components'
import { DropOption } from 'components'
import { Link } from 'dva/router'
const confirm = Modal.confirm
+1 -1
View File
@@ -1,4 +1,4 @@
import { request, config } from '../utils'
import { request, config } from 'utils'
const { api } = config
const { user, userLogout, userLogin } = api
+1 -1
View File
@@ -1,4 +1,4 @@
import { request, config } from '../utils'
import { request, config } from 'utils'
const { api } = config
const { dashboard } = api
+1 -1
View File
@@ -1,4 +1,4 @@
import { request, config } from '../utils'
import { request, config } from 'utils'
const { api } = config
const { userLogin } = api
+11
View File
@@ -0,0 +1,11 @@
import { request, config } from 'utils'
const { api } = config
const { menus } = api
export async function query (params) {
return request({
url: menus,
method: 'get',
data: params,
})
}
+1 -1
View File
@@ -1,4 +1,4 @@
import { request, config } from '../utils'
import { request, config } from 'utils'
const { api } = config
const { posts } = api
+1 -1
View File
@@ -1,4 +1,4 @@
import { request, config } from '../utils'
import { request, config } from 'utils'
const { api } = config
const { user } = api
+1 -1
View File
@@ -1,4 +1,4 @@
import { request, config } from '../utils'
import { request, config } from 'utils'
const { api } = config
const { users } = api
+2 -1
View File
@@ -9,7 +9,7 @@ module.exports = {
iconFontCSS: '/iconfont.css',
iconFontJS: '/iconfont.js',
YQL: ['http://www.zuimeitianqi.com'],
CORS: ['http://localhost:7000'],
CORS: [],
openPages: ['/login'],
apiPrefix: '/api/v1',
api: {
@@ -20,6 +20,7 @@ module.exports = {
posts: `${APIV1}/posts`,
user: `${APIV1}/user/:id`,
dashboard: `${APIV1}/dashboard`,
menus: `${APIV1}/menus`,
v1test: `${APIV1}/test`,
v2test: `${APIV2}/test`,
},
+5
View File
@@ -89,6 +89,11 @@ export default function request (options) {
return fetch(options).then((response) => {
const { statusText, status } = response
let data = options.fetchType === 'YQL' ? response.data.query.results.json : response.data
if (data instanceof Array) {
data = {
list: data,
}
}
return Promise.resolve({
success: true,
message: statusText,
+8
View File
@@ -23,5 +23,13 @@ module.exports = (webpackConfig) => {
// loader: 'eslint',
// }]
// Alias
webpackConfig.resolve.alias = {
components: `${__dirname}/src/components`,
utils: `${__dirname}/src/utils`,
config: `${__dirname}/src/utils/config`,
}
return webpackConfig
}