layout布局

50 阅读3分钟
import empty from '@/Images/others/empty.png';
import GetImg from '@/components/GetImg';
import Header from '@/components/Header';
import { QiankunMainProvider } from '@/qiankun/qiankunConfig';
import connectQiankun from '@/qiankun/state';
import useMenus from '@/qiankun/useMenu';
import { getBusinessInfo } from '@/services/businessInfoEdit';
import { MenuFoldOutlined, MenuUnfoldOutlined } from '@ant-design/icons';
import ProLayout from '@ant-design/pro-layout';
import { UNVMessageBox, UNVModal } from 'UNV-DESIGN';
import { Alert, Button, ConfigProvider, Space } from 'antd';
import axios from 'axios';
import React, { useEffect, useMemo, useState } from 'react';
import { history, useIntl } from 'umi';
import uniview from '../../public/uniview.png';
import AccountManage from '../Images/menuImages/AccountManage.png';
import AuthManage from '../Images/menuImages/AuthManage.png';
import Business from '../Images/menuImages/Business.png';
import CounterpartProduct from '../Images/menuImages/CounterpartProduct.png';
import ErrorFeedback from '../Images/menuImages/ErrorFeedback.png';
import EvaluatedMaintain from '../Images/menuImages/EvaluatedMaintain.png';
import GeneIcon from '../Images/menuImages/GeneIcon.png';
import KnowledgeBase from '../Images/menuImages/KnowledgeBase.png';
import quot from '../Images/menuImages/quot.png';
import OperationLog from '../Images/menuImages/OperationLog.png';
import OperatorDataUpload from '../Images/menuImages/OperatorDataUpload.png';
import PartsBatchMaintain from '../Images/menuImages/PartsBatchMaintain.png';
import ProductCatalog from '../Images/menuImages/ProductCatalog.png';
import ProductColorPage from '../Images/menuImages/ProductColorPage.png';
import ProductFileUpload from '../Images/menuImages/ProductFileUpload.png';
import ProductLaunch from '../Images/menuImages/ProductLaunch.png';
import ProductMetaData from '../Images/menuImages/ProductMetaData.png';
import ProductParamConfig from '../Images/menuImages/ProductParamConfig.png';
import ProductShelfCategory from '../Images/menuImages/ProductShelfCategory.png';
import ProductShelves from '../Images/menuImages/ProductShelves.png';
import ProjectFileUpload from '../Images/menuImages/ProjectFileUpload.png';
import ProjectPublishManagement from '../Images/menuImages/ProjectPublishManagement.png';
import ShutdownSwitch from '../Images/menuImages/ShutdownSwitch.png';
import SolutionParamConfig from '../Images/menuImages/SolutionParamConfig.png';
import SpecCheck from '../Images/menuImages/SpecCheck.png';
import SpecEdit from '../Images/menuImages/SpecEdit.png';
import SubscriptManage from '../Images/menuImages/SubscriptManage.png';
import TemplateManage from '../Images/menuImages/TemplateManage.png';
import BehaviorAnalysis from '../Images/menuImages/BehaviorAnalysis.png';
import TenderGuide from '../Images/menuImages/TenderGuide.png';
import ToolImg from '../Images/menuImages/ToolImg.png';
import batchEditIcon from '../Images/menuImages/batchEditIcon.png';
import menuForPromotionParams from '../Images/menuImages/menuForPromotionParams.png';
import menuForPromotionUpload from '../Images/menuImages/menuForPromotionUpload.png';
import saleCountry from '../Images/menuImages/saleCountry.png';
import picOverlay from '../Images/menuImages/picOverlay.png';
import thirdPart from '../Images/menuImages/thirdPart.png';
import CustomizedProductMaintenance from '../Images/menuImages/CustomizedProductMaintenance.png';
import ServiceNewsIcon from '../Images/menuImages/ServiceNewsIcon.png';
import handover from '../Images/menuImages/handover.png';
import Notice from '../Images/menuImages/notice.png';
import supportProduct from '../Images/menuImages/supportProduct.png';
import helpIcon from '../Images/menuImages/helpIcon.png';
import exchanged from '../Images/menuImages/exchanged.png';
import SogouExplorer from '../Images/others/SogouExplorer.png';
import chrome from '../Images/others/chrome.png';
import msedge from '../Images/others/msedge.png';
import styles from './index.less';

