Skip to content

Commit

Permalink
feature: 标签页操作栏
Browse files Browse the repository at this point in the history
  • Loading branch information
jsxiaosi committed Jul 2, 2022
1 parent b6fc34d commit ced84d5
Show file tree
Hide file tree
Showing 30 changed files with 560 additions and 125 deletions.
4 changes: 4 additions & 0 deletions mock/demo/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,10 @@ const power = [
},
],
},
{
path: '/details_page',
name: 'RtDetailsPage',
},
];

const adminRoute = [
Expand Down
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
"mockjs": "^1.1.0",
"path": "^0.12.7",
"pinia": "^2.0.14",
"qs": "^6.11.0",
"sortablejs": "^1.15.0",
"vue": "^3.2.37",
"vue-i18n": "^9.1.10",
Expand All @@ -57,6 +58,7 @@
"@types/lodash-es": "^4.17.6",
"@types/marked": "^4.0.3",
"@types/node": "^17.0.42",
"@types/qs": "^6.9.7",
"@types/sortablejs": "^1.13.0",
"@typescript-eslint/eslint-plugin": "^5.27.1",
"@typescript-eslint/parser": "^5.27.1",
Expand Down
4 changes: 3 additions & 1 deletion src/layouts/pageLayouts/components/AppMain/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@
<script setup lang="ts">
import { usePermissionStoreHook } from '@/store/modules/permission';
import { computed } from 'vue';
const getInclude = computed<string[]>(() => usePermissionStoreHook().cachePageList as string[]);
const getInclude = computed<string[]>(() => {
return usePermissionStoreHook().cachePageList as string[];
});
</script>

<style lang="scss">
Expand Down
90 changes: 90 additions & 0 deletions src/layouts/pageLayouts/components/AppTabs/hooks/useTabsChange.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import { usePermissionStoreHook } from '@/store/modules/permission';
import { MultiTabsType } from '@/store/types';
import { removeClass, toggleClass } from '@/utils/operate';
import { Ref, unref } from 'vue';
import { useRoute, useRouter } from 'vue-router';
import qs from 'qs';

export const useTabsChange = (multiTabs: Ref<MultiTabsType[]>) => {
const route = useRoute();
const router = useRouter();

const setTabPaneKey = (item: MultiTabsType): string => {
return `${item.path}${
item.query && Object.keys(item.query).length ? '?' + qs.stringify(item.query) : ''
}`;
};

// 添加标签
const addRouteTabs = (routeRaw: MultiTabsType) => {
const { path, name, query, meta } = routeRaw;
const currentRoute = { path, meta, query, name };
if (!query) currentRoute.query = {};
usePermissionStoreHook().handleMultiTabs('add', currentRoute);
};

// 关闭标签
const closeTabsRoute = (e: string, type: 'other' | 'left' | 'right') => {
const valueIndex = multiTabs.value.findIndex((i) => i.path === e);
const mapList = multiTabs.value.filter((i, index) => {
if (i.path !== e && type === 'other') return true;
else if (index < valueIndex && type === 'left') return true;
else if (index > valueIndex && type === 'right') return true;
return false;
});
mapList.forEach((i) => {
usePermissionStoreHook().cacheOperate({
mode: 'delete',
name: i.name || '',
});
usePermissionStoreHook().handleMultiTabs('delete', i.path);
});

router.push({
path: multiTabs.value[valueIndex].path,
query: multiTabs.value[valueIndex].query,
});
};

// 关闭当前导航
const removeTab = (e: string) => {
const valueIndex = multiTabs.value.findIndex((i) => setTabPaneKey(i) === e);
const tabsLength = multiTabs.value.length;
let value, toRoute;
if (valueIndex === tabsLength - 1) {
value = multiTabs.value[valueIndex - 1];
toRoute = {
path: value.path,
query: value.query,
};
} else if (multiTabs.value[valueIndex].name === route.name) {
value = multiTabs.value[tabsLength - 1];
toRoute = {
path: value.path,
query: value.query,
};
}
if (toRoute) router.push(toRoute);
usePermissionStoreHook().cacheOperate({
mode: 'delete',
name: multiTabs.value[valueIndex].name || '',
});
usePermissionStoreHook().handleMultiTabs('delete', multiTabs.value[valueIndex]);
};

// 重新加载
function onFresh(item?: MultiTabsType) {
const refreshButton = 'refresh-button';
toggleClass(true, refreshButton, document.querySelector('.rotate'));
const { path, query } = unref(item || route);
router.replace({
path: '/redirect' + path,
query: query,
});
setTimeout(() => {
removeClass(document.querySelector('.rotate'), refreshButton);
}, 600);
}

return { setTabPaneKey, addRouteTabs, onFresh, closeTabsRoute, removeTab };
};
131 changes: 131 additions & 0 deletions src/layouts/pageLayouts/components/AppTabs/hooks/useTabsView.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
import { MultiTabsType } from '@/store/types';
import { computed, CSSProperties, reactive, Ref, ref, watch } from 'vue';
import { useTabsChange } from './useTabsChange';

type RightClickTags = {
text: string;
disabled: boolean;
code: string;
};

export const useTabsView = (multiTabs: Ref<MultiTabsType[]>) => {
const { onFresh, removeTab, closeTabsRoute } = useTabsChange(multiTabs);
const rightClickTags = reactive<RightClickTags[]>([
{
text: '刷新',
disabled: false,
code: 'refresh',
},
{
text: '关闭',
disabled: false,
code: 'close',
},
{
text: '关闭其他标签',
disabled: false,
code: 'closeOther',
},
{
text: '关闭左侧其他标签',
disabled: false,
code: 'closeLeftOther',
},
{
text: '关闭右侧其他标签',
disabled: false,
code: 'closeRightOther',
},
]);

const visible = ref(false);

const rightViewTop = ref<number>(0);
const rightViewLeft = ref<number>(0);

const activityItem = ref<MultiTabsType | null>(null);

const disabledMenu = (signList: number[], show: boolean) => {
signList.forEach((v) => {
rightClickTags[v].disabled = show;
});
};

const showMenu = (item: string) => {
disabledMenu([0, 1, 2, 3, 4], false);
const multFindIndex = multiTabs.value.findIndex((i) => i.path === item);
const multlength = multiTabs.value.length;
if (multFindIndex === 0 && multlength > 1) {
disabledMenu([3], true);
} else if (multFindIndex === multlength - 1 && multlength > 1) {
disabledMenu([4], true);
} else if (multlength === 1) {
disabledMenu([1, 2, 3, 4], true);
}
};

const contextmenu = (path: string, e?: MouseEvent) => {
const item = multiTabs.value.find((i) => i.path === path);
if (!item) return;
closeMenu();
showMenu(item.path);
activityItem.value = item;
if (e) {
setTimeout(() => {
rightViewLeft.value = e.clientX;
rightViewTop.value = e.clientY;
visible.value = true;
}, 100);
}
};

const rightViewStyle = computed((): CSSProperties => {
return { left: rightViewLeft.value + 'px', top: rightViewTop.value + 'px' };
});

const closeMenu = () => {
visible.value = false;
};

watch(
() => visible.value,
(val) => {
if (val) {
document.body.addEventListener('click', closeMenu);
} else {
document.body.removeEventListener('click', closeMenu);
}
},
);

const rightViewChange = (item: RightClickTags) => {
if (!activityItem.value) return;
switch (item.code) {
case 'refresh': {
onFresh(activityItem.value);
break;
}
case 'close': {
removeTab(activityItem.value.path);
break;
}
case 'closeOther': {
closeTabsRoute(activityItem.value.path, 'other');
break;
}
case 'closeLeftOther': {
closeTabsRoute(activityItem.value.path, 'left');
break;
}
case 'closeRightOther': {
closeTabsRoute(activityItem.value.path, 'right');
break;
}
default:
break;
}
showMenu(activityItem.value.path);
};

return { visible, rightClickTags, rightViewStyle, contextmenu, rightViewChange };
};
Loading

0 comments on commit ced84d5

Please sign in to comment.