reactjs后台管理系统搭建

1 通过yarn 模板创建reactjs项目

yarn create vite reactjs-antdesign-admin --template react-ts

2 基础路由测试

定义一个router/index.tsx,里面定义路由组件

const Router: React.FC = () => {
  return (
    <HashRouter>
      <Switch>
        <Route path="/" component={Welcome} exact/>
        <Route path="/user" >
          <Switch>
            <Route path='/user' render={() => <Redirect to="/user/login" />} exact />
            <Route path='/user/login' component={Login} />
          </Switch>
        </Route>
        <Route path="/welcome"component={Welcome}/>
        <Route path="/admin">
          <Route path='/admin' render={() => <Redirect to="/admin/sub-page" />} exact />
          <Route path='/admin/sub-page' component={Admin}/>
        </Route>
        <Route path="/list" component={TableList} />
        <Route path="*" component={NotPage} />
      </Switch>
      </HashRouter>
  );
};

 在App.tsx中使用路由组件

function App() :ReactElement{
  return (
    <div className="App">
      <BrowserRouter>
      <Provider store={store}>
            <Suspense fallback={<div>wwww</div>}>
              <ErrorBoundary>
                <Router />
              </ErrorBoundary>
            </Suspense>
        </Provider>
        </BrowserRouter>
    </div>
  );
}
export default App;

3 管理系统搭建

3.1 路由结构体

export interface AppRouter {
  path: string //路由路径
  name?: string //菜单名称
  component?: //组件
    | React.ComponentType<RouteComponentProps<any>>
    | React.ComponentType<any>
  auth?: boolean //是否认证
  isHidden?: boolean //菜单是否隐藏
  icon?: any //菜单图标
  redirectUrl?: string //菜单是否重定向
  routes?: AppRouter[] //子路由
}

3.2 路由定义

router/index.tsx 

const routers: Array<AppRouter> = [
  {
    path: '/',
    name: '主界面',
    component: Welcome,
    auth: true,
    icon: <CrownFilled />,
  },
  {
    path: '/user',
    name: '用户管理',
    redirectUrl: '/user/login',
    isHidden: true,
    icon: <CrownFilled />,
    routes: [
      {
        path: '/user/login',
        component: Login,
        icon: <CrownFilled />,
      },
    ],
  },
  {
    name: '欢迎界面',
    path: '/welcome',
    component: Welcome,
    icon: <CrownFilled />,
    auth: true,
  },
  {
    name: '管理员',
    path: '/admin',
    redirectUrl: '/admin/sub-page',
    icon: <CrownFilled />,
    routes: [
      {
        name: '管理子页',
        path: '/admin/sub-page',
        icon: <CrownFilled />,
        component: Admin,
      },
    ],
  },
  {
    name: '列表页面',
    path: '/list',
    component: TableList,
    icon: <CrownFilled />,
    auth: true,
  },
  {
    path: '*',
    component: NotPage,
    auth: true,
    isHidden: true,
  },
]

3.3 App布局文件

function App(): ReactElement {
  return (
    <>
      <BrowserRouter>
        <Provider store={store}>
          <Suspense fallback={<PageLoading></PageLoading>}>
            <ErrorBoundary>
              <FrontendRouter routerConfig={WithAppRouters(routers)} />
            </ErrorBoundary>
          </Suspense>
        </Provider>
      </BrowserRouter>
    </>
  )
}
export default App

FontendRouter是处理认证的信息,WithAppRouters是重新构建真正的路由信息列表

FontendRouter主要是导入路由包含在

<MainLayout>
                    <Route
                      path={pathname}
                      component={targetRouterConfig.component}
                      exact
                    />
                  </MainLayout>

3.4 MainLayout布局文件定义

这里直接去ProLayout - 高级布局 - ProComponents (ant.design) 选择需要的布局