const getAppFromUrl = (url: string) => {
  const res = url.split('/');
  if (res && res.length > 2) {
    return `/${res[2]}`;
  }
  return '/';
};

const getIcon = (iconString: string) => {
  switch (iconString) {
    case 'SpecEdit':
      return <img src={SpecEdit} alt="" />;
    case 'TemplateManage':
      return <img src={TemplateManage} alt="" />;
    case 'ProductParamConfig':
    case 'ParamsConfig':
    case 'OperatorParamConfig':
    case 'SupportParamConfig':
    case 'FeedbackParamsConfig':
    case 'SystemFileParamConfig':
    case 'TenderDataConfig':
      return <img src={ProductParamConfig} alt="" />;
    case 'TenderGuide':
    case 'TenderGuideCheck':
      return <img src={TenderGuide} alt="" />;
    case 'ProductColorPage':
    case 'ProductColorPageInspect':
      return <img src={ProductColorPage} alt="" />;
    case 'ProductMetaData':
    case 'MarketMetaData':
    case 'MarketMetaDataCheck':
      return <img src={ProductMetaData} alt="" />;
    case 'ProductShelfCategory':
      return <img src={ProductShelfCategory} alt="" />;
    case 'SpecCheck':
      return <img src={SpecCheck} alt="" />;
    case 'ProductFileUpload':
    case 'ProductFileCheck':
    case 'TechnicalFileUpload':
    case 'TechnicalFileCheck':
    case 'BidDataManage':
    case 'TrainDataUpload':
    case 'SystemFile':
    case 'SystemFileCheck':
    case 'TenderDataUpload':
    case 'TenderDataCheck':
    case 'PublicBiddingKnowledge':
    case 'SecretBiddingKnowledge':
    case 'PersonCertificateManage':
    case 'CompanyCertificationManage':
    case 'HonorMaterialManage':
    case 'KnowledgePropertyManage':
    case 'BusinessContractManage':
    case 'BiddingMaterialReview':
      return <img src={ProductFileUpload} alt="" />;
    case 'ProductLaunch':
      return <img src={ProductLaunch} alt="" />;
    case 'Business':
      return <img src={Business} alt="" />;
    case 'ShutdownSwitch':
      return <img src={ShutdownSwitch} alt="" />;
    case 'PartsBatchMaintain':
      return <img src={PartsBatchMaintain} alt="" />;
    case 'ProductCatalog':
      return <img src={ProductCatalog} alt="" />;
    case 'AreaManagement':
    case 'CombinationManage':
      return <img src={ProductShelves} alt="" />;
    case 'ProjectPublishManagement':
    case 'ProjectCheck':
      return <img src={ProjectPublishManagement} alt="" />;
    case 'ProjectFileUpload':
    case 'ProjectFileCheck':
      return <img src={ProjectFileUpload} alt="" />;
    case 'ProjectReleaseManagement':
      return <img src={ProductShelves} alt="" />;
    case 'SolutionParamConfig':
      return <img src={SolutionParamConfig} alt="" />;
    case 'AccountManage':
    case 'AccountExt':
      return <img src={AccountManage} alt="" />;
    case 'AuthManage':
      return <img src={AuthManage} alt="" />;
    case 'ErrorFeedBack':
      return <img src={ErrorFeedback} alt="" />;
    case 'EvaluatedMaintain':
      return <img src={EvaluatedMaintain} alt="" />;
    case 'OperationLog':
      return <img src={OperationLog} alt="" />;
    case 'PublishNotice':
      return <img src={Notice} alt="" />;
    case 'PublishNoticeAudit':
      return <img src={Notice} alt="" />;
    case 'OperatorFileUpload':
    case 'OperatorFileCheck':
      return <img src={OperatorDataUpload} alt="" />;
    case 'BrandPromotionFileUpload':
      return <img src={menuForPromotionUpload} alt="" />;
    case 'BrandParamConfig':
      return <img src={menuForPromotionParams} alt="" />;
    case 'SubscriptManage':
      return <img src={SubscriptManage} alt="" />;
    case 'ToolMaintain':
    case 'ToolSetting':
    case 'ToolCheck':
      return <img src={ToolImg} alt="" />;
    case 'GenealogyManage':
    case 'MetaDocumentUpload':
    case 'MetaFileCheck':
      return <img src={GeneIcon} alt="" />;
    case 'CounterpartProduct':
    case 'CounterpartProductEn':
      return <img src={CounterpartProduct} alt="" />;
    case 'KnowledgeBase':
      return <img src={KnowledgeBase} alt="" />;
    case 'BatchEditSpec':
      return <img src={batchEditIcon} alt="" />;
    case 'CustomizedProductMaintenance':
      return <img src={CustomizedProductMaintenance} />;
    case 'ThirdPartDocking':
      return <img src={thirdPart} />;
    case 'PointExchangeRecord ':
      return <img src={exchanged} alt="" />;
    case 'ImageOverlay':
      return <img src={picOverlay} alt="pic" />;
    case 'QuotationAndProduct':
      return <img src={quot} alt="" />;
    case 'ProductModuleCheck ':
      return <img src={SpecCheck} alt="pic" />;
    case 'ProductSelection':
      return <img src={TemplateManage} alt="pic" />;
    case 'BehaviorAnalysis':
      return <img src={BehaviorAnalysis} alt="pic" />;
    case 'WorkHandover':
    case 'WorkReception':
      return <img src={handover} alt="pic" />;
    case 'SupportProduct':
      return <img src={supportProduct} alt="pic" />;
    case 'BrandDataUpload':
      return <img src={menuForPromotionUpload} alt="pic" />;
    case 'BrandDataManage':
      return <img src={menuForPromotionParams} alt="pic" />;
    case 'OnlineHelp':
      return <img src={helpIcon} alt="pic" />;
    case 'ServiceNews':
    case 'ServiceNewsCheck':
      return <img src={ServiceNewsIcon} alt="pic" />;
    case 'SaleCountry':
      return <img src={saleCountry} alt="pic" />;
    default:
      return <></>;
  }
};

