Merge branch 'main' of https://github.com/vbenjs/vue-vben-admin
This commit is contained in:
commit
e5625efcf7
@ -384,6 +384,10 @@ interface RouteMeta {
|
|||||||
* The menu is visible, but access will be redirected to 403
|
* The menu is visible, but access will be redirected to 403
|
||||||
*/
|
*/
|
||||||
menuVisibleWithForbidden?: boolean;
|
menuVisibleWithForbidden?: boolean;
|
||||||
|
/**
|
||||||
|
* Open in a new window
|
||||||
|
*/
|
||||||
|
openInNewWindow?: boolean;
|
||||||
/**
|
/**
|
||||||
* Used for route->menu sorting
|
* Used for route->menu sorting
|
||||||
*/
|
*/
|
||||||
|
@ -382,6 +382,10 @@ interface RouteMeta {
|
|||||||
* 菜单可以看到,但是访问会被重定向到403
|
* 菜单可以看到,但是访问会被重定向到403
|
||||||
*/
|
*/
|
||||||
menuVisibleWithForbidden?: boolean;
|
menuVisibleWithForbidden?: boolean;
|
||||||
|
/**
|
||||||
|
* 在新窗口打开
|
||||||
|
*/
|
||||||
|
openInNewWindow?: boolean;
|
||||||
/**
|
/**
|
||||||
* 用于路由->菜单排序
|
* 用于路由->菜单排序
|
||||||
*/
|
*/
|
||||||
@ -539,6 +543,13 @@ interface RouteMeta {
|
|||||||
|
|
||||||
用于配置页面在菜单可以看到,但是访问会被重定向到403。
|
用于配置页面在菜单可以看到,但是访问会被重定向到403。
|
||||||
|
|
||||||
|
### openInNewWindow
|
||||||
|
|
||||||
|
- 类型:`boolean`
|
||||||
|
- 默认值:`false`
|
||||||
|
|
||||||
|
设置为 `true` 时,会在新窗口打开页面。
|
||||||
|
|
||||||
### order
|
### order
|
||||||
|
|
||||||
- 类型:`number`
|
- 类型:`number`
|
||||||
|
@ -81,7 +81,7 @@ getCurrentInstance().ctx.xxxx;
|
|||||||
|
|
||||||
## 依赖安装问题
|
## 依赖安装问题
|
||||||
|
|
||||||
- 如果依赖安装不了或者启动报错可以尝试执行`pnpm run resintall`。
|
- 如果依赖安装不了或者启动报错可以尝试执行`pnpm run reinstall`。
|
||||||
- 如果依赖安装不了或者报错,可以尝试切换手机热点来进行依赖安装。
|
- 如果依赖安装不了或者报错,可以尝试切换手机热点来进行依赖安装。
|
||||||
- 如果还是不行,可以自行配置国内镜像安装。
|
- 如果还是不行,可以自行配置国内镜像安装。
|
||||||
- 也可以在项目根目录创建 `.npmrc` 文件,内容如下
|
- 也可以在项目根目录创建 `.npmrc` 文件,内容如下
|
||||||
|
@ -23,4 +23,15 @@ function openWindow(url: string, options: OpenWindowOptions = {}): void {
|
|||||||
window.open(url, target, features);
|
window.open(url, target, features);
|
||||||
}
|
}
|
||||||
|
|
||||||
export { openWindow };
|
/**
|
||||||
|
* 在新窗口中打开路由。
|
||||||
|
* @param path
|
||||||
|
*/
|
||||||
|
function openRouteInNewWindow(path: string) {
|
||||||
|
const { hash, origin } = location;
|
||||||
|
const fullPath = path.startsWith('/') ? path : `/${path}`;
|
||||||
|
const url = `${origin}${hash ? '/#' : ''}${fullPath}`;
|
||||||
|
openWindow(url, { target: '_blank' });
|
||||||
|
}
|
||||||
|
|
||||||
|
export { openRouteInNewWindow, openWindow };
|
||||||
|
@ -98,6 +98,10 @@ interface RouteMeta {
|
|||||||
* 菜单可以看到,但是访问会被重定向到403
|
* 菜单可以看到,但是访问会被重定向到403
|
||||||
*/
|
*/
|
||||||
menuVisibleWithForbidden?: boolean;
|
menuVisibleWithForbidden?: boolean;
|
||||||
|
/**
|
||||||
|
* 在新窗口打开
|
||||||
|
*/
|
||||||
|
openInNewWindow?: boolean;
|
||||||
/**
|
/**
|
||||||
* 用于路由->菜单排序
|
* 用于路由->菜单排序
|
||||||
*/
|
*/
|
||||||
|
@ -6,14 +6,12 @@ import { VbenIcon } from '../icon';
|
|||||||
interface Props extends BreadcrumbProps {}
|
interface Props extends BreadcrumbProps {}
|
||||||
|
|
||||||
defineOptions({ name: 'Breadcrumb' });
|
defineOptions({ name: 'Breadcrumb' });
|
||||||
withDefaults(defineProps<Props>(), {
|
const { breadcrumbs, showIcon } = defineProps<Props>();
|
||||||
showIcon: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
const emit = defineEmits<{ select: [string] }>();
|
const emit = defineEmits<{ select: [string] }>();
|
||||||
|
|
||||||
function handleClick(path?: string) {
|
function handleClick(index: number, path?: string) {
|
||||||
if (!path) {
|
if (!path || index === breadcrumbs.length - 1) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
emit('select', path);
|
emit('select', path);
|
||||||
@ -27,7 +25,10 @@ function handleClick(path?: string) {
|
|||||||
:key="`${item.path}-${item.title}-${index}`"
|
:key="`${item.path}-${item.title}-${index}`"
|
||||||
>
|
>
|
||||||
<li>
|
<li>
|
||||||
<a href="javascript:void 0" @click.stop="handleClick(item.path)">
|
<a
|
||||||
|
href="javascript:void 0"
|
||||||
|
@click.stop="handleClick(index, item.path)"
|
||||||
|
>
|
||||||
<span class="flex-center z-10 h-full">
|
<span class="flex-center z-10 h-full">
|
||||||
<VbenIcon
|
<VbenIcon
|
||||||
v-if="showIcon"
|
v-if="showIcon"
|
||||||
|
@ -1,23 +1,25 @@
|
|||||||
import { useRouter } from 'vue-router';
|
import { type RouteRecordNormalized, useRouter } from 'vue-router';
|
||||||
|
|
||||||
import { isHttpUrl, openWindow } from '@vben/utils';
|
import { isHttpUrl, openRouteInNewWindow, openWindow } from '@vben/utils';
|
||||||
|
|
||||||
function useNavigation() {
|
function useNavigation() {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const routes = router.getRoutes();
|
const routes = router.getRoutes();
|
||||||
|
|
||||||
const routeMetaMap = new Map<string, any>();
|
const routeMetaMap = new Map<string, RouteRecordNormalized>();
|
||||||
|
|
||||||
routes.forEach((route) => {
|
routes.forEach((route) => {
|
||||||
routeMetaMap.set(route.path, route.meta);
|
routeMetaMap.set(route.path, route);
|
||||||
});
|
});
|
||||||
|
|
||||||
const navigation = async (path: string) => {
|
const navigation = async (path: string) => {
|
||||||
|
const route = routeMetaMap.get(path);
|
||||||
|
const { openInNewWindow = false, query = {} } = route?.meta ?? {};
|
||||||
if (isHttpUrl(path)) {
|
if (isHttpUrl(path)) {
|
||||||
openWindow(path, { target: '_blank' });
|
openWindow(path, { target: '_blank' });
|
||||||
|
} else if (openInNewWindow) {
|
||||||
|
openRouteInNewWindow(path);
|
||||||
} else {
|
} else {
|
||||||
const meta = routeMetaMap.get(path);
|
|
||||||
const query = meta?.query ?? {};
|
|
||||||
await router.push({
|
await router.push({
|
||||||
path,
|
path,
|
||||||
query,
|
query,
|
||||||
|
@ -4,7 +4,7 @@ import type { Router, RouteRecordNormalized } from 'vue-router';
|
|||||||
import { toRaw } from 'vue';
|
import { toRaw } from 'vue';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
openWindow,
|
openRouteInNewWindow,
|
||||||
startProgress,
|
startProgress,
|
||||||
stopProgress,
|
stopProgress,
|
||||||
} from '@vben-core/shared/utils';
|
} from '@vben-core/shared/utils';
|
||||||
@ -290,11 +290,7 @@ export const useTabbarStore = defineStore('core-tabbar', {
|
|||||||
* @param tab
|
* @param tab
|
||||||
*/
|
*/
|
||||||
async openTabInNewWindow(tab: TabDefinition) {
|
async openTabInNewWindow(tab: TabDefinition) {
|
||||||
const { hash, origin } = location;
|
openRouteInNewWindow(tab.fullPath || tab.path);
|
||||||
const path = tab.fullPath || tab.path;
|
|
||||||
const fullPath = path.startsWith('/') ? path : `/${path}`;
|
|
||||||
const url = `${origin}${hash ? '/#' : ''}${fullPath}`;
|
|
||||||
openWindow(url, { target: '_blank' });
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -312,6 +308,14 @@ export const useTabbarStore = defineStore('core-tabbar', {
|
|||||||
// this.addTab(tab);
|
// this.addTab(tab);
|
||||||
this.tabs.splice(index, 1, tab);
|
this.tabs.splice(index, 1, tab);
|
||||||
}
|
}
|
||||||
|
// 过滤固定tabs,后面更改affixTabOrder的值的话可能会有问题,目前行464排序affixTabs没有设置值
|
||||||
|
const affixTabs = this.tabs.filter((tab) => isAffixTab(tab));
|
||||||
|
// 获得固定tabs的index
|
||||||
|
const newIndex = affixTabs.findIndex(
|
||||||
|
(item) => getTabPath(item) === getTabPath(tab),
|
||||||
|
);
|
||||||
|
// 交换位置重新排序
|
||||||
|
await this.sortTabs(index, newIndex);
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -419,6 +423,12 @@ export const useTabbarStore = defineStore('core-tabbar', {
|
|||||||
// this.addTab(tab);
|
// this.addTab(tab);
|
||||||
this.tabs.splice(index, 1, tab);
|
this.tabs.splice(index, 1, tab);
|
||||||
}
|
}
|
||||||
|
// 过滤固定tabs,后面更改affixTabOrder的值的话可能会有问题,目前行464排序affixTabs没有设置值
|
||||||
|
const affixTabs = this.tabs.filter((tab) => isAffixTab(tab));
|
||||||
|
// 获得固定tabs的index,使用固定tabs的下一个位置也就是活动tabs的第一个位置
|
||||||
|
const newIndex = affixTabs.length;
|
||||||
|
// 交换位置重新排序
|
||||||
|
await this.sortTabs(index, newIndex);
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -48,7 +48,8 @@
|
|||||||
"tabDetail": "Tab Detail Page",
|
"tabDetail": "Tab Detail Page",
|
||||||
"fullScreen": "FullScreen",
|
"fullScreen": "FullScreen",
|
||||||
"clipboard": "Clipboard",
|
"clipboard": "Clipboard",
|
||||||
"menuWithQuery": "Menu With Query"
|
"menuWithQuery": "Menu With Query",
|
||||||
|
"openInNewWindow": "Open in New Window"
|
||||||
},
|
},
|
||||||
"breadcrumb": {
|
"breadcrumb": {
|
||||||
"navigation": "Breadcrumb Navigation",
|
"navigation": "Breadcrumb Navigation",
|
||||||
|
@ -48,7 +48,8 @@
|
|||||||
"tabDetail": "标签详情页",
|
"tabDetail": "标签详情页",
|
||||||
"fullScreen": "全屏",
|
"fullScreen": "全屏",
|
||||||
"clipboard": "剪贴板",
|
"clipboard": "剪贴板",
|
||||||
"menuWithQuery": "带参菜单"
|
"menuWithQuery": "带参菜单",
|
||||||
|
"openInNewWindow": "新窗口打开"
|
||||||
},
|
},
|
||||||
"breadcrumb": {
|
"breadcrumb": {
|
||||||
"navigation": "面包屑导航",
|
"navigation": "面包屑导航",
|
||||||
|
@ -174,7 +174,7 @@ const routes: RouteRecordRaw[] = [
|
|||||||
import('#/views/demos/features/full-screen/index.vue'),
|
import('#/views/demos/features/full-screen/index.vue'),
|
||||||
meta: {
|
meta: {
|
||||||
icon: 'lucide:fullscreen',
|
icon: 'lucide:fullscreen',
|
||||||
title: $t('demos.features.title'),
|
title: $t('demos.features.fullScreen'),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -200,6 +200,17 @@ const routes: RouteRecordRaw[] = [
|
|||||||
title: $t('demos.features.menuWithQuery'),
|
title: $t('demos.features.menuWithQuery'),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: 'NewWindowDemo',
|
||||||
|
path: '/demos/new-window',
|
||||||
|
component: () =>
|
||||||
|
import('#/views/demos/features/new-window/index.vue'),
|
||||||
|
meta: {
|
||||||
|
icon: 'lucide:app-window',
|
||||||
|
openInNewWindow: true,
|
||||||
|
title: $t('demos.features.openInNewWindow'),
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: 'VueQueryDemo',
|
name: 'VueQueryDemo',
|
||||||
path: '/demos/features/vue-query',
|
path: '/demos/features/vue-query',
|
||||||
|
11
playground/src/views/demos/features/new-window/index.vue
Normal file
11
playground/src/views/demos/features/new-window/index.vue
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
<script lang="ts" setup>
|
||||||
|
import { Fallback } from '@vben/common-ui';
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<Fallback
|
||||||
|
description="当前页面已在新窗口内打开"
|
||||||
|
status="coming-soon"
|
||||||
|
title="新窗口打开页面"
|
||||||
|
/>
|
||||||
|
</template>
|
@ -43,13 +43,13 @@ catalog:
|
|||||||
'@types/html-minifier-terser': ^7.0.2
|
'@types/html-minifier-terser': ^7.0.2
|
||||||
'@types/jsonwebtoken': ^9.0.7
|
'@types/jsonwebtoken': ^9.0.7
|
||||||
'@types/lodash.clonedeep': ^4.5.9
|
'@types/lodash.clonedeep': ^4.5.9
|
||||||
'@types/node': ^22.7.7
|
'@types/node': ^22.7.8
|
||||||
'@types/nprogress': ^0.2.3
|
'@types/nprogress': ^0.2.3
|
||||||
'@types/postcss-import': ^14.0.3
|
'@types/postcss-import': ^14.0.3
|
||||||
'@types/qrcode': ^1.5.5
|
'@types/qrcode': ^1.5.5
|
||||||
'@types/sortablejs': ^1.15.8
|
'@types/sortablejs': ^1.15.8
|
||||||
'@typescript-eslint/eslint-plugin': ^8.10.0
|
'@typescript-eslint/eslint-plugin': ^8.11.0
|
||||||
'@typescript-eslint/parser': ^8.10.0
|
'@typescript-eslint/parser': ^8.11.0
|
||||||
'@vee-validate/zod': ^4.14.3
|
'@vee-validate/zod': ^4.14.3
|
||||||
'@vite-pwa/vitepress': ^0.5.3
|
'@vite-pwa/vitepress': ^0.5.3
|
||||||
'@vitejs/plugin-vue': ^5.1.4
|
'@vitejs/plugin-vue': ^5.1.4
|
||||||
@ -84,7 +84,7 @@ catalog:
|
|||||||
echarts: ^5.5.1
|
echarts: ^5.5.1
|
||||||
element-plus: ^2.8.6
|
element-plus: ^2.8.6
|
||||||
eslint: ^9.13.0
|
eslint: ^9.13.0
|
||||||
eslint-config-turbo: ^2.2.1
|
eslint-config-turbo: ^2.2.3
|
||||||
eslint-plugin-command: ^0.2.6
|
eslint-plugin-command: ^0.2.6
|
||||||
eslint-plugin-eslint-comments: ^3.2.0
|
eslint-plugin-eslint-comments: ^3.2.0
|
||||||
eslint-plugin-import-x: ^4.3.1
|
eslint-plugin-import-x: ^4.3.1
|
||||||
@ -153,7 +153,7 @@ catalog:
|
|||||||
tailwindcss: ^3.4.14
|
tailwindcss: ^3.4.14
|
||||||
tailwindcss-animate: ^1.0.7
|
tailwindcss-animate: ^1.0.7
|
||||||
theme-colors: ^0.1.0
|
theme-colors: ^0.1.0
|
||||||
turbo: ^2.2.1
|
turbo: ^2.2.3
|
||||||
typescript: ^5.6.3
|
typescript: ^5.6.3
|
||||||
unbuild: ^2.0.0
|
unbuild: ^2.0.0
|
||||||
unplugin-element-plus: ^0.8.0
|
unplugin-element-plus: ^0.8.0
|
||||||
|
Loading…
Reference in New Issue
Block a user