feat(menu): 新增菜单项在新窗口打开的功能

- 在 IRoute 类型中添加 openWindow属性,用于控制菜单项是否在新窗口打开
- 实现 openWindow 函数,用于在新窗口中打开指定 URL
- 修改 layout 组件,支持在新窗口中打开菜单项
- 优化组件开发模块的路由配置,使其支持在新窗口中打开
master
钟良源 6 months ago
parent 903bf5778a
commit 774a9b29fb

@ -25,6 +25,7 @@ import { GlobalState } from '@/store';
import getUrlParams from '@/utils/getUrlParams';
import styles from '@/style/layout.module.less';
import NoAccess from '@/pages/exception/403';
import { openWindow, OpenWindowOptions } from '@/utils/common';
const MenuItem = Menu.Item;
const SubMenu = Menu.SubMenu;
@ -91,8 +92,17 @@ function PageLayout({ children }: { children: ReactNode }) {
const [breadcrumb, setBreadCrumb] = useState([]);
function onClickMenuItem(key) {
setSelectedKeys([key]);
function onClickMenuItem(key: string) {
if (key === 'componentDevelopment') {
const url = `/ideContainer`;
const params: OpenWindowOptions = {
target: '_blank',
menu: false,
identity: key
};
openWindow(url, params);
}
else setSelectedKeys([key]);
}
function toggleCollapse() {
@ -138,6 +148,7 @@ function PageLayout({ children }: { children: ReactNode }) {
function renderRoutes(locale) {
return function travel(_routes: IRoute[], level, parentNode = []) {
return _routes.map((route) => {
console.log('route:', route);
const { ignore } = route;
const iconDom = getIconFromKey(route.key);
const titleDom = (
@ -164,13 +175,23 @@ function PageLayout({ children }: { children: ReactNode }) {
}
menuMap.current.set(route.key, { menuItem: true });
return (
<MenuItem key={route.key}>
<Link href={`/${route.key}`} passHref>
if (route?.openWindow) {
return (
<MenuItem key={route.key}>
<a suppressHydrationWarning>{titleDom}</a>
</Link>
</MenuItem>
);
</MenuItem>
);
}
else {
return (
<MenuItem key={route.key}>
<Link href={`/${route.key}`} passHref>
<a suppressHydrationWarning>{titleDom}</a>
</Link>
</MenuItem>
);
}
});
};
}

@ -2,5 +2,6 @@ import { IRoute } from '@/routes/types';
export const componentDevelopmentModule: IRoute = {
name: 'menu.componentDevelopment',
key: 'componentDevelopment'
key: 'componentDevelopment',
openWindow: true
};

@ -8,4 +8,6 @@ export type IRoute = AuthParams & {
children?: IRoute[];
// 当前路由是否渲染菜单项,为 true 的话不会在菜单中显示,但可通过路由地址访问。
ignore?: boolean;
// 当前路由是在新窗口打开,为 true 的话点击菜单后不会渲染出页面
openWindow?: boolean;
};

@ -1,5 +1,28 @@
import dayjs from 'dayjs';
export type TargetContext = '_self' | '_parent' | '_blank' | '_top';
export interface OpenWindowOptions {
target?: TargetContext;
[key: string]: any;
}
// 新窗口打开处理函数
export function openWindow(url: string, opts?: OpenWindowOptions) {
const { target = '_blank', ...others } = opts || {};
const queryString = Object.entries(others)
.filter(([key, value]) => value !== undefined && value !== null)
.map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`)
.join('&');
// 构造带查询参数的完整 URL
const fullUrl = queryString ? `${url}${url.includes('?') ? '&' : '?'}${queryString}` : url;
window.open(fullUrl, target);
}
// 格式化实例类型
export function formatInstanceType(value: string): string {
switch (value) {
@ -35,8 +58,6 @@ export function formatInstanceStatus(value: string): string {
export function formatTimestamp(timestamp: number): string {
// 判断时间戳是秒级还是毫秒级
const isMillisecond = timestamp.toString().length >= 13;
const millisecondTimestamp = isMillisecond ? timestamp : timestamp * 1000;
return dayjs(millisecondTimestamp).format('YYYY-MM-DD HH:mm:ss');
}
Loading…
Cancel
Save