Merge branch 'main' of https://github.com/vbenjs/vue-vben-admin into dev
This commit is contained in:
commit
551841bdd7
@ -347,7 +347,7 @@ export interface ActionButtonOptions {
|
|||||||
/** 是否显示 */
|
/** 是否显示 */
|
||||||
show?: boolean;
|
show?: boolean;
|
||||||
/** 按钮文本 */
|
/** 按钮文本 */
|
||||||
text?: string;
|
content?: string;
|
||||||
/** 任意属性 */
|
/** 任意属性 */
|
||||||
[key: string]: any;
|
[key: string]: any;
|
||||||
}
|
}
|
||||||
|
@ -80,6 +80,7 @@ exports[`defaultPreferences immutability test > should not modify the config obj
|
|||||||
"enable": true,
|
"enable": true,
|
||||||
"height": 38,
|
"height": 38,
|
||||||
"keepAlive": true,
|
"keepAlive": true,
|
||||||
|
"maxCount": 0,
|
||||||
"middleClickToClose": false,
|
"middleClickToClose": false,
|
||||||
"persist": true,
|
"persist": true,
|
||||||
"showIcon": true,
|
"showIcon": true,
|
||||||
|
@ -80,6 +80,7 @@ const defaultPreferences: Preferences = {
|
|||||||
enable: true,
|
enable: true,
|
||||||
height: 38,
|
height: 38,
|
||||||
keepAlive: true,
|
keepAlive: true,
|
||||||
|
maxCount: 0,
|
||||||
middleClickToClose: false,
|
middleClickToClose: false,
|
||||||
persist: true,
|
persist: true,
|
||||||
showIcon: true,
|
showIcon: true,
|
||||||
|
@ -168,6 +168,8 @@ interface TabbarPreferences {
|
|||||||
height: number;
|
height: number;
|
||||||
/** 开启标签页缓存功能 */
|
/** 开启标签页缓存功能 */
|
||||||
keepAlive: boolean;
|
keepAlive: boolean;
|
||||||
|
/** 限制最大数量 */
|
||||||
|
maxCount: number;
|
||||||
/** 是否点击中键时关闭标签 */
|
/** 是否点击中键时关闭标签 */
|
||||||
middleClickToClose: boolean;
|
middleClickToClose: boolean;
|
||||||
/** 是否持久化标签 */
|
/** 是否持久化标签 */
|
||||||
|
@ -5,6 +5,7 @@ import { computed } from 'vue';
|
|||||||
|
|
||||||
import { $t } from '@vben/locales';
|
import { $t } from '@vben/locales';
|
||||||
|
|
||||||
|
import NumberFieldItem from '../number-field-item.vue';
|
||||||
import SelectItem from '../select-item.vue';
|
import SelectItem from '../select-item.vue';
|
||||||
import SwitchItem from '../switch-item.vue';
|
import SwitchItem from '../switch-item.vue';
|
||||||
|
|
||||||
@ -22,6 +23,7 @@ const tabbarWheelable = defineModel<boolean>('tabbarWheelable');
|
|||||||
const tabbarStyleType = defineModel<string>('tabbarStyleType');
|
const tabbarStyleType = defineModel<string>('tabbarStyleType');
|
||||||
const tabbarShowMore = defineModel<boolean>('tabbarShowMore');
|
const tabbarShowMore = defineModel<boolean>('tabbarShowMore');
|
||||||
const tabbarShowMaximize = defineModel<boolean>('tabbarShowMaximize');
|
const tabbarShowMaximize = defineModel<boolean>('tabbarShowMaximize');
|
||||||
|
const tabbarMaxCount = defineModel<number>('tabbarMaxCount');
|
||||||
const tabbarMiddleClickToClose = defineModel<boolean>(
|
const tabbarMiddleClickToClose = defineModel<boolean>(
|
||||||
'tabbarMiddleClickToClose',
|
'tabbarMiddleClickToClose',
|
||||||
);
|
);
|
||||||
@ -54,6 +56,16 @@ const styleItems = computed((): SelectOption[] => [
|
|||||||
<SwitchItem v-model="tabbarPersist" :disabled="!tabbarEnable">
|
<SwitchItem v-model="tabbarPersist" :disabled="!tabbarEnable">
|
||||||
{{ $t('preferences.tabbar.persist') }}
|
{{ $t('preferences.tabbar.persist') }}
|
||||||
</SwitchItem>
|
</SwitchItem>
|
||||||
|
<NumberFieldItem
|
||||||
|
v-model="tabbarMaxCount"
|
||||||
|
:disabled="!tabbarEnable"
|
||||||
|
:max="30"
|
||||||
|
:min="0"
|
||||||
|
:step="5"
|
||||||
|
:tip="$t('preferences.tabbar.maxCountTip')"
|
||||||
|
>
|
||||||
|
{{ $t('preferences.tabbar.maxCount') }}
|
||||||
|
</NumberFieldItem>
|
||||||
<SwitchItem v-model="tabbarDraggable" :disabled="!tabbarEnable">
|
<SwitchItem v-model="tabbarDraggable" :disabled="!tabbarEnable">
|
||||||
{{ $t('preferences.tabbar.draggable') }}
|
{{ $t('preferences.tabbar.draggable') }}
|
||||||
</SwitchItem>
|
</SwitchItem>
|
||||||
|
@ -1,7 +1,10 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { SelectOption } from '@vben/types';
|
import type { SelectOption } from '@vben/types';
|
||||||
|
|
||||||
|
import { useSlots } from 'vue';
|
||||||
|
|
||||||
import { CircleHelp } from '@vben/icons';
|
import { CircleHelp } from '@vben/icons';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
NumberField,
|
NumberField,
|
||||||
NumberFieldContent,
|
NumberFieldContent,
|
||||||
@ -10,7 +13,6 @@ import {
|
|||||||
NumberFieldInput,
|
NumberFieldInput,
|
||||||
VbenTooltip,
|
VbenTooltip,
|
||||||
} from '@vben-core/shadcn-ui';
|
} from '@vben-core/shadcn-ui';
|
||||||
import { useSlots } from 'vue';
|
|
||||||
|
|
||||||
defineOptions({
|
defineOptions({
|
||||||
name: 'PreferenceSelectItem',
|
name: 'PreferenceSelectItem',
|
||||||
@ -21,10 +23,12 @@ withDefaults(
|
|||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
items?: SelectOption[];
|
items?: SelectOption[];
|
||||||
placeholder?: string;
|
placeholder?: string;
|
||||||
|
tip?: string;
|
||||||
}>(),
|
}>(),
|
||||||
{
|
{
|
||||||
disabled: false,
|
disabled: false,
|
||||||
placeholder: '',
|
placeholder: '',
|
||||||
|
tip: '',
|
||||||
items: () => [],
|
items: () => [],
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@ -45,11 +49,17 @@ const slots = useSlots();
|
|||||||
<span class="flex items-center text-sm">
|
<span class="flex items-center text-sm">
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
|
|
||||||
<VbenTooltip v-if="slots.tip" side="bottom">
|
<VbenTooltip v-if="slots.tip || tip" side="bottom">
|
||||||
<template #trigger>
|
<template #trigger>
|
||||||
<CircleHelp class="ml-1 size-3 cursor-help" />
|
<CircleHelp class="ml-1 size-3 cursor-help" />
|
||||||
</template>
|
</template>
|
||||||
<slot name="tip"></slot>
|
<slot name="tip">
|
||||||
|
<template v-if="tip">
|
||||||
|
<p v-for="(line, index) in tip.split('\n')" :key="index">
|
||||||
|
{{ line }}
|
||||||
|
</p>
|
||||||
|
</template>
|
||||||
|
</slot>
|
||||||
</VbenTooltip>
|
</VbenTooltip>
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
|
@ -116,6 +116,7 @@ const tabbarPersist = defineModel<boolean>('tabbarPersist');
|
|||||||
const tabbarDraggable = defineModel<boolean>('tabbarDraggable');
|
const tabbarDraggable = defineModel<boolean>('tabbarDraggable');
|
||||||
const tabbarWheelable = defineModel<boolean>('tabbarWheelable');
|
const tabbarWheelable = defineModel<boolean>('tabbarWheelable');
|
||||||
const tabbarStyleType = defineModel<string>('tabbarStyleType');
|
const tabbarStyleType = defineModel<string>('tabbarStyleType');
|
||||||
|
const tabbarMaxCount = defineModel<number>('tabbarMaxCount');
|
||||||
const tabbarMiddleClickToClose = defineModel<boolean>(
|
const tabbarMiddleClickToClose = defineModel<boolean>(
|
||||||
'tabbarMiddleClickToClose',
|
'tabbarMiddleClickToClose',
|
||||||
);
|
);
|
||||||
@ -365,6 +366,7 @@ async function handleReset() {
|
|||||||
v-model:tabbar-show-more="tabbarShowMore"
|
v-model:tabbar-show-more="tabbarShowMore"
|
||||||
v-model:tabbar-style-type="tabbarStyleType"
|
v-model:tabbar-style-type="tabbarStyleType"
|
||||||
v-model:tabbar-wheelable="tabbarWheelable"
|
v-model:tabbar-wheelable="tabbarWheelable"
|
||||||
|
v-model:tabbar-max-count="tabbarMaxCount"
|
||||||
v-model:tabbar-middle-click-to-close="tabbarMiddleClickToClose"
|
v-model:tabbar-middle-click-to-close="tabbarMiddleClickToClose"
|
||||||
/>
|
/>
|
||||||
</Block>
|
</Block>
|
||||||
|
@ -62,6 +62,8 @@
|
|||||||
"showMore": "Show More Button",
|
"showMore": "Show More Button",
|
||||||
"showMaximize": "Show Maximize Button",
|
"showMaximize": "Show Maximize Button",
|
||||||
"persist": "Persist Tabs",
|
"persist": "Persist Tabs",
|
||||||
|
"maxCount": "Max Count of Tabs",
|
||||||
|
"maxCountTip": "When the number of tabs exceeds the maximum,\nthe oldest tab will be closed.\n Set to 0 to disable count checking.",
|
||||||
"draggable": "Enable Draggable Sort",
|
"draggable": "Enable Draggable Sort",
|
||||||
"wheelable": "Support Mouse Wheel",
|
"wheelable": "Support Mouse Wheel",
|
||||||
"middleClickClose": "Close Tab when Mouse Middle Button Click",
|
"middleClickClose": "Close Tab when Mouse Middle Button Click",
|
||||||
|
@ -62,6 +62,8 @@
|
|||||||
"showMore": "显示更多按钮",
|
"showMore": "显示更多按钮",
|
||||||
"showMaximize": "显示最大化按钮",
|
"showMaximize": "显示最大化按钮",
|
||||||
"persist": "持久化标签页",
|
"persist": "持久化标签页",
|
||||||
|
"maxCount": "最大标签数",
|
||||||
|
"maxCountTip": "每次打开新的标签时如果超过最大标签数,\n会自动关闭一个最先打开的标签\n设置为 0 则不限制",
|
||||||
"draggable": "启动拖拽排序",
|
"draggable": "启动拖拽排序",
|
||||||
"wheelable": "启用纵向滚轮响应",
|
"wheelable": "启用纵向滚轮响应",
|
||||||
"middleClickClose": "点击鼠标中键关闭标签页",
|
"middleClickClose": "点击鼠标中键关闭标签页",
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@vben-core/preferences": "workspace:*",
|
||||||
"@vben-core/shared": "workspace:*",
|
"@vben-core/shared": "workspace:*",
|
||||||
"@vben-core/typings": "workspace:*",
|
"@vben-core/typings": "workspace:*",
|
||||||
"pinia": "catalog:",
|
"pinia": "catalog:",
|
||||||
|
@ -1,13 +1,17 @@
|
|||||||
import type { TabDefinition } from '@vben-core/typings';
|
|
||||||
import type { Router, RouteRecordNormalized } from 'vue-router';
|
import type { Router, RouteRecordNormalized } from 'vue-router';
|
||||||
|
|
||||||
|
import type { TabDefinition } from '@vben-core/typings';
|
||||||
|
|
||||||
|
import { toRaw } from 'vue';
|
||||||
|
|
||||||
|
import { preferences } from '@vben-core/preferences';
|
||||||
import {
|
import {
|
||||||
openRouteInNewWindow,
|
openRouteInNewWindow,
|
||||||
startProgress,
|
startProgress,
|
||||||
stopProgress,
|
stopProgress,
|
||||||
} from '@vben-core/shared/utils';
|
} from '@vben-core/shared/utils';
|
||||||
|
|
||||||
import { acceptHMRUpdate, defineStore } from 'pinia';
|
import { acceptHMRUpdate, defineStore } from 'pinia';
|
||||||
import { toRaw } from 'vue';
|
|
||||||
|
|
||||||
interface TabbarState {
|
interface TabbarState {
|
||||||
/**
|
/**
|
||||||
@ -104,6 +108,7 @@ export const useTabbarStore = defineStore('core-tabbar', {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (tabIndex === -1) {
|
if (tabIndex === -1) {
|
||||||
|
const maxCount = preferences.tabbar.maxCount;
|
||||||
// 获取动态路由打开数,超过 0 即代表需要控制打开数
|
// 获取动态路由打开数,超过 0 即代表需要控制打开数
|
||||||
const maxNumOfOpenTab = (routeTab?.meta?.maxNumOfOpenTab ??
|
const maxNumOfOpenTab = (routeTab?.meta?.maxNumOfOpenTab ??
|
||||||
-1) as number;
|
-1) as number;
|
||||||
@ -119,8 +124,14 @@ export const useTabbarStore = defineStore('core-tabbar', {
|
|||||||
(item) => item.name === routeTab.name,
|
(item) => item.name === routeTab.name,
|
||||||
);
|
);
|
||||||
index !== -1 && this.tabs.splice(index, 1);
|
index !== -1 && this.tabs.splice(index, 1);
|
||||||
|
} else if (maxCount > 0 && this.tabs.length >= maxCount) {
|
||||||
|
// 关闭第一个
|
||||||
|
const index = this.tabs.findIndex(
|
||||||
|
(item) =>
|
||||||
|
!Reflect.has(item.meta, 'affixTab') || !item.meta.affixTab,
|
||||||
|
);
|
||||||
|
index !== -1 && this.tabs.splice(index, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.tabs.push(tab);
|
this.tabs.push(tab);
|
||||||
} else {
|
} else {
|
||||||
// 页面已经存在,不重复添加选项卡,只更新选项卡参数
|
// 页面已经存在,不重复添加选项卡,只更新选项卡参数
|
||||||
|
Loading…
Reference in New Issue
Block a user