├── 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 |
52 | {location.state.mark}
53 | );
54 | } else {
55 | return (
56 | { link(e, actions, location, routing); }} className={`tabbar-cell ${active}`} key={location.state.mark}>
57 |
58 | {location.state.mark}
59 | { decrementAndRedirect(e, actions, location); }} />
60 | );
61 | }
62 | }));
63 |
64 | return (
65 |
66 | {loopTabBars(tabBarLocations)}
67 |
68 |
69 | );
70 | };
71 | function mapState(state) {
72 | return { tabBarLocations: state.tabBarLocations, routing: state.routing };
73 | }
74 |
75 | function mapDispatch(dispatch) {
76 | return {
77 | actions: bindActionCreators({ tabBarDecrementAndRedirect, linkTo }, dispatch),
78 | };
79 | }
80 |
81 | export default connect(mapState, mapDispatch)(Tabbar);
82 |
--------------------------------------------------------------------------------
/src/actions/kitAction.js:
--------------------------------------------------------------------------------
1 | import { push, replace, goBack as back, goForward as forward, go as goto } from 'react-router-redux';
2 | import { TABBAR_INCREMENT, TABBAR_DECREMENT, PARENT_ROUTE_COMP_VIS, STATE_ROLL_BACK } from '../constants/kitTypes';
3 |
4 | /**
5 | * 新增头部导航标签
6 | * @param {*当前历史记录} currentLocation
7 | */
8 | export function tabBarIncrement(currentLocation) {
9 | return { type: TABBAR_INCREMENT, currentLocation };
10 | }
11 | /**
12 | * 删除头部导航标签
13 | * @param {*any} currentLocation
14 | */
15 | export function tabBarDecrementAndRedirect(currentLocation) {
16 | // console.log(currentLocation);
17 | return (dispatch, getState) => {
18 | const { tabBarLocations, routing } = getState();
19 | const currentPathname = currentLocation.pathname;
20 | const routingPathname = routing.locationBeforeTransitions.pathname;
21 | if (tabBarLocations.length > 1) {
22 | for (let i = 0, len = tabBarLocations.length; i < len; i++) {
23 | const locationPathname = tabBarLocations[i].pathname;
24 | if (locationPathname === currentPathname) {
25 | if (i < tabBarLocations.length - 1) {
26 | if (routingPathname === currentPathname) {
27 | dispatch(redirect(tabBarLocations[i + 1]));
28 | }
29 | } else if (routingPathname === currentPathname) {
30 | dispatch(redirect(tabBarLocations[i - 1]));
31 | }
32 | }
33 | }
34 | }
35 |
36 | dispatch(tabBarDecrement(currentLocation));
37 | };
38 | }
39 | /**
40 | * 删除头部导航标签
41 | * @param {*当前历史记录} currentLocation
42 | */
43 | export function tabBarDecrement(currentLocation) {
44 | return { type: TABBAR_DECREMENT, currentLocation };
45 | }
46 | /**
47 | * 重定向
48 | * @param {*定向地址} location
49 | */
50 | export function redirect(location) {
51 | return (dispatch) => {
52 | dispatch(replace(location));
53 | };
54 | }
55 | /**
56 | * 跳转
57 | * @param {*定向地址} location
58 | * @returns
59 | */
60 | export function linkTo(location) {
61 | return (dispatch) => {
62 | dispatch(push(location));
63 | };
64 | }
65 | /**
66 | * 回退
67 | * @export
68 | * @returns
69 | */
70 | export function goBack() {
71 | return (dispatch) => {
72 | dispatch(back());
73 | };
74 | }
75 | /**
76 | *
77 | * 前进
78 | * @export
79 | * @returns
80 | */
81 | export function goForward() {
82 | return (dispatch) => {
83 | dispatch(forward());
84 | };
85 | }
86 | /**
87 | *
88 | * 跳转到指定的历史记录
89 | * @export
90 | * @param {*页码} number
91 | * @returns
92 | */
93 | export function go(number) {
94 | return (dispatch) => {
95 | dispatch(goto(number));
96 | };
97 | }
98 | /**
99 | *
100 | * 多级路由下控制上级路由的显隐
101 | * @param {*是否显隐} statue
102 | */
103 |
104 | export function parentRouteCompVisible(statue) {
105 | return { type: PARENT_ROUTE_COMP_VIS, visible: statue };
106 | }
107 | /**
108 | * 使一个state值回滚到初始值
109 | * @param {*} statue
110 | */
111 | export function rollBack(namespace) {
112 | return { type: STATE_ROLL_BACK, namespace };
113 | }
114 |
--------------------------------------------------------------------------------
/src/util/request.js:
--------------------------------------------------------------------------------
1 | /**
2 | * File: /Users/fengchengpu/Project/TomatoProject/moon/src/tomatobean/util/request.js
3 | * Project: /Users/fengchengpu/Project/TomatoProject/moon
4 | * Created Date: Saturday January 13th 2018 4:06:18 pm
5 | * Author: chengpu
6 | * -----
7 | * Last Modified:Saturday January 13th 2018 4:06:18 pm
8 | * Modified By: chengpu
9 | * -----
10 | * Copyright (c) 2018 MagCloud
11 | */
12 | import fetch from 'isomorphic-fetch';
13 | import { urlAppendQuery } from '../util/tools';
14 |
15 | function checkStatus(response) {
16 | if (response.status >= 200 && response.status < 300) {
17 | return response;
18 | }
19 | if (response.status === 401) {
20 | // window.location = '/login';
21 | }
22 | console.error(`请求错误 ${response.status}: ${response.url}`, response.statusText,);
23 | const error = new Error(response.statusText);
24 | error.response = response;
25 | throw error;
26 | }
27 |
28 | function send(url, options, autoTips) {
29 | const defaultOptions = {
30 | // credentials: "include",
31 | headers: {
32 | 'X-Auth-Token': localStorage.token,
33 | },
34 | };
35 | const newOptions = { ...defaultOptions, ...options };
36 | if (newOptions.method === 'POST' || newOptions.method === 'PUT') {
37 | newOptions.headers = {
38 | Accept: 'application/json',
39 | 'Content-Type': 'application/x-www-form-urlencoded; charset=utf-8',
40 | // "Content-Type": "application/json; charset=utf-8",
41 | ...newOptions.headers,
42 | };
43 | if (newOptions.body) {
44 | let data = new URLSearchParams();
45 | Object.keys(newOptions.body).map(v => data.set(v, newOptions.body[v]));
46 | if (/multipart/.test(newOptions.headers['Content-Type'])) {
47 | newOptions.headers['Content-Type'] = 'multipart/form-data';
48 | data = new FormData();
49 | Object.keys(newOptions.body).map(v => data.append(v, newOptions.body[v]));
50 | }
51 | newOptions.body = data;
52 | // newOptions.body = JSON.stringify(newOptions.body);
53 | }
54 | }
55 |
56 | // 拼接路径参数
57 | let newUrl = url;
58 | if (options && options.params) {
59 | newUrl = urlAppendQuery(url, options.params);
60 | }
61 |
62 | const checkBiz = response => response.json().then((res) => {
63 | if (autoTips) {
64 | if (!res.success) {
65 | notification.error({
66 | message: res.msg,
67 | });
68 | } else if (res.msg) {
69 | notification.success({
70 | message: res.msg,
71 | });
72 | }
73 | }
74 | return res;
75 | });
76 | return fetch(newUrl, newOptions)
77 | .then(checkStatus)
78 | .then(checkBiz)
79 | .catch((error) => {
80 | if (error.code) {
81 | notification.error({
82 | message: error.name,
83 | description: error.message,
84 | });
85 | }
86 | if ('stack' in error && 'message' in error) {
87 | notification.error({
88 | message: `请求错误: ${url}`,
89 | description: error.message,
90 | });
91 | }
92 | return error;
93 | });
94 | }
95 | const request = {
96 | GET(url, options, autoTips) {
97 | if (typeof options !== 'object') {
98 | return send(url, { method: 'GET' }, options);
99 | }
100 | return send(url, { ...options, method: 'GET' }, autoTips);
101 | },
102 | POST(url, options, autoTips) {
103 | if (typeof options !== 'object') {
104 | return send(url, { method: 'POST' }, options);
105 | }
106 | return send(url, { ...options, method: 'POST' }, autoTips);
107 | },
108 | PUT(url, options, autoTips) {
109 | if (typeof options !== 'object') {
110 | return send(url, { method: 'PUT' }, options);
111 | }
112 | return send(url, { ...options, method: 'PUT' }, autoTips);
113 | },
114 | DELETE(url, options, autoTips) {
115 | if (typeof options !== 'object') {
116 | return send(url, { method: 'DELETE' }, options);
117 | }
118 | return send(url, { ...options, method: 'DELETE' }, autoTips);
119 | },
120 | };
121 | export default request;
122 |
--------------------------------------------------------------------------------
/src/util/tools.js:
--------------------------------------------------------------------------------
1 | /**
2 | * File: /Users/fengchengpu/Project/moonlight/src/util/tools.js
3 | * Project: /Users/fengchengpu/Project/moonlight
4 | * Created Date: Saturday November 11th 2017 6:13:58 pm
5 | * Author: chengpu
6 | * -----
7 | * Last Modified:Saturday November 11th 2017 6:13:58 pm
8 | * Modified By: chengpu
9 | * -----
10 | *
11 | */
12 | /**
13 | * 按关键字分组(将一维数组分成二维数组)
14 | *
15 | * @param {Array} array
16 | * @param {String} key
17 | * @returns { false | Array