const MainLayout: React.FC<{ children: ReactNode }> = (props) => {
  const [settings, setSetting] = useState<Partial<ProSettings> | undefined>({
    fixSiderbar: true,
    layout: 'mix',
    splitMenus: false,
  })

  const [pathname, setPathname] = useState('/')
  const [num, setNum] = useState(40)
  if (typeof document === 'undefined') {
    return <div />
  }
  return (
    <div
      id="test-pro-layout"
      style={{
        height: '100vh',
        overflow: 'auto',
      }}
    >
      <ProConfigProvider hashed={false}>
        <ConfigProvider
          getTargetContainer={() => {
            return document.getElementById('test-pro-layout') || document.body
          }}
        >
          <ProLayout
            prefixCls="my-prefix"
            bgLayoutImgList={[
              {
                src: 'https://img.alicdn.com/imgextra/i2/O1CN01O4etvp1DvpFLKfuWq_!!6000000000279-2-tps-609-606.png',
                left: 85,
                bottom: 100,
                height: '303px',
              },
              {
                src: 'https://img.alicdn.com/imgextra/i2/O1CN01O4etvp1DvpFLKfuWq_!!6000000000279-2-tps-609-606.png',
                bottom: -68,
                right: -45,
                height: '303px',
              },
              {
                src: 'https://img.alicdn.com/imgextra/i3/O1CN018NxReL1shX85Yz6Cx_!!6000000005798-2-tps-884-496.png',
                bottom: 0,
                left: 0,
                width: '331px',
              },
            ]}
            {...defaultProps}
            location={{
              pathname,
            }}
            token={{
              header: {
                colorBgMenuItemSelected: 'rgba(0,0,0,0.04)',
              },
            }}
            avatarProps={{
              src: 'https://gw.alipayobjects.com/zos/antfincdn/efFD%24IOql2/weixintupian_20170331104822.jpg',
              size: 'small',
              title: '七妮妮',
              render: (props, dom) => {
                return (
                  <Dropdown
                    menu={{
                      items: [
                        {
                          key: 'logout',
                          icon: <LogoutOutlined />,
                          label: '退出登录',
                        },
                      ],
                    }}
                  >
                    {dom}
                  </Dropdown>
                )
              },
            }}
            actionsRender={(props) => {
              if (props.isMobile) return []
              if (typeof window === 'undefined') return []
              return [
                <InfoCircleFilled key="InfoCircleFilled" />,
                <QuestionCircleFilled key="QuestionCircleFilled" />,
                <GithubFilled key="GithubFilled" />,
              ]
            }}
            menuFooterRender={(props) => {
              if (props?.collapsed) return undefined
              return (
                <div
                  style={{
                    textAlign: 'center',
                    paddingBlockStart: 12,
                  }}
                >
                  <div>© 2021 Made with love</div>
                  <div>by Ant Design</div>
                </div>
              )
            }}
            onMenuHeaderClick={(e) => console.log(e)}
            menuItemRender={(item, dom) => (
              <div
                onClick={() => {
                  setPathname(item.path || '/welcome')
                }}
              >
                {dom}
              </div>
            )}
            {...settings}
          >
            {props.children}
          </ProLayout>
        </ConfigProvider>
      </ProConfigProvider>
    </div>
  )
}
export default MainLayout

prelayout需要配置:_defaultProps.tsx

import { CrownFilled } from '@ant-design/icons'
import { AppRouter } from '../FrontendAuth'
import { routers } from '@/router'
//将默认的路由配置生成prelayout需要的
export function WithAppRouters(appRouters1: AppRouter[]): AppRouter[] {
  const appRouterFun = (appRouters2: AppRouter[]): AppRouter[] => {
    const newAppRouters: AppRouter[] = []
    for (const appRouter of appRouters2) {
      if (!appRouter.isHidden) {
        newAppRouters.push(appRouter)
        if (appRouter.routes && appRouter.routes.length > 0) {
          appRouter.routes = WithAppRouters(appRouter.routes)
        }
      }
    }
    return newAppRouters
  }
  return appRouterFun(appRouters1)
}
export default {
  route: {
    path: '/',
    routes: WithAppRouters(routers),
  },
  location: {
    pathname: '/',
  },
}

4 显示结果

源码:liu289747235/reactjs-antdesign-admin

上一篇:UDP的报文结构和注意事项


下一篇:Hadoop概述