├── doc ├── update-doc-1.0.x.md └── update-doc-0.9.x.md ├── src ├── constants │ ├── bizTypes.js │ └── kitTypes.js ├── containers │ ├── Root.js │ ├── Root.prod.jsx │ └── Root.dev.jsx ├── enhance │ ├── index.js │ ├── TabbarEn.js │ ├── Notification.js │ └── BaseActionsEn.js ├── reducers │ ├── bizReducer.js │ ├── index.js │ ├── modelReducers.js │ └── kitReducer.js ├── comp.js ├── connect │ ├── index.js │ ├── BaseSubRouteConnect.js │ ├── TConnect.js │ ├── BaseParentRouteConnect.js │ ├── BaseComponent.js │ └── ModalSelecterConnect.js ├── paramsStore │ ├── confStore.js │ ├── publicStore.js │ ├── confClassStore.js │ └── modelStore.js ├── notificationCenter │ ├── index.js │ └── nofiFactory.js ├── annotation │ └── Configuration.js ├── store │ ├── configureStore.prod.js │ ├── configureStore.dev.js │ └── configureStore.js ├── router │ ├── modules.js │ └── routes.js ├── hostSetting.js ├── context.js ├── configuration │ └── AuthorityInterceptor.js ├── components │ └── tabbar │ │ ├── tabbar.less │ │ └── Tabbar.jsx ├── actions │ ├── bizAction.js │ └── kitAction.js ├── index.js ├── renderApp.js └── util │ ├── ajax.js │ ├── request.js │ └── tools.js ├── .gitignore ├── .babelrc ├── publish.sh ├── LICENSE ├── package.json └── README.md /doc/update-doc-1.0.x.md: -------------------------------------------------------------------------------- 1 | ### Tomatobean v1.0.x 更新说明 2 | 3 | #### update1: 兼容create-react-app 4 | 使用babel7.0编译 5 | -------------------------------------------------------------------------------- /src/constants/bizTypes.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 身份权限校验 3 | */ 4 | export const CHECK_AUTHORITY = 'CHECK_AUTHORITY'; 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # 2 | node_modules/ 3 | publish/ 4 | .vscode 5 | npm-debug.log* 6 | .DS_Store 7 | .DS_Store? 8 | .idea 9 | -------------------------------------------------------------------------------- /src/containers/Root.js: -------------------------------------------------------------------------------- 1 | if (process.env.NODE_ENV === 'production') { 2 | module.exports = require('./Root.prod').default; 3 | } else { 4 | module.exports = require('./Root.dev').default; 5 | } 6 | -------------------------------------------------------------------------------- /src/enhance/index.js: -------------------------------------------------------------------------------- 1 | import BaseActions from './BaseActionsEn'; 2 | 3 | export default BaseActions; 4 | export { TabbarEn as Tabbar } from './TabbarEn'; 5 | export { NotificationEn as Notification } from './Notification'; 6 | 7 | -------------------------------------------------------------------------------- /src/reducers/bizReducer.js: -------------------------------------------------------------------------------- 1 | import { CHECK_AUTHORITY } from '../constants/bizTypes'; 2 | 3 | export const authorityStatus = (state = false, action) => { 4 | switch (action.type) { 5 | case CHECK_AUTHORITY: 6 | return action.visible; 7 | default: 8 | return state; 9 | } 10 | }; 11 | -------------------------------------------------------------------------------- /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "@babel/preset-env", "@babel/preset-react" 4 | ], 5 | "plugins": [ 6 | ["@babel/plugin-proposal-decorators", {"decoratorsBeforeExport": true}] 7 | // ["import", { 8 | // "libraryName": "antd", 9 | // "style": "css" 10 | // }] 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /src/constants/kitTypes.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 增加头部导航标签 3 | */ 4 | export const TABBAR_INCREMENT = 'TABBAR_INCREMENT'; 5 | /** 6 | * 删除头部导航标签 7 | */ 8 | export const TABBAR_DECREMENT = 'TABBAR_DECREMENT'; 9 | /** 10 | * 多级路由下控制上级路由的显隐 11 | */ 12 | export const PARENT_ROUTE_COMP_VIS = 'PARENT_ROUTE_COMP_VIS'; 13 | 14 | /** 15 | * 使一个state值回滚到初始值 16 | */ 17 | export const STATE_ROLL_BACK = 'STATE_ROLL_BACK'; 18 | -------------------------------------------------------------------------------- /src/containers/Root.prod.jsx: -------------------------------------------------------------------------------- 1 | import React, {Component} from 'react'; 2 | import {Provider} from 'react-redux'; 3 | import RouterTree from '../router/routes' 4 | 5 | export default class Root extends Component { 6 | render() { 7 | const {store, history} = this.props; 8 | return ( 9 | 10 | 11 | 12 | ); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/comp.js: -------------------------------------------------------------------------------- 1 | /** 2 | * File: /Users/fengchengpu/Project/moonlight/src/comp.js 3 | * Project: /Users/fengchengpu/Project/moonlight 4 | * Created Date: Saturday November 11th 2017 5:47:22 pm 5 | * Author: chengpu 6 | * ----- 7 | * Last Modified:Saturday November 11th 2017 5:47:22 pm 8 | * Modified By: chengpu 9 | * ----- 10 | * 11 | */ 12 | import Tabbar from './components/tabbar/Tabbar'; 13 | 14 | export { Tabbar as Tag }; 15 | -------------------------------------------------------------------------------- /publish.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # babel -d publish/ $1/ --no-comments 4 | # lessc $1/components/tabbar/tabbar.less publish/components/tabbar/tabbar.css 5 | ./node_modules/.bin/babel -d publish/ src --no-comments && ./node_modules/.bin/lessc src/components/tabbar/tabbar.less publish/components/tabbar/tabbar.css 6 | 7 | cp -R /Users/fengchengpu/Desktop/CIYUN/Project/TomatoProject/Tomatobean/publish/** /Users/fengchengpu/Desktop/dl-pro/TBExample-master/node_modules/tomatobean 8 | -------------------------------------------------------------------------------- /src/connect/index.js: -------------------------------------------------------------------------------- 1 | import ModalSelecter from './ModalSelecterConnect'; 2 | import TConnect from './TConnect'; 3 | 4 | export default TConnect; 5 | export { BaseSubRoute as BaseSubRouteConnect } from './BaseSubRouteConnect'; 6 | export { ModalSelecter as ModalSelecterConnect }; 7 | export { BaseParentRoute as BaseParentRouteConnect } from './BaseParentRouteConnect'; 8 | export { BaseComponent as BaseComponentConnect, RootRoute as RootRouteConnect } from './BaseComponent'; 9 | -------------------------------------------------------------------------------- /src/containers/Root.dev.jsx: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { Provider } from 'react-redux'; 3 | // import DevTools from './DevTools'; 4 | import RouterTree from '../router/routes'; 5 | // var App = require('../pages/App.jsx'); 6 | 7 | export default class Root extends Component { 8 | render() { 9 | const { store, history } = this.props; 10 | return ( 11 | 12 | 13 | 14 | ); 15 | } 16 | } 17 | // / 18 | -------------------------------------------------------------------------------- /src/paramsStore/confStore.js: -------------------------------------------------------------------------------- 1 | /** 2 | * File: /Users/fengchengpu/Project/moonlight/src/config/confStore.js 3 | * Project: /Users/fengchengpu/Project/moonlight 4 | * Created Date: Saturday November 11th 2017 4:42:24 pm 5 | * Author: chengpu 6 | * ----- 7 | * Last Modified:Saturday November 11th 2017 4:42:24 pm 8 | * Modified By: chengpu 9 | * ----- 10 | * 11 | */ 12 | function confStoreCreate() { 13 | let config = {}; 14 | return (conf) => { 15 | if (!conf) return config; 16 | config = conf; 17 | }; 18 | } 19 | const confStore = confStoreCreate(); 20 | export default confStore; 21 | 22 | -------------------------------------------------------------------------------- /src/paramsStore/publicStore.js: -------------------------------------------------------------------------------- 1 | /** 2 | * File: /Users/fengchengpu/Project/moon/src/tomatobean/paramsStore/publicStore.js 3 | * Project: /Users/fengchengpu/Project/moon 4 | * Created Date: Saturday December 16th 2017 7:21:45 pm 5 | * Author: chengpu 6 | * ----- 7 | * Last Modified:Saturday December 16th 2017 7:21:45 pm 8 | * Modified By: chengpu 9 | * ----- 10 | * 11 | */ 12 | function publicStoreCreate() { 13 | let config = {}; 14 | return (conf) => { 15 | if (!conf) return config; 16 | config = conf; 17 | }; 18 | } 19 | const publicStore = publicStoreCreate(); 20 | export default publicStore; 21 | -------------------------------------------------------------------------------- /src/reducers/index.js: -------------------------------------------------------------------------------- 1 | import { 2 | combineReducers, 3 | } from 'redux'; 4 | import { routerReducer } from 'react-router-redux'; 5 | import tabBarLocations, { parentRouteCompVisible } from './kitReducer'; 6 | import { authorityStatus } from './bizReducer'; 7 | import modelReducers from './modelReducers'; 8 | 9 | export default function gatherReducers() { 10 | const modReducers = modelReducers(); 11 | const reducers = { 12 | tabBarLocations, 13 | parentRouteCompStatus: parentRouteCompVisible, 14 | authorityStatus, 15 | routing: routerReducer, 16 | ...modReducers, 17 | }; 18 | return combineReducers(reducers); 19 | } 20 | -------------------------------------------------------------------------------- /src/enhance/TabbarEn.js: -------------------------------------------------------------------------------- 1 | /** 2 | * File: /Users/fengchengpu/Project/tomatobeen/src/connect/TabbarConnect.js 3 | * Project: /Users/fengchengpu/Project/tomatobeen 4 | * Created Date: Monday November 13th 2017 5:45:11 pm 5 | * Author: chengpu 6 | * ----- 7 | * Last Modified:Monday November 13th 2017 5:56:22 pm 8 | * Modified By: chengpu 9 | * ----- 10 | * 11 | */ 12 | import TConnect from '../connect'; 13 | import { tabBarDecrementAndRedirect, linkTo, tabBarDecrement } from '../actions/kitAction.js'; 14 | 15 | export function TabbarEn() { 16 | return TConnect(['tabBarLocations', 'routing'], { tabbarActions: { tabBarDecrementAndRedirect, linkTo, tabBarDecrement } }); 17 | } 18 | -------------------------------------------------------------------------------- /src/notificationCenter/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * File: /Users/fengchengpu/Project/moon/src/tomatobean/notificationCenter/index.js 3 | * Project: /Users/fengchengpu/Project/moon 4 | * Created Date: Tuesday November 21st 2017 1:23:57 pm 5 | * Author: chengpu 6 | * ----- 7 | * Last Modified:Tuesday November 21st 2017 1:23:57 pm 8 | * Modified By: chengpu 9 | * ----- 10 | * 11 | */ 12 | /** 13 | * 一个可以被构造的通知中心 14 | */ 15 | import notiExtension from './nofiFactory'; 16 | 17 | const noti = notiExtension(); 18 | export const observer = noti.registObserver; 19 | export const notiCenter = noti.getCenter; 20 | export const postNotification = noti.postNoti; 21 | export const removeObserver = noti.removeOb; 22 | -------------------------------------------------------------------------------- /src/connect/BaseSubRouteConnect.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { getDisplayName } from '../util/tools'; 3 | /** 4 | * 5 | * @param {*目标组件} Comp 6 | * @param {*子集名称} childrenName 7 | */ 8 | export const BaseSubRouteConnect = (Comp, childrenName) => { 9 | class WithSubscription extends Component { 10 | render() { 11 | const { 12 | children, 13 | ...props 14 | } = this.props; 15 | return ( 16 | 17 | 18 |
{children}
19 |
20 | ); 21 | } 22 | } 23 | WithSubscription.displayName = `BaseSubRouteConnect(${getDisplayName(Comp)})`; 24 | 25 | return WithSubscription; 26 | }; 27 | -------------------------------------------------------------------------------- /src/reducers/modelReducers.js: -------------------------------------------------------------------------------- 1 | import modelStore from '../paramsStore/modelStore'; 2 | import { STATE_ROLL_BACK } from '../constants/kitTypes'; 3 | 4 | export default function modelReducers() { 5 | const reducers = {}; 6 | modelStore().forEach((model) => { 7 | reducers[model.namespace] = (state = model.state, action) => { 8 | if (model.reducers[action.type]) { 9 | return model.reducers[action.type](state, action); 10 | } 11 | // 添加一些基础功能 12 | switch (action.type) { 13 | // 回滚state 14 | case STATE_ROLL_BACK: 15 | if (action.namespace === model.namespace) { 16 | return model.state; 17 | } 18 | break; 19 | default: 20 | return state; 21 | } 22 | }; 23 | }); 24 | return reducers; 25 | } 26 | -------------------------------------------------------------------------------- /src/annotation/Configuration.js: -------------------------------------------------------------------------------- 1 | /** 2 | * File: /Users/fengchengpu/Project/moon/src/tomatobean/annotation/Configure.js 3 | * Project: /Users/fengchengpu/Project/moon 4 | * Created Date: Thursday December 14th 2017 10:58:33 am 5 | * Author: chengpu 6 | * ----- 7 | * Last Modified:Thursday December 14th 2017 10:58:33 am 8 | * Modified By: chengpu 9 | * ----- 10 | * 11 | */ 12 | import confClassStore from '../paramsStore/confClassStore'; 13 | // export default function Configuration(target, key, descriptor) { 14 | // const method = descriptor.value; 15 | // descriptor.value = (...args) => { 16 | // return method.apply(target, args); 17 | // }; 18 | // return descriptor; 19 | // } 20 | export function Configuration(target) { 21 | const className = target.getSuperName(); 22 | confClassStore(className, target); 23 | return target; 24 | } 25 | -------------------------------------------------------------------------------- /src/store/configureStore.prod.js: -------------------------------------------------------------------------------- 1 | import { createStore, applyMiddleware } from 'redux'; 2 | import { routerMiddleware } from 'react-router-redux'; 3 | import { browserHistory } from 'react-router'; 4 | import thunk from 'redux-thunk'; 5 | import gatherReducers from '../reducers'; 6 | 7 | const middleware = routerMiddleware(browserHistory); 8 | 9 | const enhancer = applyMiddleware(thunk, middleware); 10 | 11 | export default function configureStore(initialState) { 12 | return createStore(gatherReducers(), initialState, enhancer); 13 | } 14 | 15 | // var thunkMiddleware = function ({ dispatch, getState }) { 16 | // return function(next) { 17 | // return function (action) { 18 | // return typeof action === 'function' ? 19 | // action(dispatch, getState) : 20 | // next(action) 21 | // } 22 | // } 23 | // } 24 | -------------------------------------------------------------------------------- /src/router/modules.js: -------------------------------------------------------------------------------- 1 | import confStore from '../paramsStore/confStore'; 2 | 3 | const modules = {}; 4 | const refrence = (routes) => { 5 | const deepLoop = (rts) => { 6 | rts.forEach((route) => { 7 | route.compMatch = route.component; 8 | try { 9 | modules[route.component] = require(`pages/${route.component}/index`); 10 | } catch (error) { 11 | modules[route.component] = require(`pages/${route.component}`); 12 | } 13 | if (modules[route.component].default) { 14 | modules[route.component] = modules[route.component].default; 15 | } 16 | if (route.childRoutes) { 17 | deepLoop(route.childRoutes); 18 | } 19 | }); 20 | }; 21 | deepLoop(routes); 22 | return routes; 23 | }; 24 | const routerConfig = confStore(); 25 | refrence(routerConfig.routes); 26 | 27 | export { routerConfig as default, modules }; 28 | -------------------------------------------------------------------------------- /src/hostSetting.js: -------------------------------------------------------------------------------- 1 | /** 2 | * File: /Users/fengchengpu/Project/moonlight/src/hostSetting.js 3 | * Project: /Users/fengchengpu/Project/moonlight 4 | * Created Date: Saturday November 11th 2017 4:19:16 pm 5 | * Author: chengpu 6 | * ----- 7 | * Last Modified:Saturday November 11th 2017 4:19:16 pm 8 | * Modified By: chengpu 9 | * ----- 10 | * 11 | */ 12 | export default function setHost(conf) { 13 | // 是否是生产环境 14 | if (process.env.NODE_ENV === 'production') { 15 | // 是否有缓存 16 | if (!sessionStorage.host) { 17 | // 是否是外部设置 18 | if (process.env.HOST_ENV) { 19 | sessionStorage.host = process.env.HOST_ENV; 20 | } else { 21 | sessionStorage.host = conf.prod; 22 | } 23 | } 24 | } else if (process.env.HOST_ENV) { 25 | sessionStorage.host = process.env.HOST_ENV; 26 | } else { 27 | sessionStorage.host = conf.dev; 28 | } 29 | window.host = sessionStorage.host; 30 | } 31 | -------------------------------------------------------------------------------- /src/context.js: -------------------------------------------------------------------------------- 1 | /** 2 | * File: /Users/fengchengpu/Project/TomatoProject/moon/src/tomatobean/context.js 3 | * Project: /Users/fengchengpu/Project/TomatoProject/moon 4 | * Created Date: Saturday January 13th 2018 7:09:47 pm 5 | * Author: chengpu 6 | * ----- 7 | * Last Modified:Saturday January 13th 2018 7:09:47 pm 8 | * Modified By: chengpu 9 | * ----- 10 | * Copyright (c) 2018 MagCloud 11 | */ 12 | import modelStore from './paramsStore/modelStore'; 13 | 14 | export default function scan() { 15 | const ct = require.context('tomatoScan', true, /\.c\.js$/); 16 | const ks = ct.keys(); 17 | const testModals = []; 18 | for (let i = 0; i < ks.length; i += 1) { 19 | testModals.push(ct(ks[i])); 20 | } 21 | const context = require.context('tomatoScan', true, /\.m\.js$/); 22 | const keys = context.keys(); 23 | const models = []; 24 | for (let i = 0; i < keys.length; i += 1) { 25 | models.push(context(keys[i]).default); 26 | } 27 | modelStore(models); 28 | } 29 | 30 | -------------------------------------------------------------------------------- /src/enhance/Notification.js: -------------------------------------------------------------------------------- 1 | /** 2 | * File: /Users/fengchengpu/Project/moon/src/tomatobean/enhance/Notification.js 3 | * Project: /Users/fengchengpu/Project/moon 4 | * Created Date: Wednesday November 22nd 2017 9:43:28 am 5 | * Author: chengpu 6 | * ----- 7 | * Last Modified:Wednesday November 22nd 2017 9:43:28 am 8 | * Modified By: chengpu 9 | * ----- 10 | * 11 | */ 12 | import React from 'react'; 13 | import * as noti from 'notificationcenter'; 14 | import { getDisplayName } from '../util/tools'; 15 | 16 | /** 17 | * 18 | * @param {*目标函数} Target 19 | * @param {*目标名称} name 20 | * @param {*表述信息} descriptor 21 | */ 22 | export function NotificationEn(Target) { 23 | const WithSubscription = (props) => { 24 | return ( 25 | 26 | 27 | 28 | ); 29 | }; 30 | 31 | WithSubscription.displayName = `NotificationEn(${getDisplayName(Target)})`; 32 | 33 | return WithSubscription; 34 | } 35 | -------------------------------------------------------------------------------- /src/store/configureStore.dev.js: -------------------------------------------------------------------------------- 1 | import { createStore, applyMiddleware, compose } from 'redux'; 2 | // import { persistState } from 'redux-devtools'; 3 | import { routerMiddleware } from 'react-router-redux'; 4 | import { browserHistory } from 'react-router'; 5 | import thunk from 'redux-thunk'; 6 | import gatherReducers from '../reducers'; 7 | // Build the middleware for intercepting and dispatching navigation actions 8 | const middleware = routerMiddleware(browserHistory); 9 | 10 | const enhancer = compose( 11 | applyMiddleware(thunk, middleware), 12 | // persistState( 13 | // window.location.href.match( 14 | // /[?&]debug_session=([^&#]+)\b/ 15 | // ) 16 | // ) 17 | ); 18 | 19 | export default function configureStore(initialState) { 20 | const store = createStore(gatherReducers(), initialState, enhancer); 21 | 22 | if (module.hot) { 23 | module.hot.accept('../reducers', () => 24 | store.replaceReducer(require('../reducers').default) 25 | ); 26 | } 27 | return store; 28 | } 29 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 VonCheng 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/paramsStore/confClassStore.js: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * File: /Users/fengchengpu/Project/moon/src/tomatobean/paramsStore/confClassStore.js 4 | * Project: /Users/fengchengpu/Project/moon 5 | * Created Date: Thursday December 14th 2017 11:08:23 am 6 | * Author: chengpu 7 | * ----- 8 | * Last Modified:Friday December 15th 2017 11:29:20 am 9 | * Modified By: chengpu 10 | * ----- 11 | * 12 | */ 13 | 14 | function confClassStoreCreate() { 15 | const context = require.context('../configuration', true, /\.js$/); 16 | function requireAll(requireContext) { 17 | return requireContext.keys().map(requireContext); 18 | } 19 | const cCs = requireAll(context); 20 | let config = {}; 21 | cCs.forEach((conf) => { 22 | config = { ...config, ...conf }; 23 | }); 24 | 25 | return (className, conf) => { 26 | if (!className) return config; 27 | if (!conf) return config[className]; 28 | config[className] = conf; 29 | }; 30 | } 31 | /** 32 | * className 不存在则返回所有配置类 33 | * className存在 conf不存在 则返回该指定配置类 34 | * className 存在 conf存在 则写入该配置类 35 | */ 36 | const confClassStore = confClassStoreCreate(); 37 | export default confClassStore; 38 | -------------------------------------------------------------------------------- /src/configuration/AuthorityInterceptor.js: -------------------------------------------------------------------------------- 1 | /** 2 | * File: /Users/fengchengpu/Project/moon/src/configer/check.js 3 | * Project: /Users/fengchengpu/Project/moon 4 | * Created Date: Wednesday December 13th 2017 6:22:19 pm 5 | * Author: chengpu 6 | * ----- 7 | * Last Modified:Wednesday December 13th 2017 6:22:19 pm 8 | * Modified By: chengpu 9 | * ----- 10 | * 11 | */ 12 | 13 | // function dispatch(target, key, descriptor) { 14 | // descriptor.value = (...args)=>{ 15 | // return method.apply(target, args); 16 | // } 17 | // return descriptor; 18 | // } 19 | export class AuthorityInterceptor { 20 | static getSuperName() { 21 | return AuthorityInterceptor.name; 22 | } 23 | /** 24 | * 是不是有效用户权限 25 | * @param {Func} author 进入系统的遥控器(此方法可以作为信物传递),只有当 author(true)时才会打开系统。 26 | * 需要注意的是,系统必须存在一个状态,非开即关。所以无论如何author方法必须被调用。 27 | * @param {Func} redirect 从定向方法 28 | */ 29 | static checkAuthority(author) { 30 | author(true); 31 | } 32 | /** 33 | * 每个页面进入之前的预处理(可以在此处做权限控制) 34 | * @param {Object} location 当前访问的地址信息 35 | * @param {Func} redirect 从定向方法 36 | */ 37 | static preHandle() { 38 | } 39 | } 40 | 41 | -------------------------------------------------------------------------------- /src/notificationCenter/nofiFactory.js: -------------------------------------------------------------------------------- 1 | /** 2 | * File: /Users/fengchengpu/Project/moon/src/tomatobean/notificationCenter/nofiFactory.js 3 | * Project: /Users/fengchengpu/Project/moon 4 | * Created Date: Tuesday November 21st 2017 1:38:30 pm 5 | * Author: chengpu 6 | * ----- 7 | * Last Modified:Tuesday November 21st 2017 1:38:30 pm 8 | * Modified By: chengpu 9 | * ----- 10 | * 11 | */ 12 | export default function notiExtension() { 13 | const center = {}; 14 | const extension = { 15 | registObserver(obName, func) { 16 | center[obName] = func; 17 | return center; 18 | }, 19 | getCenter() { 20 | return center; 21 | }, 22 | postNoti(obName, obj) { 23 | if (!center[obName]) { 24 | if (process.env.NODE_ENV !== 'production') { 25 | console.warn(`The observer '${obName}' is not found. You may have removed the observer`); 26 | } 27 | return false; 28 | } 29 | center[obName](obj); 30 | }, 31 | removeOb(obName) { 32 | delete center[obName]; 33 | }, 34 | }; 35 | /** 36 | * 返回一个可以注册器 37 | */ 38 | return extension; 39 | } 40 | 41 | 42 | // notification.observer('ob', (obj) => { 43 | // console.log(obj); 44 | // }); 45 | // notification.('ob', {}); 46 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "moonlight", 3 | "version": "0.0.1", 4 | "description": "create a react app", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "publish": "./node_modules/.bin/babel -d publish/ src1.0.0/ --no-comments && ./node_modules/.bin/lessc src1.0.0/components/tabbar/tabbar.less publish/components/tabbar/tabbar.css" 9 | }, 10 | "author": "chengpu", 11 | "license": "ISC", 12 | "repository": { 13 | "type": "git", 14 | "url": "https://github.com/VonCheng/Tomatobean.git" 15 | }, 16 | "bugs": { 17 | "url": "https://github.com/VonCheng/Tomatobean/issues" 18 | }, 19 | "homepage": "https://github.com/VonCheng/Tomatobean#readme", 20 | "dependencies": { 21 | "notificationcenter": "^1.1.0", 22 | "react": "^16.1.0", 23 | "react-dom": "^16.0.0", 24 | "react-redux": "^4.1.0", 25 | "react-router": "^3.0.2", 26 | "react-router-redux": "^4.0.8", 27 | "redux": "^3.1.1", 28 | "redux-thunk": "^1.0.3", 29 | "webpack": "^3.8.1" 30 | }, 31 | "devDependencies": { 32 | "@babel/cli": "^7.5.0", 33 | "@babel/core": "^7.5.4", 34 | "@babel/plugin-proposal-decorators": "^7.4.4", 35 | "@babel/preset-env": "^7.5.4", 36 | "@babel/preset-react": "^7.0.0", 37 | "less": "^3.9.0" 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/components/tabbar/tabbar.less: -------------------------------------------------------------------------------- 1 | .tabBarLocations { 2 | width: 100%; 3 | margin-top: 40px; 4 | margin-left: 139px; 5 | margin-right: 20px; 6 | color: black; 7 | height: 40px; 8 | background-color: white; 9 | position: fixed; 10 | padding: 0px 20px; 11 | top: 20px; 12 | z-index: 2; 13 | .tabbar-cell { 14 | display: inline-block; 15 | // padding: 0px 5px; 16 | background-color: #f3f3f3; 17 | line-height: 30px; 18 | margin-right: 5px; 19 | position: relative; 20 | top: 9px; 21 | cursor: pointer; 22 | width: 120px; 23 | span { 24 | margin-left: 10px; 25 | } 26 | em { 27 | margin-left: 10px; 28 | margin-right: 10px; 29 | } 30 | i { 31 | color: #666666; 32 | position: absolute; 33 | right: 10px; 34 | top: 10px; 35 | } 36 | } 37 | .tabbar-active { 38 | background-color: #1482b4;; 39 | color: white; 40 | z-index: 20; 41 | i { 42 | color: #fff; 43 | } 44 | } 45 | .separate-line { 46 | height: 2px; 47 | background-color: #e8e8e8; 48 | position: relative; 49 | top: 8px 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/reducers/kitReducer.js: -------------------------------------------------------------------------------- 1 | import { TABBAR_INCREMENT, TABBAR_DECREMENT, PARENT_ROUTE_COMP_VIS } from '../constants/kitTypes'; 2 | import routerConfig from '../router/modules'; 3 | 4 | const initializationLocations = routerConfig.initializationTabs; 5 | export default (state = initializationLocations ? initializationLocations.concat() : [], 6 | action) => { 7 | switch (action.type) { 8 | case TABBAR_INCREMENT: { 9 | if (!action.currentLocation.state || !action.currentLocation.state.mark) { 10 | return state.concat(); 11 | } 12 | for (let i = 0; i < state.length; i++) { 13 | const location = state[i]; 14 | if (location.pathname === action.currentLocation.pathname) { 15 | state[i] = action.currentLocation; 16 | return state.concat(); 17 | } 18 | } 19 | state.push(action.currentLocation); 20 | return state.concat(); 21 | } 22 | case TABBAR_DECREMENT: { 23 | for (let i = 0; i < state.length; i++) { 24 | const location = state[i]; 25 | if (location.pathname === action.currentLocation.pathname) { 26 | state.splice(i, 1); 27 | return state.concat(); 28 | } 29 | } 30 | return state.concat(); 31 | } 32 | default: 33 | return state; 34 | } 35 | }; 36 | 37 | export const parentRouteCompVisible = (state = true, action) => { 38 | switch (action.type) { 39 | case PARENT_ROUTE_COMP_VIS: 40 | return action.visible; 41 | default: 42 | return state; 43 | } 44 | }; 45 | 46 | -------------------------------------------------------------------------------- /src/actions/bizAction.js: -------------------------------------------------------------------------------- 1 | import { replace } from 'react-router-redux'; 2 | import { CHECK_AUTHORITY } from '../constants/bizTypes'; 3 | // import { AjaxNor } from '../util/ajax'; 4 | import confClassStore from '../paramsStore/confClassStore'; 5 | /** 6 | * 校验身份是否可以访问页面 7 | * @param {*是否可以访问} status 8 | */ 9 | 10 | export function setAuthority(state) { 11 | return { type: CHECK_AUTHORITY, visible: state }; 12 | } 13 | /** 14 | * 分析外部提供的进入系统的状态值做出响应 15 | * @param {*} dispatch 16 | * @param {*} statue 是否可以进入程序 17 | * @param {*} updateStatus 18 | */ 19 | export function authorityDispatch(dispatch, statue, updateStatus) { 20 | if (statue) { 21 | if (updateStatus) { 22 | updateStatus(false); 23 | } 24 | dispatch(setAuthority(true)); 25 | } else { 26 | dispatch(setAuthority(statue)); 27 | } 28 | } 29 | /** 30 | * 校验身份是否可以访问页面 31 | * @param {*是否可以访问} status 32 | */ 33 | export function checkAuthority(updateStatus, fulfilled) { 34 | return (dispatch) => { 35 | // 获取配置类 36 | const AuthorityInterceptor = confClassStore('AuthorityInterceptor'); 37 | // 设置进入系统权限 blean 38 | const authority = (statue, resolve) => { 39 | authorityDispatch(dispatch, statue, updateStatus); 40 | resolve(statue); 41 | }; 42 | // 重定向方法 43 | const redirect = (loaction) => { 44 | dispatch(replace(loaction)); 45 | }; 46 | // 注入authority和redirect 方法 47 | new Promise((resolve) => { 48 | AuthorityInterceptor.checkAuthority(statue => authority(statue, resolve), redirect); 49 | }).then(fulfilled); 50 | }; 51 | } 52 | -------------------------------------------------------------------------------- /src/store/configureStore.js: -------------------------------------------------------------------------------- 1 | /* 2 | _________ ____________ ___________ 3 | | | | | | | 4 | | Action |------------▶| Dispatcher |------------▶| callbacks | 5 | |_________| |____________| |___________| 6 | ▲ | 7 | | | 8 | | | 9 | _________ ____|_____ ____▼____ 10 | | |◀----| Action | | | 11 | | Web API | | Creators | | Store | 12 | |_________|----▶|__________| |_________| 13 | ▲ | 14 | | | 15 | ____|________ ____________ ____▼____ 16 | | User | | React | | Change | 17 | | interactions |◀--------| Views |◀-------------| events | 18 | |______________| |___________| |_________| 19 | 20 | */ 21 | if (process.env.NODE_ENV === 'production') { 22 | module.exports = require('./configureStore.prod').default; 23 | } else { 24 | module.exports = require('./configureStore.dev').default; 25 | } 26 | -------------------------------------------------------------------------------- /src/paramsStore/modelStore.js: -------------------------------------------------------------------------------- 1 | /** 2 | * File: /Users/fengchengpu/Project/moonlight/src/paramsStore/modelStore.js 3 | * Project: /Users/fengchengpu/Project/moonlight 4 | * Created Date: Saturday November 11th 2017 5:05:26 pm 5 | * Author: chengpu 6 | * ----- 7 | * Last Modified:Saturday November 11th 2017 5:05:26 pm 8 | * Modified By: chengpu 9 | * ----- 10 | * 11 | */ 12 | import { objDeepCopy } from '../util/tools'; 13 | 14 | function modelStoreCreate() { 15 | const models = []; 16 | return (mods) => { 17 | if (!mods) return models; 18 | mods.forEach((model) => { 19 | const newModel = objDeepCopy(model); 20 | // connectCount 未请求成功时,连接次数 21 | const connectCount = 0; 22 | const sts = model.state; 23 | for (const k in sts) { 24 | if (sts.hasOwnProperty(k)) { 25 | const newKey = `_${k}`; 26 | newModel[newKey] = connectCount; 27 | } 28 | } 29 | // maxConnect 未请求成功时,最大连接次数 30 | newModel.maxConnect = 1; 31 | newModel.reducers = {}; 32 | const newReducers = newModel.reducers; 33 | 34 | // models可能有多种来源,手动设置权限高于扫描 35 | models.forEach((m, i) => { 36 | if (newModel.namespace === m.namespace) { 37 | model.splice(i, 1); 38 | } 39 | }); 40 | models.push(newModel); 41 | 42 | const rdus = model.reducers; 43 | for (const k in rdus) { 44 | if (rdus.hasOwnProperty(k)) { 45 | newReducers[`${model.namespace}/${k}`] = rdus[k]; 46 | } 47 | } 48 | }); 49 | }; 50 | } 51 | const modelStore = modelStoreCreate(); 52 | export default modelStore; 53 | -------------------------------------------------------------------------------- /src/enhance/BaseActionsEn.js: -------------------------------------------------------------------------------- 1 | /** 2 | * File: /Users/fengchengpu/Project/tomatobeen/src/enhance/BaseReduxCompEn.js 3 | * Project: /Users/fengchengpu/Project/tomatobeen 4 | * Created Date: Monday November 13th 2017 6:22:08 pm 5 | * Author: chengpu 6 | * ----- 7 | * Last Modified:Monday November 13th 2017 6:22:08 pm 8 | * Modified By: chengpu 9 | * ----- 10 | * 11 | */ 12 | import React, { Component } from 'react'; 13 | import { connect } from 'react-redux'; 14 | import { bindActionCreators } from 'redux'; 15 | import { linkTo, go, goBack, goForward, redirect, rollBack } from '../actions/kitAction'; 16 | import { getDisplayName } from '../util/tools'; 17 | 18 | /** 19 | * 20 | * @param {*目标函数} Target 21 | * @param {*目标名称} name 22 | * @param {*表述信息} descriptor 23 | */ 24 | 25 | export default function BaseActionsEn(Target) { 26 | // console.log(descriptor, Target); 27 | function mapState(state) { 28 | return { tabBarLocations: state.tabBarLocations }; 29 | } 30 | function mapDispatch(dispatch) { 31 | return { 32 | baseActions: bindActionCreators({ 33 | linkTo, 34 | redirect, 35 | go, 36 | goBack, 37 | goForward, 38 | rollBack, 39 | }, dispatch), 40 | }; 41 | } 42 | 43 | const Comp = connect(mapState, mapDispatch)(Target); 44 | class WithSubscription extends Component { 45 | render() { 46 | const { 47 | ...props 48 | } = this.props; 49 | 50 | return ( 51 | 52 | 53 | 54 | ); 55 | } 56 | } 57 | WithSubscription.displayName = `BaseActionsEn(${getDisplayName(Comp)})`; 58 | 59 | return WithSubscription; 60 | } 61 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * File: /Users/fengchengpu/Project/moonlight/src/index.js 3 | * Project: /Users/fengchengpu/Project/moonlight 4 | * Created Date: Saturday November 11th 2017 4:18:28 pm 5 | * Author: chengpu 6 | * ----- 7 | * Last Modified:Saturday November 11th 2017 4:18:28 pm 8 | * Modified By: chengpu 9 | * ----- 10 | * 11 | */ 12 | import confStore from './paramsStore/confStore'; 13 | import modelStore from './paramsStore/modelStore'; 14 | import setHost from './hostSetting'; 15 | import renderApp from './renderApp'; 16 | import BaseActions from './enhance'; 17 | import tomatoScan from './context'; 18 | import publicStore from './paramsStore/publicStore'; 19 | 20 | import { ModalSelecterConnect } from './connect'; 21 | 22 | // 扫描工程目录提取配置类及model 23 | tomatoScan(); 24 | 25 | function createApp() { 26 | return { 27 | config() { 28 | }, 29 | router(conf) { 30 | confStore(conf); 31 | }, 32 | model(model) { 33 | modelStore(model); 34 | }, 35 | setHost(conf) { 36 | setHost(conf); 37 | }, 38 | run() { 39 | renderApp(); 40 | }, 41 | }; 42 | } 43 | /** 44 | * 构建相关 45 | */ 46 | export default createApp; 47 | export { ModalSelecterConnect as Selecter }; 48 | export { RootRoute as RootRouteConnect } from "./connect/BaseComponent" ; 49 | export { combinArray as combinModals } from './util/tools.js'; 50 | /** 51 | * 配置相关 52 | */ 53 | export { AuthorityInterceptor } from './configuration/AuthorityInterceptor'; 54 | export { Configuration } from './annotation/Configuration'; 55 | 56 | /** 57 | * 增强器 58 | */ 59 | export { BaseActions }; 60 | export { Tabbar, Notification } from './enhance'; 61 | 62 | /** 63 | *工具方法 64 | */ 65 | export { publicStore }; 66 | 67 | -------------------------------------------------------------------------------- /src/renderApp.js: -------------------------------------------------------------------------------- 1 | /** 2 | * File: /Users/fengchengpu/Project/moonlight/src/renderApp.js 3 | * Project: /Users/fengchengpu/Project/moonlight 4 | * Created Date: Saturday November 11th 2017 4:18:58 pm 5 | * Author: chengpu 6 | * ----- 7 | * Last Modified:Saturday November 11th 2017 4:18:58 pm 8 | * Modified By: chengpu 9 | * ----- 10 | * 11 | */ 12 | import React from 'react'; 13 | import ReactDOM from 'react-dom'; 14 | import { browserHistory } from 'react-router'; 15 | import { syncHistoryWithStore } from 'react-router-redux'; 16 | import { tabBarIncrement } from './actions/kitAction'; 17 | // import configureStore from './store/configureStore'; 18 | // import Root from './containers/Root'; 19 | // import createHistory from 'history/lib/createBrowserHistory' 20 | 21 | export default function renderApp() { 22 | // 如果在调试模式必须 取default 23 | const Root = require('./containers/Root'); 24 | // console.log(Root); 25 | const configureStore = require('./store/configureStore'); 26 | 27 | const store = configureStore(); 28 | 29 | const history = syncHistoryWithStore(browserHistory, store); 30 | // const history = syncHistoryWithStore(createHistory({ 31 | // forceRefresh: false 32 | // }), store); 33 | 34 | /** 35 | * 监听浏览历史用于头部导航标签 36 | * 37 | */ 38 | 39 | history.listen((location) => { 40 | // 多级路由下 控制上级路由的显隐 41 | // store.dispatch(parentRouteCompVisible(true)) 42 | if (location.state && location.state.mark) { 43 | store.dispatch(tabBarIncrement(location)); 44 | } 45 | // 切换页面时滚动到顶部 46 | document.body.scrollTop = 0; 47 | }); 48 | ReactDOM.render( 49 | , 53 | document.getElementById('root') 54 | ); 55 | } 56 | -------------------------------------------------------------------------------- /src/connect/TConnect.js: -------------------------------------------------------------------------------- 1 | /** 2 | * File: /Users/fengchengpu/Project/tomatobeen/src/connect/TConnect.js 3 | * Project: /Users/fengchengpu/Project/tomatobeen 4 | * Created Date: Monday November 13th 2017 5:39:47 pm 5 | * Author: chengpu 6 | * ----- 7 | * Last Modified:Monday November 13th 2017 5:56:03 pm 8 | * Modified By: chengpu 9 | * ----- 10 | * 11 | */ 12 | import React, { Component } from 'react'; 13 | import { connect } from 'react-redux'; 14 | import { bindActionCreators } from 'redux'; 15 | import { getDisplayName } from '../util/tools'; 16 | 17 | /** 18 | * 19 | * @param {*目标函数} Target 20 | * @param {*目标名称} name 21 | * @param {*表述信息} descriptor 22 | */ 23 | export default function (selects, ao) { 24 | return (Target) => { 25 | // console.log(descriptor, Target); 26 | class WithSubscription extends Component { 27 | render() { 28 | const { 29 | ...props 30 | } = this.props; 31 | return ( 32 | 33 | 34 | 35 | ); 36 | } 37 | } 38 | WithSubscription.displayName = `TabbarConnect(${getDisplayName(Target)})`; 39 | function mapState(state) { 40 | const states = {}; 41 | selects.forEach((stateName) => { 42 | states[stateName] = state[stateName]; 43 | }, this); 44 | return { ...states }; 45 | } 46 | let actions; 47 | let key; 48 | for (const k in ao) { 49 | if (ao.hasOwnProperty(k)) { 50 | actions = ao[k]; 51 | key = k; 52 | } 53 | } 54 | function mapDispatch(dispatch) { 55 | const map = {}; 56 | map[key] = bindActionCreators({ ...actions }, dispatch); 57 | return map; 58 | } 59 | return connect(mapState, mapDispatch)(WithSubscription); 60 | }; 61 | } 62 | 63 | -------------------------------------------------------------------------------- /doc/update-doc-0.9.x.md: -------------------------------------------------------------------------------- 1 | ### Tomatobean v0.9.0 更新说明(此版本下兼容) 2 | 3 | #### update1: 兼容create-react-app 4 | 本次更新针对官方构建工具create-react-app做了一些改动。完成了`create-react-app` + `tomatobean` 最佳开发实践。两者搭配能够快速构建工程,降低了学习成本。对于初学者来说能够抛开webpack复杂的配置,单其中会对webpack的配置文件做少量的修改。具体可以查看[Demo](http:www.baidu.com)。 5 | #### update2: 新增自动扫描功能 6 | 上个版本中配置类和model需要手动引入,但在此版本中只需要加入扫描路径就可以。具体配置方法如下: 7 | 8 | 1.修改文件名。 9 | 如果过当前文件是配置类文件需要将文件的后缀改为`xxx.c.js` ,然后使用`@Configuration`修饰一下。像这样 10 | 11 | ``` js 12 | import { Configuration, AuthorityInterceptor } from 'tomatobean'; 13 | 14 | @Configuration 15 | export class AI extends AuthorityInterceptor { 16 | ... 17 | } 18 | ``` 19 | 20 | 如果是model文件则只需要将文件名的后缀改为`xxx.m.js`。TODO:引入修饰符 21 | 22 | 2.在wepack的配置文件中加入扫描路径。格式像这样。 23 | 24 | ``` js 25 | alias: { 26 | // tomato的扫描路径 27 | tomatoScan: path.join(__dirname, './src'), 28 | // 页面路径 29 | pages: path.join(__dirname, './src/pages/'), 30 | } 31 | ``` 32 | #### update3: 变更方法的导出来源 33 | 34 | 曾经需要指明方法具体包的来源,像这样: 35 | 36 | ``` js 37 | // 旧版本 38 | import BaseActions, { Notification, Tabbar } from 'tomatobean/enhance'; 39 | ``` 40 | 最新版本中所有tomatobean提供的方法和对象都可以从更目录中导出,像下面这样: 41 | 42 | ``` js 43 | import {BaseActions, Notification, Tabbar } from 'tomatobean'; 44 | ``` 45 | #### update4: page组件可以使用ES6方式导出 46 | 47 | 曾经导出方式,像这样: 48 | 49 | ``` js 50 | 51 | import React, { Component } from 'react'; 52 | 53 | class View extends Component { 54 | render() { 55 | return ( 56 |
57 | 这是一个页面 58 |
59 | ); 60 | } 61 | } 62 | module.exports = View; 63 | 64 | ``` 65 | 最新版本中可以这样导出,像下面这样: 66 | 67 | ``` js 68 | 69 | import React, { Component } from 'react'; 70 | 71 | export default class View extends Component { 72 | render() { 73 | return ( 74 |
75 | 这是一个页面 76 |
77 | ); 78 | } 79 | } 80 | 81 | ``` 82 | 83 | 84 | 85 | -------------------------------------------------------------------------------- /src/connect/BaseParentRouteConnect.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { connect } from 'react-redux'; 3 | import { bindActionCreators } from 'redux'; 4 | import { parentRouteCompVisible } from '../actions/kitAction.js'; 5 | import { getDisplayName } from '../util/tools'; 6 | /** 7 | * 8 | * @param {*目标函数} Target 9 | * @param {*目标名称} name 10 | * @param {*表述信息} descriptor 11 | */ 12 | 13 | export const BaseParentRoute = (Target) => { 14 | class WithSubscription extends Component { 15 | constructor(props) { 16 | super(props); 17 | this.state = { 18 | bridge: null, 19 | }; 20 | this.bridge = this.bridge.bind(this); 21 | } 22 | /** 23 | * 24 | * 25 | * @param {*通知信息} [info=null] 26 | * @param {*后续操作(可选)} action 27 | * 28 | * @memberof 连接上下级路由,通知作用 29 | */ 30 | bridge(info = null, action) { 31 | this.setState({ 32 | bridge: info, 33 | }); 34 | 35 | setTimeout(() => { 36 | this.setState({ 37 | bridge: null, 38 | }); 39 | if (action) { 40 | action(); 41 | } 42 | }); 43 | } 44 | render() { 45 | const { 46 | children, 47 | parentRouteCompStatus, 48 | actions, 49 | ...props 50 | } = this.props; 51 | const childrenO = React.Children.map(children, (o, i) => { 52 | return React.cloneElement(o, { bridge: this.bridge, key: i }); 53 | }); 54 | return ( 55 | 56 |
59 | 60 |
61 |
{childrenO}
62 |
63 | ); 64 | } 65 | } 66 | WithSubscription.displayName = `BaseParentRouteConnect(${getDisplayName(Target)})`; 67 | function mapState(state) { 68 | return { parentRouteCompStatus: state.parentRouteCompStatus }; 69 | } 70 | 71 | function mapDispatch(dispatch) { 72 | return { 73 | actions: bindActionCreators({ parentRouteCompVisible }, dispatch), 74 | }; 75 | } 76 | return connect(mapState, mapDispatch)(WithSubscription); 77 | }; 78 | -------------------------------------------------------------------------------- /src/connect/BaseComponent.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { connect } from 'react-redux'; 3 | import { bindActionCreators } from 'redux'; 4 | import { checkAuthority } from '../actions/bizAction'; 5 | import { getDisplayName } from '../util/tools'; 6 | /** 7 | * 8 | * @param {*目标组件} Comp 9 | * @param {*回调函数} callBack 10 | */ 11 | export const BaseComponent = (Comp, callBack) => { 12 | class WithSubscription extends Component { 13 | componentDidMount() { 14 | callBack(this.props.location); 15 | } 16 | render() { 17 | const { 18 | ...props 19 | } = this.props; 20 | return ( 21 | 22 | 23 | 24 | ); 25 | } 26 | } 27 | WithSubscription.displayName = `BaseComponentConnect(${getDisplayName(Comp)})`; 28 | 29 | return WithSubscription; 30 | }; 31 | /** 32 | * 33 | * @param {*目标函数} Target 34 | * @param {*目标名称} name 35 | * @param {*表述信息} descriptor 36 | */ 37 | 38 | export const RootRoute = (Target) => { 39 | const WithSubscription = (props) => { 40 | const { 41 | children, 42 | authorityStatus, 43 | dispatch, 44 | ...others 45 | } = props; 46 | const actions = bindActionCreators({ checkAuthority }, dispatch); 47 | 48 | return ( 49 | 50 | {authorityStatus ? 51 | 52 | 53 | {/*
{children}
*/} 54 |
: ''} 55 |
56 | ); 57 | }; 58 | WithSubscription.displayName = `RootRouteConnect(${getDisplayName(Target)})`; 59 | function mapState(state) { 60 | return { authorityStatus: state.authorityStatus }; 61 | } 62 | return connect(mapState)(WithSubscription); 63 | }; 64 | 65 | /** 66 | * 67 | * @param {*目标函数} Target 68 | * @param {*目标名称} name 69 | * @param {*表述信息} descriptor 70 | */ 71 | export const readonly = (target, name, descriptor) => { 72 | descriptor.writable = false; 73 | return descriptor; 74 | }; 75 | 76 | 77 | export const decorateArmour = (target, key, descriptor) => { 78 | const method = descriptor.value; 79 | // console.log(descriptor, target, key); 80 | 81 | const moreDef = 100; 82 | let ret; 83 | descriptor.value = (...args) => { 84 | args[0] += moreDef; 85 | ret = method.apply(target, args); 86 | return ret; 87 | }; 88 | return descriptor; 89 | }; 90 | -------------------------------------------------------------------------------- /src/util/ajax.js: -------------------------------------------------------------------------------- 1 | /** 2 | * File: /Users/fengchengpu/Project/moonlight/src/util/ajax.js 3 | * Project: /Users/fengchengpu/Project/moonlight 4 | * Created Date: Saturday November 11th 2017 6:00:32 pm 5 | * Author: chengpu 6 | * ----- 7 | * Last Modified:Saturday November 11th 2017 6:00:32 pm 8 | * Modified By: chengpu 9 | * ----- 10 | * 11 | */ 12 | import { message } from 'antd'; 13 | /** 14 | * 15 | * @param option option [{ 16 | * url:地址 17 | * method: "get"|"post",默认为"get" 18 | * data: {} 19 | * }] 20 | * @param response function 21 | * @constructor 22 | */ 23 | let flag = true; 24 | export default function Ajax(option, response, error) { 25 | // $.when( ).done(function (a) {}); 26 | $.ajax({ 27 | url: option.url, 28 | method: option.method || 'GET', 29 | data: option.data || {}, 30 | dataType: 'json', 31 | // async: false, 32 | // timeout : 50000, //超时时间:50秒 33 | beforeSend(req) { 34 | req.setRequestHeader('token', localStorage.token); 35 | }, 36 | contentType: option.contentType || 'application/json', 37 | success(data) { 38 | if (data.code === '401') { 39 | if (flag) { 40 | message.error(data.message, 2); 41 | flag = false; 42 | } 43 | setTimeout(() => { 44 | window.location.href = '/login'; 45 | }, 1000); 46 | } else { 47 | response(data); 48 | } 49 | }, 50 | error(XMLHttpRequest) { 51 | if (XMLHttpRequest.status === 401) { 52 | if (XMLHttpRequest.responseJSON && XMLHttpRequest.responseJSON.code === '401') { 53 | message.error(XMLHttpRequest.responseJSON, 2); 54 | setTimeout(() => { 55 | window.location.href = '/login.html'; 56 | }, 1000); 57 | } 58 | } 59 | if (error) { 60 | error(XMLHttpRequest.responseJSON); 61 | } 62 | }, 63 | }); 64 | } 65 | export const AjaxNor = (option, response, error) => { 66 | // $.when( ).done(function (a) {}); 67 | $.ajax({ 68 | url: option.url, 69 | method: option.method || 'GET', 70 | data: option.data || {}, 71 | dataType: 'json', 72 | xhrFields: { 73 | withCredentials: true, 74 | }, 75 | crossDomain: true, 76 | // async: false, 77 | // timeout : 50000, //超时时间:50秒 78 | beforeSend(req) { 79 | req.setRequestHeader('token', localStorage.token); 80 | }, 81 | contentType: option.contentType || 'application/json', 82 | success(data) { 83 | response(data); 84 | }, 85 | error(XMLHttpRequest) { 86 | if (error) { 87 | error(XMLHttpRequest.responseJSON); 88 | } 89 | }, 90 | }); 91 | }; 92 | -------------------------------------------------------------------------------- /src/components/tabbar/Tabbar.jsx: -------------------------------------------------------------------------------- 1 | /** 2 | * File: /Users/fengchengpu/Project/moonlight/src/components/tabbar/Tabbar.jsx 3 | * Project: /Users/fengchengpu/Project/moonlight 4 | * Created Date: Friday November 10th 2017 2:39:53 pm 5 | * Author: chengpu 6 | * ----- 7 | * Last Modified:Friday November 10th 2017 2:39:53 pm 8 | * Modified By: chengpu 9 | * ----- 10 | * 11 | */ 12 | 13 | import React from 'react'; 14 | import { connect } from 'react-redux'; 15 | import { bindActionCreators } from 'redux'; 16 | import { tabBarDecrementAndRedirect, linkTo } from '../../actions/kitAction.js'; 17 | import './tabbar.less'; 18 | 19 | const Tabbar = (props) => { 20 | const link = (e, actions, location, routing) => { 21 | e.stopPropagation(); 22 | if (!routing.locationBeforeTransitions 23 | || routing.locationBeforeTransitions.pathname !== location.pathname) { 24 | actions.linkTo(location); 25 | } 26 | }; 27 | const decrementAndRedirect = (e, actions, location) => { 28 | e.stopPropagation(); 29 | actions.tabBarDecrementAndRedirect(location); 30 | }; 31 | const { tabBarLocations, actions, routing } = props; 32 | const loopTabBars = data => (data.map((location, i) => { 33 | let active = 'tabbar-normal'; 34 | if (location.state && location.state.mark) { 35 | if (routing.locationBeforeTransitions 36 | && routing.locationBeforeTransitions.state 37 | && routing.locationBeforeTransitions.state.mark 38 | && (routing.locationBeforeTransitions.state.mark === location.state.mark)) { 39 | active = 'tabbar-active'; 40 | } 41 | if (routing.locationBeforeTransitions 42 | && routing.locationBeforeTransitions.pathname === location.pathname 43 | && location.state.mark) { 44 | active = 'tabbar-active'; 45 | } 46 | } 47 | 48 | if (i === 0) { 49 | return ( 50 | { link(e, actions, location, routing); }} className={`tabbar-cell ${active}`} key={location.state.mark}> 51 |