const customEmpty = () => (
  <div className={styles.layout_customEmpty_wrapper}>
    <img src={empty} />
    <span>{intl.formatMessage({ id: 'No data' })}</span>
  </div>
);

interface MenuType {
  path?: string;
  icon?: React.ReactElement;
  name?: string;
  id?: number;
  parentId?: number;
  routes?: MenuType[];
}

const Layouts = (props: any) => {
  const { children } = props;

  // 控制左侧栏菜单展开/收起
  const [collapsed, setCollapsed] = useState(false);

  // 获取到当前的菜单列表
  const [menuList] = useMenus();

  // 当前选中的一级菜单
  const [currentFirstMenu, setCurrentFirstMenu] = useState<any>(0);

  // 当前格式化后的菜单列表
  const [menus, setMenus] = useState<MenuType[]>([]);

  // 当前平铺的菜单
  const [allMenus, setAllMenus] = useState<MenuType[]>([]);

  // 工作台logo
  const [workLogo, setWorkLogo] = useState<string>('');

  // 浏览器不兼容提示
  const [browserWarningType, setBrowserWarningType] = useState<number>(0);

  useEffect(() => {
    const ua = navigator.userAgent;
    // 当前浏览器是否为大于79版本的Chrome内核
    if (ua.indexOf('Chrome') === -1) {
      setBrowserWarningType(1);
    } else if (!(Number(ua.match(/Chrome\/(\d+)/)?.[1]) >= 79)) {
      setBrowserWarningType(2);
    }
  }, []);

  // 全局注入国际化
  window.intl = useIntl();
  // 全局注入多选规格枚举值分隔符
  window.intl.separator = BUILD_ENV !== 'zh-CN' ? '|' : '|';
  // const [version, setVersion] = useState('');
  const [showRefreshMessage, setShowRefreshMessage] = useState(false);
  useEffect(() => {
    checkVersion();
    const intervalId = setInterval(checkVersion, 1800000); // 每30分钟检查一次版本
    return () => clearInterval(intervalId); // 清除定时器
  }, []);
  async function checkVersion() {
    // 发送请求检查应用程序版本
    const response = await axios.get('/bench/version.json'); // 比较当前版本和最新版本是否一致
    if (localStorage.version === undefined) {
      localStorage.setItem('version', response.data.version);
    } else {
      if (String(localStorage.version) !== String(response.data.version)) {
        // setVersion(response.data.version);
        setShowRefreshMessage(true);
      }
    }
  }

  /**
   * @method  刷新页面以加载最新版本
   * @param
   */
  const _handleRefresh = () => {
    localStorage.removeItem('version');
    window.location.reload();
  };

  /**
   * @method  跳过更新
   */
  const _noRefresh = () => {
    localStorage.removeItem('version');
    setShowRefreshMessage(false);
  };

  // 标准化数据和存储所有的数据
  useEffect(() => {
    if (Array.isArray(menuList) && menuList.length > 0) {
      const routes: MenuType[] = [];
      const allData: MenuType[] = [];
      const format = (data: any, result: MenuType[]) => {
        data.forEach((item: any) => {
          const newItem: MenuType = {
            name: item.name,
            id: item.id,
            parentId: item.parentId
          };
          allData.push({
            ...item,
            name: item.name,
            id: item.id,
            parentId: item.parentId
          });
          if (item.icon) {
            newItem.icon = getIcon(item.icon);
          }
          if (item.path) {
            newItem.path = item.path;
          }
          if (Array.isArray(item.children) && item.children.length > 0) {
            newItem.routes = [];
            format(item.children, newItem.routes);
          }
          result.push(newItem);
        });
        return result;
      };

      format(
        menuList.filter((item: any) => item.type !== '6'),
        routes
      );
      let newRoutes: Array<any> = [];
      let newData: Array<any> = [];
      if (BUILD_ENV === 'zh-CN') {
        newData = allData.filter(
          (item: any) => item.path !== '/CounterpartProductEn'
        );
        newRoutes = routes.map((item: any) => {
          const { path, routes } = item;
          let tempRoutes: Array<any> = [];
          if (path === '/ProductLaunch') {
            tempRoutes = routes.filter(
              (item: any) => item.path !== '/CounterpartProductEn'
            );

            return {
              ...item,
              routes: tempRoutes
            };
          } else {
            return item;
          }
        });
      } else {
        newData = allData.filter(
          (item: any) => item.path !== '/CounterpartProduct'
        );
        newRoutes = routes.map((item: any) => {
          const { path, routes } = item;
          let tempRoutes: Array<any> = [];
          if (path === '/ProductLaunch') {
            tempRoutes = routes.filter(
              (item: any) => item.path !== '/CounterpartProduct'
            );
            return {
              ...item,
              routes: tempRoutes
            };
          } else {
            return item;
          }
        });
      }
      setMenus(newRoutes);
      setAllMenus(newData);
    }
  }, [menuList]);

  // 当菜单发生改变,设置默认选中一级菜单
  // useEffect(() => {
  //   if (Array.isArray(menus) && menus.length > 0 && currentFirstMenu) {
  //     setCurrentFirstMenu(menus[0] ? menus[0].id : 0);
  //   }
  // }, [menus]);

  // 获取logo信息
  const getLogoImg = async () => {
    const result = await getBusinessInfo({});
    if (result && result.code === 0) {
      const { data = {}} = result;
      setWorkLogo(data.workLogoUrl);
    }
  };
  useEffect(() => {
    getLogoImg();
  }, []);

  // 选中一级菜单后,设置左侧栏的子菜单
  const menuFormat = useMemo(() => {
    if (menus && menus.length > 0) {
      const menu: MenuType | undefined = menus.find(
        (item: MenuType) => item.id === currentFirstMenu
      );
      return { routes: menu ? menu.routes : [] };
    }
    return { routes: [] };
  }, [currentFirstMenu, menus]);

  // 刷新路由时,设置选中的一级、子菜单
  useEffect(() => {
    if (Array.isArray(menus) && menus.length > 0 && window.location.pathname) {
      const res = getAppFromUrl(window.location.pathname);
      if (res) {
        let currentItem: MenuType = {};
        const getId = (list: MenuType[]) => {
          for (let i = 0; i < list.length; i++) {
            const item: MenuType = list[i];
            if (item.path === res) {
              currentItem = item;
              break;
            } else if (Array.isArray(item.routes) && item.routes.length > 0) {
              getId(item.routes);
            }
          }
        };
        getId(menus);

        if (currentItem && currentItem.id && currentItem.parentId) {
          let firstMenu = 0;
          const findFirstMenu = (cItem: MenuType) => {
            const parentItem = allMenus.find(
              (item: MenuType) => item.id === cItem?.parentId
            );
            if (!parentItem) {
              firstMenu = cItem.id as number;
            } else {
              findFirstMenu(parentItem);
            }
          };

          findFirstMenu(currentItem);

          setCurrentFirstMenu(firstMenu);
          // console.log('数据权限又足了吗', currentItem, menus, firstMenu);
        }
        // } else {
        //   console.log('数据权限不足吗');
        //   console.log('currentItemcurrentItem', currentItem, menus);
        //   UNVMessageBox.warn(
        //     intl.formatMessage({
        //       id: 'No product data permission. Please contact admin'
        //     })
        //   );
        //   history.push('/Home');
        // }
      }
    }
  }, [window.location.pathname, menus]);

  // 设置当前的选中路由
  const getLocation = useMemo(() => {
    if (window.location.pathname) {
      if (currentFirstMenu) {
        const res = getAppFromUrl(window.location.pathname);
        return res || '';
      }
      return '';
    }
    return '';
  }, [window.location.pathname, currentFirstMenu]);

  const menuClick = (e: { [key: string]: any }) => {
    if (e.path) {
      history.push(e.path);
    } else {
      console.error('路由错误');
    }
  };

  const titleTimer = setTimeout(() => {
    document.title = intl.formatMessage({ id: 'My Workspace' });
    clearTimeout(titleTimer);
  });

  const menuItemOnClick = (item: any) => {
    history.push(item.path);
  };

  return (
    <ConfigProvider autoInsertSpaceInButton={false} renderEmpty={customEmpty}>
      {!!browserWarningType && (
        <Alert
          message={
            <div>
              {browserWarningType === 1 ?
                intl.formatMessage({
                  id: 'The current browser is not supported. Please use the recommended browser.'
                }) :
                intl.formatMessage({
                  id: 'The current browser version is too low. Please upgrade.'
                })}
              :
              <img src={chrome} />
              <a href="https://www.google.cn/chrome/index.html" target="_blank">
                Chrome
              </a>
              <img src={msedge} />
              <a
                href="https://www.microsoft.com/zh-cn/edge/download"
                target="_blank"
              >
                Edge
              </a>
              <img src={SogouExplorer} />
              <a href="https://ie.sogou.com/" target="_blank">
                搜狗浏览器
              </a>
            </div>
          }
          className={styles.banner}
          banner
          closable
          onClose={() => setBrowserWarningType(0)}
        />
      )}
      {getAppFromUrl(window.location.pathname).toUpperCase() === '/LOGIN' ||
      getAppFromUrl(window.location.pathname).toUpperCase() === '/' ? (
          <div
            className={
              browserWarningType ?
                `${styles.baseLayouts} ${styles.haveBanner}` :
                styles.baseLayouts
            }
          >
            {children}
          </div>
        ) : (
          <ProLayout
            className={`
              ${browserWarningType ? styles.haveBanner : ''}
              ${
          getAppFromUrl(window.location.pathname).toUpperCase() ===
                  '/HOME' ||
                getAppFromUrl(window.location.pathname).toUpperCase() ===
                  '/HELPCENTER' ||
                getAppFromUrl(window.location.pathname).toUpperCase() ===
                  '/DATAACCOUNT' ||
                getAppFromUrl(window.location.pathname).toUpperCase() ===
                  '/TAKEDOWNNOTICE' ?
            `${styles.proContainerNoLeft}` :
            ''
          }
              ${styles.proContainer}
              `}
            logo={
              <div
                className={styles.layouts_index_imgDiv}
                title={intl.formatMessage({ id: 'Go to UNV DIMS' })}
                onClick={() => {
                  window.open(
                    `${window.location.protocol}//${window.location.hostname}`
                  );
                }}
              >
                {workLogo ? (
                  <GetImg src={workLogo} alt="pic" />
                ) : (
                  <img src={uniview} alt="pic" />
                )}
              </div>
            }
            siderWidth={200}
            title={intl.formatMessage({ id: 'My Workspace' })}
            location={{ pathname: getLocation }}
            route={menuFormat}
            layout="mix" //上方导航栏固定
            headerContentRender={() => {
              return (
                <Header
                  menuItemOnClick={menuItemOnClick}
                  menuList={menus}
                  activeMenuItem={currentFirstMenu}
                  setActiveMenuItem={setCurrentFirstMenu}
                />
              );
            }}
            collapsedButtonRender={() => {
              return (
                <div className={styles.collapsed}>
                  <span
                    onClick={() => {
                      setCollapsed(!collapsed);
                    }}
                  >
                    {collapsed ? <MenuUnfoldOutlined /> : <MenuFoldOutlined />}
                  </span>
                </div>
              );
            }}
            menuItemRender={(_, dom) => {
              return (
                <div
                  onClick={() => {
                    menuClick(_);
                  }}
                >
                  {dom}
                </div>
              );
            }}
            collapsed={collapsed}
          >
            {/* 将设置选中一级目录的方法,传递到子组件中,主要是home中需要使用 */}
            <QiankunMainProvider
              value={{ setActiveMenuItem: setCurrentFirstMenu }}
            >
              <div className={styles.baseLayouts}>{children}</div>
            </QiankunMainProvider>
          </ProLayout>
        )}
      {showRefreshMessage && (
        <UNVModal
          title={intl.formatMessage({ id: 'Version update' })}
          onCancel={() => setShowRefreshMessage(false)}
          visible={showRefreshMessage}
          canDragm
          className={styles.addMark}
          footer={
            <Space>
              <Button type="primary" onClick={_handleRefresh}>
                {intl.formatMessage({ id: 'Refresh Now' })}
              </Button>
              <Button onClick={_noRefresh}>
                {' '}
                {intl.formatMessage({ id: 'Skip updates' })}
              </Button>
            </Space>
          }
        >
          <p>
            {intl.formatMessage({
              id: 'Detected that the system version has been updated. Please refresh before using it'
            })}
          </p>
        </UNVModal>
      )}
    </ConfigProvider>
  );
};

