JGJS2026/src/pinia/tab.ts
2026-03-17 17:52:46 +08:00

143 lines
4.2 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { defineStore } from 'pinia'
import { ref } from 'vue'
import {
PROJECT_TAB_ID,
QUICK_CONTRACT_TAB_ID,
QUICK_TAB_ID,
readWorkspaceMode
} from '@/lib/workspace'
export interface TabItem<TProps = Record<string, unknown>> {
id: string
title: string
componentName: string
props?: TProps
}
const DEFAULT_PROJECT_TAB: TabItem = {
id: PROJECT_TAB_ID,
title: '项目卡片',
componentName: 'ProjectCalcView'
}
/** 根据当前 workspace mode 返回受保护的 tab ID 集合 */
const getProtectedIds = (): Set<string> => {
return readWorkspaceMode() === 'quick'
? new Set([QUICK_TAB_ID, QUICK_CONTRACT_TAB_ID])
: new Set([PROJECT_TAB_ID, QUICK_CONTRACT_TAB_ID])
}
/** 根据当前 workspace mode 返回首个 tab 的 fallback ID */
const getFallbackTabId = (): string => {
return readWorkspaceMode() === 'quick' ? QUICK_TAB_ID : PROJECT_TAB_ID
}
export const useTabStore = defineStore(
'tabs',
() => {
const tabs = ref<TabItem[]>([{ ...DEFAULT_PROJECT_TAB }])
const activeTabId = ref()
const hasCompletedSetup = ref(false)
const ensureHomeTab = () => {
const fallbackId = getFallbackTabId()
if (tabs.value.some(tab => tab.id === fallbackId)) return
// quick 模式下不自动插入默认 tab由 enterWorkspace 控制
if (readWorkspaceMode() === 'quick') return
tabs.value = [{ ...DEFAULT_PROJECT_TAB }, ...tabs.value]
}
const ensureActiveValid = () => {
ensureHomeTab()
if (tabs.value.length === 0) tabs.value = [{ ...DEFAULT_PROJECT_TAB }]
if (!tabs.value.some(tab => tab.id === activeTabId.value)) {
activeTabId.value = tabs.value[0]?.id ?? getFallbackTabId()
}
}
const enterWorkspace = (config: TabItem) => {
tabs.value = [{ ...config }]
activeTabId.value = config.id
}
const openTab = (config: TabItem) => {
if (!tabs.value.some(tab => tab.id === config.id)) {
tabs.value = [...tabs.value, config]
}
activeTabId.value = config.id
}
const removeTab = (id: string) => {
if (getProtectedIds().has(id)) return
const index = tabs.value.findIndex(tab => tab.id === id)
if (index < 0) return
const wasActive = activeTabId.value === id
tabs.value = tabs.value.filter(tab => tab.id !== id)
ensureHomeTab()
if (wasActive) {
const fallbackIndex = Math.max(0, Math.min(index - 1, tabs.value.length - 1))
activeTabId.value = tabs.value[fallbackIndex]?.id ?? getFallbackTabId()
return
}
ensureActiveValid()
}
const closeAllTabs = () => {
const protectedIds = getProtectedIds()
const protectedTabs = tabs.value.filter(tab => protectedIds.has(tab.id))
tabs.value = protectedTabs.length > 0 ? protectedTabs : [{ ...DEFAULT_PROJECT_TAB }]
activeTabId.value = tabs.value[0]?.id ?? getFallbackTabId()
}
const closeLeftTabs = (targetId: string) => {
const targetIndex = tabs.value.findIndex(tab => tab.id === targetId)
if (targetIndex < 0) return
const protectedIds = getProtectedIds()
tabs.value = tabs.value.filter((tab, index) => protectedIds.has(tab.id) || index >= targetIndex)
ensureActiveValid()
}
const closeRightTabs = (targetId: string) => {
const targetIndex = tabs.value.findIndex(tab => tab.id === targetId)
if (targetIndex < 0) return
const protectedIds = getProtectedIds()
tabs.value = tabs.value.filter((tab, index) => protectedIds.has(tab.id) || index <= targetIndex)
ensureActiveValid()
}
const closeOtherTabs = (targetId: string) => {
const protectedIds = getProtectedIds()
tabs.value = tabs.value.filter(tab => protectedIds.has(tab.id) || tab.id === targetId)
ensureHomeTab()
activeTabId.value = tabs.value.some(tab => tab.id === targetId) ? targetId : getFallbackTabId()
}
const resetTabs = () => {
tabs.value = [{ ...DEFAULT_PROJECT_TAB }]
activeTabId.value = PROJECT_TAB_ID
hasCompletedSetup.value = false
}
return {
tabs,
activeTabId,
hasCompletedSetup,
enterWorkspace,
openTab,
removeTab,
closeAllTabs,
closeLeftTabs,
closeRightTabs,
closeOtherTabs,
resetTabs
}
},
{
persist: true
}
)