Skip to content

Commit b8a767d

Browse files
hellohookehonghuangdc
authored andcommitted
feat(projects): support pinning and unpinning of tabs
1 parent 605173a commit b8a767d

File tree

6 files changed

+88
-4
lines changed

6 files changed

+88
-4
lines changed

src/layouts/modules/global-tab/context-menu.vue

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ const props = withDefaults(defineProps<Props>(), {
2626
2727
const visible = defineModel<boolean>('visible');
2828
29-
const { removeTab, clearTabs, clearLeftTabs, clearRightTabs } = useTabStore();
29+
const { removeTab, clearTabs, clearLeftTabs, clearRightTabs, fixTab, unfixTab, isTabRetain } = useTabStore();
3030
const { SvgIconVNode } = useSvgIcon();
3131
3232
type DropdownOption = {
@@ -64,6 +64,23 @@ const options = computed(() => {
6464
icon: SvgIconVNode({ icon: 'ant-design:line-outlined', fontSize: 18 })
6565
}
6666
];
67+
68+
if (props.tabId !== '/home') {
69+
if (isTabRetain(props.tabId)) {
70+
opts.push({
71+
key: 'unpin',
72+
label: $t('dropdown.unpin'),
73+
icon: SvgIconVNode({ icon: 'mdi:pin-off-outline', fontSize: 18 })
74+
});
75+
} else {
76+
opts.push({
77+
key: 'pin',
78+
label: $t('dropdown.pin'),
79+
icon: SvgIconVNode({ icon: 'mdi:pin-outline', fontSize: 18 })
80+
});
81+
}
82+
}
83+
6784
const { excludeKeys, disabledKeys } = props;
6885
6986
const result = opts.filter(opt => !excludeKeys.includes(opt.key));
@@ -98,6 +115,12 @@ const dropdownAction: Record<App.Global.DropdownKey, () => void> = {
98115
},
99116
closeAll() {
100117
clearTabs();
118+
},
119+
pin() {
120+
fixTab(props.tabId);
121+
},
122+
unpin() {
123+
unfixTab(props.tabId);
101124
}
102125
};
103126

src/locales/langs/en-us.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -336,7 +336,9 @@ const local: App.I18n.Schema = {
336336
closeOther: 'Close Other',
337337
closeLeft: 'Close Left',
338338
closeRight: 'Close Right',
339-
closeAll: 'Close All'
339+
closeAll: 'Close All',
340+
pin: 'Pin Tab',
341+
unpin: 'Unpin Tab'
340342
},
341343
icon: {
342344
themeConfig: 'Theme Configuration',

src/locales/langs/zh-cn.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -333,7 +333,9 @@ const local: App.I18n.Schema = {
333333
closeOther: '关闭其它',
334334
closeLeft: '关闭左侧',
335335
closeRight: '关闭右侧',
336-
closeAll: '关闭所有'
336+
closeAll: '关闭所有',
337+
pin: '固定标签',
338+
unpin: '取消固定'
337339
},
338340
icon: {
339341
themeConfig: '主题配置',

src/store/modules/tab/index.ts

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import {
1818
getTabByRoute,
1919
getTabIdByRoute,
2020
isTabInTabs,
21+
reorderFixedTabs,
2122
updateTabByI18nKey,
2223
updateTabsByI18nKey
2324
} from './shared';
@@ -248,6 +249,48 @@ export const useTabStore = defineStore(SetupStoreId.Tab, () => {
248249
await clearTabs(excludes);
249250
}
250251

252+
/**
253+
* Fix tab
254+
*
255+
* @param tabId
256+
*/
257+
function fixTab(tabId: string) {
258+
const tabIndex = tabs.value.findIndex(t => t.id === tabId);
259+
if (tabIndex === -1) return;
260+
261+
const tab = tabs.value[tabIndex];
262+
const fixedCount = getFixedTabIds(tabs.value).length;
263+
tab.fixedIndex = fixedCount;
264+
265+
if (tabIndex !== fixedCount) {
266+
tabs.value.splice(tabIndex, 1);
267+
tabs.value.splice(fixedCount, 0, tab);
268+
}
269+
270+
reorderFixedTabs(tabs.value);
271+
}
272+
273+
/**
274+
* Unfix tab
275+
*
276+
* @param tabId
277+
*/
278+
function unfixTab(tabId: string) {
279+
const tabIndex = tabs.value.findIndex(t => t.id === tabId);
280+
if (tabIndex === -1) return;
281+
282+
const tab = tabs.value[tabIndex];
283+
tab.fixedIndex = undefined;
284+
285+
const fixedCount = getFixedTabIds(tabs.value).length;
286+
if (tabIndex !== fixedCount) {
287+
tabs.value.splice(tabIndex, 1);
288+
tabs.value.splice(fixedCount, 0, tab);
289+
}
290+
291+
reorderFixedTabs(tabs.value);
292+
}
293+
251294
/**
252295
* Set new label of tab
253296
*
@@ -328,6 +371,8 @@ export const useTabStore = defineStore(SetupStoreId.Tab, () => {
328371
clearTabs,
329372
clearLeftTabs,
330373
clearRightTabs,
374+
fixTab,
375+
unfixTab,
331376
switchRouteByTab,
332377
setTabLabel,
333378
resetTabLabel,

src/store/modules/tab/shared.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,18 @@ export function getFixedTabIds(tabs: App.Global.Tab[]) {
198198
return fixedTabs.map(tab => tab.id);
199199
}
200200

201+
/**
202+
* Reorder fixed tabs fixedIndex
203+
*
204+
* @param tabs
205+
*/
206+
export function reorderFixedTabs(tabs: App.Global.Tab[]) {
207+
const fixedTabs = getFixedTabs(tabs);
208+
fixedTabs.forEach((t, i) => {
209+
t.fixedIndex = i;
210+
});
211+
}
212+
201213
/**
202214
* Update tabs label
203215
*

src/typings/app.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -282,7 +282,7 @@ declare namespace App {
282282
type FormRule = import('naive-ui').FormItemRule;
283283

284284
/** The global dropdown key */
285-
type DropdownKey = 'closeCurrent' | 'closeOther' | 'closeLeft' | 'closeRight' | 'closeAll';
285+
type DropdownKey = 'closeCurrent' | 'closeOther' | 'closeLeft' | 'closeRight' | 'closeAll' | 'pin' | 'unpin';
286286
}
287287

288288
/**

0 commit comments

Comments
 (0)