menu.ts 3.73 KB
Newer Older
1
import Authorized from '@/utils/Authorized';
2 3 4 5 6 7 8
import { Effect } from 'dva';
import isEqual from 'lodash/isEqual';
import memoizeOne from 'memoize-one';
import { Reducer } from 'redux';
import { formatMessage } from 'umi-plugin-locale';
import defaultSettings from '../../config/defaultSettings';
const { menu } = defaultSettings;
9 10 11
const { check } = Authorized;

// Conversion router to menu.
12
function formatter(data: any[], parentAuthority: string[], parentName: string): any[] {
13 14 15 16 17 18 19 20 21 22 23 24
  return data
    .map(item => {
      if (!item.name || !item.path) {
        return null;
      }

      let locale = 'menu';
      if (parentName) {
        locale = `${parentName}.${item.name}`;
      } else {
        locale = `menu.${item.name}`;
      }
Yu's avatar
Yu committed
25 26 27 28 29
      // if enableMenuLocale use item.name,
      // close menu international
      const name = menu.disableLocal
        ? item.name
        : formatMessage({ id: locale, defaultMessage: item.name });
30 31
      const result = {
        ...item,
Yu's avatar
Yu committed
32
        name,
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
        locale,
        authority: item.authority || parentAuthority,
      };
      if (item.routes) {
        const children = formatter(item.routes, item.authority, locale);
        // Reduce memory usage
        result.children = children;
      }
      delete result.routes;
      return result;
    })
    .filter(item => item);
}

const memoizeOneFormatter = memoizeOne(formatter, isEqual);

49 50 51 52 53 54 55 56 57
interface SubMenuItem {
  children: SubMenuItem[];
  hideChildrenInMenu?: boolean;
  hideInMenu?: boolean;
  name?: any;
  component: any;
  authority?: string[];
  path: string;
}
58 59 60
/**
 * get SubMenu or Item
 */
61
const getSubMenu: (item: SubMenuItem) => any = item => {
62 63 64 65 66 67 68 69 70 71 72 73 74
  // doc: add hideChildrenInMenu
  if (item.children && !item.hideChildrenInMenu && item.children.some(child => child.name)) {
    return {
      ...item,
      children: filterMenuData(item.children), // eslint-disable-line
    };
  }
  return item;
};

/**
 * filter menuData
 */
75
const filterMenuData: (menuData: SubMenuItem[]) => SubMenuItem[] = menuData => {
76 77 78 79 80
  if (!menuData) {
    return [];
  }
  return menuData
    .filter(item => item.name && !item.hideInMenu)
81
    .map(item => check(item.authority, getSubMenu(item), null))
82 83
    .filter(item => item);
};
84 85
/**
 * ่Žทๅ–้ขๅŒ…ๅฑ‘ๆ˜ ๅฐ„
86
 * @param ISubMenuItem[] menuData ่œๅ•้…็ฝฎ
87
 */
88
const getBreadcrumbNameMap: (menuData: SubMenuItem[]) => object = menuData => {
89 90
  const routerMap = {};

91
  const flattenMenuData: (data: SubMenuItem[]) => void = data => {
92 93 94 95 96 97 98 99 100 101 102 103 104
    data.forEach(menuItem => {
      if (menuItem.children) {
        flattenMenuData(menuItem.children);
      }
      // Reduce memory usage
      routerMap[menuItem.path] = menuItem;
    });
  };
  flattenMenuData(menuData);
  return routerMap;
};

const memoizeOneGetBreadcrumbNameMap = memoizeOne(getBreadcrumbNameMap, isEqual);
105

106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122
export interface MenuModelState {
  menuData: any[];
  routerData: any[];
  breadcrumbNameMap: object;
}

export interface MenuModelType {
  namespace: 'menu';
  state: MenuModelState;
  effects: {
    getMenuData: Effect;
  };
  reducers: {
    save: Reducer<any>;
  };
}
const MenuModel: MenuModelType = {
123 124 125 126
  namespace: 'menu',

  state: {
    menuData: [],
Yu's avatar
Yu committed
127
    routerData: [],
128
    breadcrumbNameMap: {},
129 130 131 132 133
  },

  effects: {
    *getMenuData({ payload }, { put }) {
      const { routes, authority } = payload;
Yu's avatar
Yu committed
134 135 136
      const originalMenuData = memoizeOneFormatter(routes, authority);
      const menuData = filterMenuData(originalMenuData);
      const breadcrumbNameMap = memoizeOneGetBreadcrumbNameMap(originalMenuData);
137 138
      yield put({
        type: 'save',
Yu's avatar
Yu committed
139
        payload: { menuData, breadcrumbNameMap, routerData: routes },
140 141 142 143 144 145 146 147
      });
    },
  },

  reducers: {
    save(state, action) {
      return {
        ...state,
148
        ...action.payload,
149 150 151 152
      };
    },
  },
};
153 154

export default MenuModel;