登录与品类

This commit is contained in:
孙景学
2025-08-04 16:06:23 +08:00
parent ad4efd8e46
commit b5cb08deb5
29 changed files with 665 additions and 270 deletions

View File

@ -1,15 +1,15 @@
// src/layouts/BasicLayout.tsx
import React, { useEffect, useState } from 'react';
import React, { useState, useEffect } from 'react';
import ProLayout, { PageContainer } from '@ant-design/pro-layout';
import { Link, useLocation, useIntl, useHistory } from 'umi';
import { Link, useLocation, useIntl } from 'umi';
import { connect } from 'dva';
import defaultSettings from '../../config/defaultSettings';
import routes from '../../config/router.config'; // 引入你的自定义路由结构
import routes from '../../config/router.config';
import { ConfigProvider, Breadcrumb } from 'antd';
import HeaderComponent from './Header';
import IconFont from '@/components/IconFont/IconFont';
import type { BreadcrumbState } from '@/models/breadcrumb';
import { SupplierDetailModalProvider } from '@/components/SupplierDetailModalContext/SupplierDetailModalContext';
import type { TabModelState } from '@/models/tab';
const MenuRender = (item: any, isSubMenu: boolean) => {
const intl = useIntl();
@ -19,14 +19,14 @@ const MenuRender = (item: any, isSubMenu: boolean) => {
<span className="ant-pro-menu-item">
<IconFont type={item.icon as string} />
<span className="ant-pro-menu-item-title">
{intl.formatMessage({ id: `menu.${item.name}` || '' })}
{intl.formatMessage({ id: `${item.name}` || '' })}
</span>
</span>
) : (
<Link className="ant-pro-menu-item" key={item.path} to={item.path || '/'} innerRef={null}>
<IconFont type={item.icon as string} />
<span className="ant-pro-menu-item-title">
{intl.formatMessage({ id: `menu.${item.name}` || '' })}
{intl.formatMessage({ id: `${item.name}` || '' })}
</span>
</Link>
)}
@ -34,28 +34,6 @@ const MenuRender = (item: any, isSubMenu: boolean) => {
);
};
// 递归交集过滤函数
function filterMenuByRouter(routes: any, menuRoutes: any) {
return routes.reduce((result: any, route: any) => {
// 只看有 name 的节点
const menu = menuRoutes.find((m) => m.name === route.name);
if (menu) {
// 匹配到后,递归处理 children
let children = [];
if (route.children && menu.children) {
children = filterMenuByRouter(route.children, menu.children);
}
// 构建新节点,保留原 router.config.ts 路径等信息(比如 path, icon, ...其它字段)
result.push({
...route,
// ...menu, // 可按需决定是否 menu 字段覆盖 route 字段(比如 path
// children: children.length > 0 ? children : undefined
});
}
return result;
}, []);
}
const BreadcrumbRender = (
routeBreadcrumb: any,
intl: any,
@ -89,64 +67,123 @@ const BreadcrumbRender = (
interface BasicLayoutProps {
children: React.ReactNode;
breadcrumb: BreadcrumbState;
tab: TabModelState;
dispatch: any;
}
function convertMenuData(menus: any[]): any[] {
return menus.map(item => {
// 保留 icon 字段,如果没有就给默认
const icon = item.icon || undefined;
// 递归 children->routes
let routes;
if (item.children && item.children.length > 0) {
routes = convertMenuData(item.children);
}
// 国际化优先找 menu.name否则直接显示 name
return {
...item,
icon,
routes, // prolayout 只认 routes
name: item.name, // 不要转 menu.xxxMenuRender 时才转
};
});
}
const BasicLayout: React.FC<BasicLayoutProps> = (props) => {
const { children, breadcrumb } = props;
const { children, tab, dispatch } = props;
const location = useLocation();
const intl = useIntl();
const history = useHistory();
const handleTabChange = (key: string) => {
dispatch({
type: 'tab/switchTab',
payload: { key },
});
};
const handleTabEdit = (targetKey: any, action: string) => {
if (action === 'remove') {
dispatch({
type: 'tab/closeTab',
payload: { key: targetKey },
});
}
};
const [menuRoutes, setMenuRoutes] = useState<any[]>([]);
useEffect(() => {
const menuStr = sessionStorage.getItem('menuList');
if (menuStr) {
const menusFromApi = JSON.parse(menuStr);
// routes是本地静态路由menusFromApi是接口菜单
const finalMenus = filterMenuByRouter(routes, menusFromApi);
console.log(finalMenus);
setMenuRoutes(finalMenus);
const menus = JSON.parse(menuStr);
setMenuRoutes(convertMenuData(menus));
}
}, []);
if (menuRoutes.length === 0) return null;
return (
<ConfigProvider>
<SupplierDetailModalProvider>
<ProLayout
{...defaultSettings}
route={{ routes }}
// route={{ routes: menuRoutes }}
subMenuItemRender={(menuItemProps, defaultDom) => {
return MenuRender(menuItemProps, true);
<ProLayout
{...defaultSettings}
route={{ path: '/', routes: menuRoutes }}
breadcrumbRender={() => undefined}
subMenuItemRender={(menuItemProps, defaultDom) => {
return MenuRender(menuItemProps, true);
}}
menuItemRender={(item, dom) => {
return MenuRender(item, false);
}}
location={location}
fixSiderbar
layout="mix"
headerRender={() => {
return <HeaderComponent />;
}}
>
<PageContainer
ghost={true}
header={{
title: false,
breadcrumbRender: () => null,
// breadcrumbRender: ({ breadcrumb: routeBreadcrumb }) =>
// BreadcrumbRender(routeBreadcrumb, intl, history, breadcrumb.breadcrumbName),
}}
menuItemRender={(item, dom) => {
return MenuRender(item, false);
}}
location={location}
fixSiderbar
layout="mix"
headerRender={() => {
return <HeaderComponent />;
// 将tab.tabList转换为需要的格式添加国际化处理
tabList={tab.tabList.map((item) => ({
...item,
tab:
typeof item.tab === 'string'
? intl.formatMessage({ id: `menu.${item.tab}` })
: item.tab,
}))}
tabProps={{
type: 'editable-card',
hideAdd: true,
activeKey: tab.activeKey,
onChange: handleTabChange,
onEdit: handleTabEdit,
size: 'small',
tabBarGutter: 6,
renderTabBar: (propsTab, DefaultTabBar) => (
<DefaultTabBar {...propsTab} className="custom-tab-bar" />
),
}}
>
<PageContainer
ghost={true}
header={{
title: false,
breadcrumbRender: ({ breadcrumb: routeBreadcrumb }) =>
BreadcrumbRender(routeBreadcrumb, intl, history, breadcrumb.breadcrumbName),
}}
>
{children}
</PageContainer>
</ProLayout>
</SupplierDetailModalProvider>
{children}
</PageContainer>
</ProLayout>
</ConfigProvider>
);
};
export default connect(({ breadcrumb }: { breadcrumb: BreadcrumbState }) => ({
breadcrumb,
}))(BasicLayout);
export default connect(
({ breadcrumb, tab }: { breadcrumb: BreadcrumbState; tab: TabModelState }) => ({
breadcrumb,
tab,
}),
)(BasicLayout);