mirror of
https://github.com/vbenjs/vue-vben-admin.git
synced 2025-08-27 16:15:19 +08:00
feat: add tab drag and drop sort
This commit is contained in:
@@ -4,6 +4,7 @@
|
||||
display: flex;
|
||||
height: @header-height;
|
||||
padding: 0 20px 0 0;
|
||||
margin-left: -1px;
|
||||
line-height: @header-height;
|
||||
color: @white;
|
||||
background: @white;
|
||||
|
@@ -9,4 +9,8 @@
|
||||
> .ant-layout {
|
||||
min-height: 100%;
|
||||
}
|
||||
|
||||
&__main {
|
||||
margin-left: 2px;
|
||||
}
|
||||
}
|
||||
|
@@ -81,7 +81,7 @@ export default defineComponent({
|
||||
{() => (
|
||||
<>
|
||||
{unref(showSideBarRef) && <LayoutSideBar />}
|
||||
<Layout>
|
||||
<Layout class="default-layout__main">
|
||||
{() => (
|
||||
<>
|
||||
<LayoutMultipleHeader />
|
||||
|
@@ -1,16 +1,46 @@
|
||||
import { defineComponent, unref, computed } from 'vue';
|
||||
|
||||
import type { PropType } from 'vue';
|
||||
|
||||
import { defineComponent, unref, computed, FunctionalComponent } from 'vue';
|
||||
|
||||
import { TabItem, tabStore } from '/@/store/modules/tab';
|
||||
import { getScaleAction, TabContentProps } from './tab.data';
|
||||
import { getScaleAction, TabContentProps } from './data';
|
||||
|
||||
import { Dropdown } from '/@/components/Dropdown/index';
|
||||
import { RightOutlined } from '@ant-design/icons-vue';
|
||||
import { appStore } from '/@/store/modules/app';
|
||||
|
||||
import { TabContentEnum } from './tab.data';
|
||||
import { TabContentEnum } from './data';
|
||||
import { useTabDropdown } from './useTabDropdown';
|
||||
import { useMenuSetting } from '/@/hooks/setting/useMenuSetting';
|
||||
import { useHeaderSetting } from '/@/hooks/setting/useHeaderSetting';
|
||||
import { useMultipleTabSetting } from '/@/hooks/setting/useMultipleTabSetting';
|
||||
|
||||
const ExtraContent: FunctionalComponent = () => {
|
||||
return (
|
||||
<span class={`multiple-tabs-content__extra `}>
|
||||
<RightOutlined />
|
||||
</span>
|
||||
);
|
||||
};
|
||||
|
||||
const TabContent: FunctionalComponent<{ tabItem: TabItem }> = (props) => {
|
||||
const { tabItem: { meta } = {} } = props;
|
||||
|
||||
function handleContextMenu(e: Event) {
|
||||
if (!props.tabItem) return;
|
||||
const tableItem = props.tabItem;
|
||||
e?.preventDefault();
|
||||
const index = unref(tabStore.getTabsState).findIndex((tab) => tab.path === tableItem.path);
|
||||
|
||||
tabStore.commitCurrentContextMenuIndexState(index);
|
||||
tabStore.commitCurrentContextMenuState(props.tabItem);
|
||||
}
|
||||
|
||||
return (
|
||||
<div class={`multiple-tabs-content__content `} onContextmenu={handleContextMenu}>
|
||||
<span class="ml-1">{meta && meta.title}</span>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default defineComponent({
|
||||
name: 'TabContent',
|
||||
@@ -19,82 +49,39 @@ export default defineComponent({
|
||||
type: Object as PropType<TabItem>,
|
||||
default: null,
|
||||
},
|
||||
|
||||
type: {
|
||||
type: Number as PropType<number>,
|
||||
type: Number as PropType<TabContentEnum>,
|
||||
default: TabContentEnum.TAB_TYPE,
|
||||
},
|
||||
trigger: {
|
||||
type: Array as PropType<string[]>,
|
||||
default: () => {
|
||||
return ['contextmenu'];
|
||||
},
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
const getProjectConfigRef = computed(() => {
|
||||
return appStore.getProjectConfig;
|
||||
const { getShowMenu } = useMenuSetting();
|
||||
const { getShowHeader } = useHeaderSetting();
|
||||
const { getShowQuick } = useMultipleTabSetting();
|
||||
|
||||
const getIsScale = computed(() => {
|
||||
return !unref(getShowMenu) && !unref(getShowHeader);
|
||||
});
|
||||
|
||||
const getIsScaleRef = computed(() => {
|
||||
const {
|
||||
menuSetting: { show: showMenu },
|
||||
headerSetting: { show: showHeader },
|
||||
} = unref(getProjectConfigRef);
|
||||
return !showMenu && !showHeader;
|
||||
const getIsTab = computed(() => {
|
||||
return !unref(getShowQuick) ? true : props.type === TabContentEnum.TAB_TYPE;
|
||||
});
|
||||
|
||||
function handleContextMenu(e: Event) {
|
||||
if (!props.tabItem) return;
|
||||
const tableItem = props.tabItem;
|
||||
e.preventDefault();
|
||||
const index = unref(tabStore.getTabsState).findIndex((tab) => tab.path === tableItem.path);
|
||||
|
||||
tabStore.commitCurrentContextMenuIndexState(index);
|
||||
tabStore.commitCurrentContextMenuState(props.tabItem);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description: 渲染图标
|
||||
*/
|
||||
|
||||
function renderTabContent() {
|
||||
const { tabItem: { meta } = {} } = props;
|
||||
return (
|
||||
<div class={`multiple-tabs-content__content `} onContextmenu={handleContextMenu}>
|
||||
<span class="ml-1">{meta && meta.title}</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
function renderExtraContent() {
|
||||
return (
|
||||
<span class={`multiple-tabs-content__extra `}>
|
||||
<RightOutlined />
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
const { getDropMenuList, handleMenuEvent } = useTabDropdown(props as TabContentProps);
|
||||
|
||||
return () => {
|
||||
const { trigger, type } = props;
|
||||
const {
|
||||
multiTabsSetting: { showQuick },
|
||||
} = unref(getProjectConfigRef);
|
||||
|
||||
const isTab = !showQuick ? true : type === TabContentEnum.TAB_TYPE;
|
||||
const scaleAction = getScaleAction(
|
||||
unref(getIsScaleRef) ? '缩小' : '放大',
|
||||
unref(getIsScaleRef)
|
||||
);
|
||||
const scaleAction = getScaleAction(unref(getIsScale) ? '收起' : '展开', unref(getIsScale));
|
||||
const dropMenuList = unref(getDropMenuList) || [];
|
||||
|
||||
const isTab = unref(getIsTab);
|
||||
return (
|
||||
<Dropdown
|
||||
dropMenuList={!isTab ? [scaleAction, ...dropMenuList] : dropMenuList}
|
||||
trigger={isTab ? trigger : ['hover']}
|
||||
trigger={isTab ? ['contextmenu'] : ['click']}
|
||||
onMenuEvent={handleMenuEvent}
|
||||
>
|
||||
{() => (isTab ? renderTabContent() : renderExtraContent())}
|
||||
{() => (isTab ? <TabContent tabItem={props.tabItem} /> : <ExtraContent />)}
|
||||
</Dropdown>
|
||||
);
|
||||
};
|
||||
|
@@ -6,11 +6,13 @@ export enum TabContentEnum {
|
||||
TAB_TYPE,
|
||||
EXTRA_TYPE,
|
||||
}
|
||||
|
||||
export interface TabContentProps {
|
||||
tabItem: TabItem | AppRouteRecordRaw;
|
||||
type?: TabContentEnum;
|
||||
trigger?: Array<'click' | 'hover' | 'contextmenu'>;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description: 右键:下拉菜单文字
|
||||
*/
|
@@ -2,11 +2,12 @@
|
||||
|
||||
.multiple-tabs {
|
||||
z-index: 10;
|
||||
height: @multiple-height+2;
|
||||
height: @multiple-height + 2;
|
||||
padding: 0 0 2px 0;
|
||||
line-height: @multiple-height+2;
|
||||
margin-left: -1px;
|
||||
line-height: @multiple-height + 2;
|
||||
background: @white;
|
||||
box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.08);
|
||||
box-shadow: 0 1px 2px 0 rgba(29, 35, 41, 0.05);
|
||||
|
||||
.ant-tabs-small {
|
||||
height: @multiple-height;
|
||||
@@ -32,19 +33,25 @@
|
||||
color: @text-color-call-out;
|
||||
background: @white;
|
||||
border: 1px solid darken(@border-color-light, 8%);
|
||||
border-radius: none !important;
|
||||
transition: none;
|
||||
|
||||
&:hover {
|
||||
.ant-tabs-close-x {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.ant-tabs-close-x {
|
||||
width: 12px;
|
||||
width: 8px;
|
||||
height: 12px;
|
||||
font-size: 12px;
|
||||
color: inherit;
|
||||
opacity: 0;
|
||||
transition: none;
|
||||
|
||||
&:hover {
|
||||
svg {
|
||||
width: 0.8em;
|
||||
width: 0.75em;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -61,12 +68,26 @@
|
||||
}
|
||||
|
||||
.ant-tabs-tab-active {
|
||||
position: relative;
|
||||
padding-left: 26px;
|
||||
color: @white;
|
||||
background: fade(@primary-color, 100%);
|
||||
border: 0;
|
||||
|
||||
&::before {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: calc(50% - 3px);
|
||||
left: 8px;
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
background: #fff;
|
||||
border-radius: 50%;
|
||||
content: '';
|
||||
transition: none;
|
||||
}
|
||||
|
||||
.ant-tabs-close-x {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
svg {
|
||||
@@ -78,6 +99,10 @@
|
||||
|
||||
.ant-tabs-nav > div:nth-child(1) {
|
||||
padding: 0 10px;
|
||||
|
||||
.ant-tabs-tab {
|
||||
margin-right: 3px !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -111,7 +136,10 @@
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
border-left: 1px solid #eee;
|
||||
// box-shadow: 0 1px 4px rgba(0, 21, 41, 0.08);
|
||||
|
||||
&:hover {
|
||||
color: @text-color-base;
|
||||
}
|
||||
|
||||
span[role='img'] {
|
||||
transform: rotate(90deg);
|
||||
|
@@ -1,10 +1,12 @@
|
||||
import './index.less';
|
||||
|
||||
import type { TabContentProps } from './tab.data';
|
||||
import type { TabContentProps } from './data';
|
||||
import type { TabItem } from '/@/store/modules/tab';
|
||||
import type { AppRouteRecordRaw } from '/@/router/types';
|
||||
|
||||
import { defineComponent, watch, computed, unref } from 'vue';
|
||||
import { defineComponent, watch, computed, unref, ref, onMounted, nextTick } from 'vue';
|
||||
import Sortable from 'sortablejs';
|
||||
|
||||
import { useRouter } from 'vue-router';
|
||||
|
||||
import { Tabs } from 'ant-design-vue';
|
||||
@@ -12,24 +14,28 @@ import TabContent from './TabContent';
|
||||
|
||||
import { useGo } from '/@/hooks/web/usePage';
|
||||
|
||||
import { TabContentEnum } from './tab.data';
|
||||
import { TabContentEnum } from './data';
|
||||
|
||||
import { tabStore } from '/@/store/modules/tab';
|
||||
import { userStore } from '/@/store/modules/user';
|
||||
|
||||
import { closeTab } from './useTabDropdown';
|
||||
import { useTabs } from '/@/hooks/web/useTabs';
|
||||
import { initAffixTabs } from './useAffixTabs';
|
||||
import { initAffixTabs } from './useMultipleTabs';
|
||||
import { isNullAndUnDef } from '/@/utils/is';
|
||||
import { useProjectSetting } from '/@/hooks/setting';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'MultipleTabs',
|
||||
setup() {
|
||||
initAffixTabs();
|
||||
const activeKeyRef = ref('');
|
||||
|
||||
const affixTextList = initAffixTabs();
|
||||
|
||||
const go = useGo();
|
||||
|
||||
const { multiTabsSetting } = useProjectSetting();
|
||||
|
||||
const { currentRoute } = useRouter();
|
||||
const { activeKeyRef } = useTabs();
|
||||
|
||||
const getTabsState = computed(() => tabStore.getTabsState);
|
||||
|
||||
@@ -41,24 +47,24 @@ export default defineComponent({
|
||||
|
||||
if (!lastChangeRoute || !userStore.getTokenState) return;
|
||||
|
||||
const { path, fullPath } = lastChangeRoute;
|
||||
if (activeKeyRef.value !== (fullPath || path)) {
|
||||
activeKeyRef.value = fullPath || path;
|
||||
const { path, fullPath } = lastChangeRoute as AppRouteRecordRaw;
|
||||
const p = fullPath || path;
|
||||
if (activeKeyRef.value !== p) {
|
||||
activeKeyRef.value = p;
|
||||
}
|
||||
tabStore.commitAddTab((lastChangeRoute as unknown) as AppRouteRecordRaw);
|
||||
tabStore.commitAddTab(lastChangeRoute);
|
||||
},
|
||||
{
|
||||
immediate: true,
|
||||
}
|
||||
);
|
||||
|
||||
// tab切换
|
||||
function handleChange(activeKey: any) {
|
||||
activeKeyRef.value = activeKey;
|
||||
go(activeKey, false);
|
||||
}
|
||||
|
||||
// 关闭当前tab
|
||||
// Close the current tab
|
||||
function handleEdit(targetKey: string) {
|
||||
// Added operation to hide, currently only use delete operation
|
||||
const index = unref(getTabsState).findIndex(
|
||||
@@ -71,30 +77,65 @@ export default defineComponent({
|
||||
const tabContentProps: TabContentProps = {
|
||||
tabItem: (currentRoute as unknown) as AppRouteRecordRaw,
|
||||
type: TabContentEnum.EXTRA_TYPE,
|
||||
trigger: ['click', 'contextmenu'],
|
||||
};
|
||||
return (
|
||||
<span>
|
||||
<TabContent {...(tabContentProps as any)} />
|
||||
</span>
|
||||
);
|
||||
return <TabContent {...(tabContentProps as any)} />;
|
||||
}
|
||||
|
||||
function renderTabs() {
|
||||
return unref(getTabsState).map((item: TabItem) => {
|
||||
const key = item.query ? item.fullPath : item.path;
|
||||
const closable = !(item && item.meta && item.meta.affix);
|
||||
|
||||
const slots = {
|
||||
tab: () => <TabContent tabItem={item} />,
|
||||
};
|
||||
return (
|
||||
<Tabs.TabPane key={key} closable={closable}>
|
||||
{{
|
||||
tab: () => <TabContent tabItem={item} />,
|
||||
}}
|
||||
{slots}
|
||||
</Tabs.TabPane>
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
function initSortableTabs() {
|
||||
if (!multiTabsSetting.canDrag) return;
|
||||
nextTick(() => {
|
||||
const el = document.querySelectorAll(
|
||||
'.multiple-tabs .ant-tabs-nav > div'
|
||||
)?.[0] as HTMLElement;
|
||||
|
||||
if (!el) return;
|
||||
Sortable.create(el, {
|
||||
animation: 500,
|
||||
delay: 400,
|
||||
delayOnTouchOnly: true,
|
||||
filter: (e: ChangeEvent) => {
|
||||
const text = e?.target?.innerText;
|
||||
if (!text) return false;
|
||||
return affixTextList.includes(text);
|
||||
},
|
||||
onEnd: (evt) => {
|
||||
const { oldIndex, newIndex } = evt;
|
||||
|
||||
if (isNullAndUnDef(oldIndex) || isNullAndUnDef(newIndex) || oldIndex === newIndex) {
|
||||
return;
|
||||
}
|
||||
|
||||
tabStore.commitSortTabs({ oldIndex, newIndex });
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
initSortableTabs();
|
||||
});
|
||||
|
||||
return () => {
|
||||
const slots = {
|
||||
default: () => renderTabs(),
|
||||
tabBarExtraContent: () => renderQuick(),
|
||||
};
|
||||
return (
|
||||
<div class="multiple-tabs">
|
||||
<Tabs
|
||||
@@ -102,15 +143,12 @@ export default defineComponent({
|
||||
size="small"
|
||||
animated={false}
|
||||
hideAdd={true}
|
||||
tabBarGutter={4}
|
||||
tabBarGutter={3}
|
||||
activeKey={unref(activeKeyRef)}
|
||||
onChange={handleChange}
|
||||
onEdit={handleEdit}
|
||||
>
|
||||
{{
|
||||
default: () => renderTabs(),
|
||||
tabBarExtraContent: () => renderQuick(),
|
||||
}}
|
||||
{slots}
|
||||
</Tabs>
|
||||
</div>
|
||||
);
|
||||
|
@@ -1,9 +1,10 @@
|
||||
import { toRaw } from 'vue';
|
||||
import { toRaw, ref } from 'vue';
|
||||
import router from '/@/router';
|
||||
import { AppRouteRecordRaw } from '/@/router/types';
|
||||
import { TabItem, tabStore } from '/@/store/modules/tab';
|
||||
|
||||
export function initAffixTabs() {
|
||||
const affixList = ref<TabItem[]>([]);
|
||||
/**
|
||||
* @description: Filter all fixed routes
|
||||
*/
|
||||
@@ -23,13 +24,16 @@ export function initAffixTabs() {
|
||||
*/
|
||||
function addAffixTabs(): void {
|
||||
const affixTabs = filterAffixTabs((router.getRoutes() as unknown) as AppRouteRecordRaw[]);
|
||||
affixList.value = affixTabs;
|
||||
for (const tab of affixTabs) {
|
||||
tabStore.commitAddTab(tab);
|
||||
}
|
||||
}
|
||||
|
||||
let isAddAffix = false;
|
||||
if (!isAddAffix) {
|
||||
addAffixTabs();
|
||||
isAddAffix = true;
|
||||
}
|
||||
return affixList.value.map((item) => item.meta?.title).filter(Boolean);
|
||||
}
|
@@ -1,11 +1,11 @@
|
||||
import type { AppRouteRecordRaw } from '/@/router/types';
|
||||
import type { TabContentProps } from './tab.data';
|
||||
import type { TabContentProps } from './data';
|
||||
import type { Ref } from 'vue';
|
||||
import type { TabItem } from '/@/store/modules/tab';
|
||||
import type { DropMenu } from '/@/components/Dropdown';
|
||||
|
||||
import { computed, unref } from 'vue';
|
||||
import { TabContentEnum, MenuEventEnum, getActions } from './tab.data';
|
||||
import { TabContentEnum, MenuEventEnum, getActions } from './data';
|
||||
import { tabStore } from '/@/store/modules/tab';
|
||||
import { appStore } from '/@/store/modules/app';
|
||||
import { PageEnum } from '/@/enums/pageEnum';
|
||||
@@ -15,9 +15,7 @@ import { useTabs, isInitUseTab } from '/@/hooks/web/useTabs';
|
||||
import { RouteLocationRaw } from 'vue-router';
|
||||
|
||||
const { initTabFn } = useTabs();
|
||||
/**
|
||||
* @description: 右键下拉
|
||||
*/
|
||||
|
||||
export function useTabDropdown(tabContentProps: TabContentProps) {
|
||||
const { currentRoute } = router;
|
||||
const redo = useRedo();
|
||||
@@ -30,26 +28,24 @@ export function useTabDropdown(tabContentProps: TabContentProps) {
|
||||
: ((unref(currentRoute) as any) as AppRouteRecordRaw);
|
||||
});
|
||||
|
||||
// 当前tab列表
|
||||
const getTabsState = computed(() => {
|
||||
return tabStore.getTabsState;
|
||||
});
|
||||
// Current tab list
|
||||
const getTabsState = computed(() => tabStore.getTabsState);
|
||||
|
||||
/**
|
||||
* @description: 下拉列表
|
||||
* @description: drop-down list
|
||||
*/
|
||||
const getDropMenuList = computed(() => {
|
||||
const dropMenuList = getActions();
|
||||
// 重置为初始状态
|
||||
// Reset to initial state
|
||||
for (const item of dropMenuList) {
|
||||
item.disabled = false;
|
||||
}
|
||||
|
||||
// 没有tab
|
||||
// No tab
|
||||
if (!unref(getTabsState) || unref(getTabsState).length <= 0) {
|
||||
return dropMenuList;
|
||||
} else if (unref(getTabsState).length === 1) {
|
||||
// 只有一个tab
|
||||
// Only one tab
|
||||
for (const item of dropMenuList) {
|
||||
if (item.event !== MenuEventEnum.REFRESH_PAGE) {
|
||||
item.disabled = true;
|
||||
@@ -57,22 +53,20 @@ export function useTabDropdown(tabContentProps: TabContentProps) {
|
||||
}
|
||||
return dropMenuList;
|
||||
}
|
||||
if (!unref(getCurrentTab)) {
|
||||
return;
|
||||
}
|
||||
if (!unref(getCurrentTab)) return;
|
||||
const { meta, path } = unref(getCurrentTab);
|
||||
// console.log(unref(getCurrentTab));
|
||||
|
||||
// 刷新按钮
|
||||
// Refresh button
|
||||
const curItem = tabStore.getCurrentContextMenuState;
|
||||
const index = tabStore.getCurrentContextMenuIndexState;
|
||||
const refreshDisabled = curItem ? curItem.path !== path : true;
|
||||
// 关闭左侧
|
||||
// Close left
|
||||
const closeLeftDisabled = index === 0;
|
||||
|
||||
// 关闭右侧
|
||||
// Close right
|
||||
const closeRightDisabled = index === unref(getTabsState).length - 1;
|
||||
// 当前为固定tab
|
||||
// Currently fixed tab
|
||||
// TODO PERf
|
||||
dropMenuList[0].disabled = unref(isTabsRef) ? refreshDisabled : false;
|
||||
if (meta && meta.affix) {
|
||||
dropMenuList[1].disabled = true;
|
||||
@@ -84,7 +78,7 @@ export function useTabDropdown(tabContentProps: TabContentProps) {
|
||||
});
|
||||
|
||||
/**
|
||||
* @description: 关闭所有页面时,跳转页面
|
||||
* @description: Jump to page when closing all pages
|
||||
*/
|
||||
function gotoPage() {
|
||||
const len = unref(getTabsState).length;
|
||||
@@ -99,14 +93,14 @@ export function useTabDropdown(tabContentProps: TabContentProps) {
|
||||
toPath = p;
|
||||
}
|
||||
}
|
||||
// 跳到当前页面报错
|
||||
// Jump to the current page and report an error
|
||||
path !== toPath && go(toPath as PageEnum, true);
|
||||
}
|
||||
|
||||
function isGotoPage(currentTab?: TabItem) {
|
||||
const { path } = unref(currentRoute);
|
||||
const currentPath = (currentTab || unref(getCurrentTab)).path;
|
||||
// 不是当前tab,关闭左侧/右侧时,需跳转页面
|
||||
// Not the current tab, when you close the left/right side, you need to jump to the page
|
||||
if (path !== currentPath) {
|
||||
go(currentPath as PageEnum, true);
|
||||
}
|
||||
@@ -117,25 +111,31 @@ export function useTabDropdown(tabContentProps: TabContentProps) {
|
||||
} catch (error) {}
|
||||
redo();
|
||||
}
|
||||
|
||||
function closeAll() {
|
||||
tabStore.commitCloseAllTab();
|
||||
gotoPage();
|
||||
}
|
||||
|
||||
function closeLeft(tabItem?: TabItem) {
|
||||
tabStore.closeLeftTabAction(tabItem || unref(getCurrentTab));
|
||||
isGotoPage(tabItem);
|
||||
}
|
||||
|
||||
function closeRight(tabItem?: TabItem) {
|
||||
tabStore.closeRightTabAction(tabItem || unref(getCurrentTab));
|
||||
isGotoPage(tabItem);
|
||||
}
|
||||
|
||||
function closeOther(tabItem?: TabItem) {
|
||||
tabStore.closeOtherTabAction(tabItem || unref(getCurrentTab));
|
||||
isGotoPage(tabItem);
|
||||
}
|
||||
|
||||
function closeCurrent(tabItem?: TabItem) {
|
||||
closeTab(unref(tabItem || unref(getCurrentTab)));
|
||||
}
|
||||
|
||||
function scaleScreen() {
|
||||
const {
|
||||
headerSetting: { show: showHeader },
|
||||
@@ -159,7 +159,7 @@ export function useTabDropdown(tabContentProps: TabContentProps) {
|
||||
});
|
||||
}
|
||||
|
||||
// 处理右键事件
|
||||
// Handle right click event
|
||||
function handleMenuEvent(menu: DropMenu): void {
|
||||
const { event } = menu;
|
||||
|
||||
@@ -168,76 +168,74 @@ export function useTabDropdown(tabContentProps: TabContentProps) {
|
||||
scaleScreen();
|
||||
break;
|
||||
case MenuEventEnum.REFRESH_PAGE:
|
||||
// 刷新页面
|
||||
// refresh page
|
||||
refreshPage();
|
||||
break;
|
||||
// 关闭当前
|
||||
// Close current
|
||||
case MenuEventEnum.CLOSE_CURRENT:
|
||||
closeCurrent();
|
||||
break;
|
||||
// 关闭左侧
|
||||
// Close left
|
||||
case MenuEventEnum.CLOSE_LEFT:
|
||||
closeLeft();
|
||||
break;
|
||||
// 关闭右侧
|
||||
// Close right
|
||||
case MenuEventEnum.CLOSE_RIGHT:
|
||||
closeRight();
|
||||
break;
|
||||
// 关闭其他
|
||||
// Close other
|
||||
case MenuEventEnum.CLOSE_OTHER:
|
||||
closeOther();
|
||||
break;
|
||||
// 关闭其他
|
||||
// Close all
|
||||
case MenuEventEnum.CLOSE_ALL:
|
||||
closeAll();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return { getDropMenuList, handleMenuEvent };
|
||||
}
|
||||
|
||||
export function getObj(tabItem: TabItem) {
|
||||
const { params, path, query } = tabItem;
|
||||
return {
|
||||
params: params || {},
|
||||
path,
|
||||
query: query || {},
|
||||
};
|
||||
}
|
||||
|
||||
export function closeTab(closedTab: TabItem | AppRouteRecordRaw) {
|
||||
const { currentRoute, replace } = router;
|
||||
// 当前tab列表
|
||||
const getTabsState = computed(() => {
|
||||
return tabStore.getTabsState;
|
||||
});
|
||||
// Current tab list
|
||||
const getTabsState = computed(() => tabStore.getTabsState);
|
||||
|
||||
const { path } = unref(currentRoute);
|
||||
if (path !== closedTab.path) {
|
||||
// 关闭的不是激活tab
|
||||
// Closed is not the activation tab
|
||||
tabStore.commitCloseTab(closedTab);
|
||||
return;
|
||||
}
|
||||
// 关闭的为激活atb
|
||||
|
||||
// Closed is activated atb
|
||||
let toObj: RouteLocationRaw = {};
|
||||
|
||||
const index = unref(getTabsState).findIndex((item) => item.path === path);
|
||||
|
||||
// 如果当前为最左边tab
|
||||
// If the current is the leftmost tab
|
||||
if (index === 0) {
|
||||
// 只有一个tab,则跳转至首页,否则跳转至右tab
|
||||
// There is only one tab, then jump to the homepage, otherwise jump to the right tab
|
||||
if (unref(getTabsState).length === 1) {
|
||||
toObj = PageEnum.BASE_HOME;
|
||||
} else {
|
||||
// 跳转至右边tab
|
||||
// Jump to the right tab
|
||||
const page = unref(getTabsState)[index + 1];
|
||||
const { params, path, query } = page;
|
||||
toObj = {
|
||||
params,
|
||||
path,
|
||||
query,
|
||||
};
|
||||
toObj = getObj(page);
|
||||
}
|
||||
} else {
|
||||
// 跳转至左边tab
|
||||
// Close the current tab
|
||||
const page = unref(getTabsState)[index - 1];
|
||||
const { params, path, query } = page;
|
||||
toObj = {
|
||||
params: params || {},
|
||||
path,
|
||||
query: query || {},
|
||||
};
|
||||
toObj = getObj(page);
|
||||
}
|
||||
const route = (unref(currentRoute) as unknown) as AppRouteRecordRaw;
|
||||
tabStore.commitCloseTab(route);
|
||||
|
@@ -203,7 +203,7 @@ export default defineComponent({
|
||||
getMenuFixed,
|
||||
getCollapsed,
|
||||
getShowSearch,
|
||||
getHasDrag,
|
||||
getCanDrag,
|
||||
getTopMenuAlign,
|
||||
getAccordion,
|
||||
getMenuWidth,
|
||||
@@ -267,7 +267,7 @@ export default defineComponent({
|
||||
handler: (e) => {
|
||||
baseHandler(HandlerEnum.MENU_HAS_DRAG, e);
|
||||
},
|
||||
def: unref(getHasDrag),
|
||||
def: unref(getCanDrag),
|
||||
disabled: !unref(getShowMenuRef),
|
||||
}),
|
||||
renderSwitchItem('侧边菜单搜索', {
|
||||
|
@@ -30,7 +30,7 @@ export function handler(event: HandlerEnum, value: any): DeepPartial<ProjectConf
|
||||
};
|
||||
|
||||
case HandlerEnum.MENU_HAS_DRAG:
|
||||
return { menuSetting: { hasDrag: value } };
|
||||
return { menuSetting: { canDrag: value } };
|
||||
|
||||
case HandlerEnum.MENU_ACCORDION:
|
||||
return { menuSetting: { accordion: value } };
|
||||
|
@@ -1,7 +1,7 @@
|
||||
@import (reference) '../../../design/index.less';
|
||||
|
||||
.layout-sidebar {
|
||||
overflow: hidden;
|
||||
// overflow: hidden;
|
||||
|
||||
&.fixed {
|
||||
position: fixed;
|
||||
@@ -15,7 +15,7 @@
|
||||
}
|
||||
|
||||
&:not(.ant-layout-sider-dark) {
|
||||
border-right: 1px solid @border-color-light;
|
||||
// border-right: 1px solid @border-color-light;
|
||||
box-shadow: 2px 0 8px 0 rgba(29, 35, 41, 0.05);
|
||||
}
|
||||
|
||||
|
@@ -82,7 +82,7 @@ export function useTrigger() {
|
||||
* @param dragBarRef
|
||||
*/
|
||||
export function useDragLine(siderRef: Ref<any>, dragBarRef: Ref<any>) {
|
||||
const { getMiniWidthNumber, getCollapsed, setMenuSetting, getHasDrag } = useMenuSetting();
|
||||
const { getMiniWidthNumber, getCollapsed, setMenuSetting, getCanDrag } = useMenuSetting();
|
||||
|
||||
const getDragBarStyle = computed(() => {
|
||||
if (unref(getCollapsed)) {
|
||||
@@ -101,7 +101,7 @@ export function useDragLine(siderRef: Ref<any>, dragBarRef: Ref<any>) {
|
||||
function renderDragLine() {
|
||||
return (
|
||||
<div
|
||||
class={[`layout-sidebar__darg-bar`, !unref(getHasDrag) ? 'hide' : '']}
|
||||
class={[`layout-sidebar__darg-bar`, { hide: !unref(getCanDrag) }]}
|
||||
style={unref(getDragBarStyle)}
|
||||
ref={dragBarRef}
|
||||
/>
|
||||
|
Reference in New Issue
Block a user