export default connectQiankun(Layouts);

@import '../global.less';

.baseLayouts { width: 100%; height: 100%; }

.headerTitle { color: white; width: 100%; text-align: center; font-size: 18px; font-weight: bold;

h1 { font-size: 14px; font-weight: 400; margin: 0 0 0 8px; } }

.proContainer { overflow: hidden; height: 100%; width: 100%;

&.proContainerNoLeft { :global { .ant-layout-sider { display: none; } } }

:global {

.ant-layout-content {
  background-color: #f5f5f5;
}

.ant-pro-global-header-logo a img {
  height: unset;
}

.ant-pro-sider-link-menu {
  background-color: #333333;
}

.ant-menu-item {
  height: 48px;
  padding-left: 8px !important;

  &:hover {
    background-color: #31414a;
  }
}

.ant-menu-submenu-title {
  padding-left: 8px !important;
}

.anticon-menu-unfold {
  padding-left: 8px !important;
}

.anticon-menu-fold {
  padding-left: 8px
}

.ant-menu-sub {
  .ant-menu-title-content {
    margin-left: 20px;
  }
}

.ant-pro-sider-menu {
  background-color: #333333;
}

.ant-menu-sub {
  background-color: #333333 !important;
}

.ant-menu-item-selected {
  background-color: #2e6381 !important;
}

.ant-pro-menu-item-title {
  color: #fff;
  margin-left: 10px;
}

.ant-layout-sider-children {
  background-color: #333333;
}

.ant-pro-basicLayout-content {
  margin: 10px;
}

.ant-pro-sider-logo {
  height: 50px;
  background-color: #287bab;
}

.ant-pro-global-header-layout-side {
  padding: 0;
  box-shadow: none;
  line-height: 50px;
}

.ant-pro-global-header-logo {
  background-color: #287bab;
  height: 51px;
  padding-left: 15px;

  >a>h1 {
    margin-left: 5px;
    height: 30px;
    font-size: 14px;
    font-weight: 400;
  }
}

.ant-pro-global-header {
  padding: 0;

  >div:first-child {
    width: 220px;
  }

  >div:last-child {
    width: calc(100% - 220px);
  }
}

.ant-menu-item-only-child {
  margin: 0 !important;
  height: 48px !important;
}

.ant-menu-submenu-inline {
  .ant-menu-submenu-title {
    margin: 0;
  }
}

} }

.layouts_index_imgDiv { height: 50px !important; max-width: 110px; }

.layouts_index_imgDiv+h1 { cursor: text; }

.layout_customEmpty_wrapper { margin: 0 auto; padding: 10px 0; color: rgba(0, 0, 0, 0.7); text-align: center;

span { display: block; margin-top: 6px; }

img { max-width: 160px; min-width: 60px; width: 100%; } }

:global { .ant-menu-item-selected { background-color: #2e6381 !important; } }

.haveBanner { height: calc(100% - 38px); min-height: calc(100% - 38px);

:global { .ant-pro-fixed-header { top: 38px !important; } } }

.banner { text-align: center;

img { margin: 0 2px 3px 10px; width: 16px; height: 16px; }

a { text-decoration: underline; } }