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

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

@ -1,5 +1,28 @@
import dayjs from 'dayjs'; 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 { export function formatInstanceType(value: string): string {
switch (value) { switch (value) {
@ -35,8 +58,6 @@ export function formatInstanceStatus(value: string): string {
export function formatTimestamp(timestamp: number): string { export function formatTimestamp(timestamp: number): string {
// 判断时间戳是秒级还是毫秒级 // 判断时间戳是秒级还是毫秒级
const isMillisecond = timestamp.toString().length >= 13; const isMillisecond = timestamp.toString().length >= 13;
const millisecondTimestamp = isMillisecond ? timestamp : timestamp * 1000; const millisecondTimestamp = isMillisecond ? timestamp : timestamp * 1000;
return dayjs(millisecondTimestamp).format('YYYY-MM-DD HH:mm:ss'); return dayjs(millisecondTimestamp).format('YYYY-MM-DD HH:mm:ss');
} }
Loading…
Cancel
Save