Files
fauto-design/draggable-panels/src/fauto/stores/panelStore.ts
2025-12-20 23:16:23 +08:00

264 lines
7.1 KiB
TypeScript

import { defineStore } from 'pinia'
import { ref, watch, computed } from 'vue'
import type { LayoutConfig, TabItem, Panel } from '../types'
import { materialList, getMaterialInfo } from '../materials'
// 生成唯一ID
const generateId = () => Math.random().toString(36).substring(2, 9)
// 默认配置
const getDefaultLayout = (): LayoutConfig => ({
leftPanel: {
id: 'left',
tabs: [],
activeTabId: null
},
centerPanel: {
id: 'center',
tabs: [],
activeTabId: null
},
rightPanel: {
id: 'right',
tabs: [],
activeTabId: null
}
})
// 初始化每个面板的activeTabId
const initActiveTabIds = (layout: LayoutConfig): LayoutConfig => {
const panels: (keyof LayoutConfig)[] = ['leftPanel', 'centerPanel', 'rightPanel']
panels.forEach(key => {
const panel = layout[key]
if (panel.tabs.length > 0 && !panel.activeTabId) {
panel.activeTabId = panel.tabs[0].id
}
})
return layout
}
export const usePanelStore = defineStore('panel', () => {
// 布局配置
const layout = ref<LayoutConfig>(initActiveTabIds(getDefaultLayout()))
// 物料组件状态独立存储 (materialId -> state)
const materialStates = ref<Record<string, Record<string, any>>>({})
// 是否已加载配置
const isLoaded = ref(false)
// 获取所有已打开的物料组件ID
const openedMaterialIds = computed(() => {
const allTabs = [
...layout.value.leftPanel.tabs,
...layout.value.centerPanel.tabs,
...layout.value.rightPanel.tabs
]
return allTabs
.filter(tab => tab.materialId)
.map(tab => tab.materialId as string)
})
// 获取可用的物料组件列表(未打开的)
const availableMaterials = computed(() => {
return materialList.filter(m => !openedMaterialIds.value.includes(m.id))
})
// 检查物料组件是否已打开
const isMaterialOpened = (materialId: string) => {
return openedMaterialIds.value.includes(materialId)
}
// 加载配置
const loadConfig = async () => {
try {
// 加载布局配置
const response = await fetch('/api/config')
if (response.ok) {
const config = await response.json()
if (config && config.layout) {
layout.value = initActiveTabIds(config.layout)
}
}
// 加载物料组件状态
const statesResponse = await fetch('/api/material-states')
if (statesResponse.ok) {
const states = await statesResponse.json()
if (states && typeof states === 'object') {
materialStates.value = states
}
}
} catch (error) {
console.log('使用默认配置')
}
isLoaded.value = true
}
// 保存配置
const saveConfig = async () => {
try {
await fetch('/api/config', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
layout: layout.value,
lastUpdated: new Date().toISOString()
})
})
} catch (error) {
console.error('保存配置失败:', error)
}
}
// 保存物料组件状态
const saveMaterialStates = async () => {
try {
await fetch('/api/material-states', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(materialStates.value)
})
} catch (error) {
console.error('保存物料状态失败:', error)
}
}
// 获取物料组件状态
const getMaterialState = (materialId: string): Record<string, any> | undefined => {
return materialStates.value[materialId]
}
// 更新物料组件状态
const updateMaterialState = (materialId: string, state: Record<string, any>) => {
materialStates.value[materialId] = { ...materialStates.value[materialId], ...state }
saveMaterialStates()
}
// 监听变化并自动保存
watch(layout, () => {
if (isLoaded.value) {
saveConfig()
}
}, { deep: true })
// 获取面板
const getPanel = (panelId: string): Panel | undefined => {
const panels = [layout.value.leftPanel, layout.value.centerPanel, layout.value.rightPanel]
return panels.find(p => p.id === panelId)
}
// 添加新Tab
const addTab = (panelId: string, tab?: Partial<TabItem>) => {
const panel = getPanel(panelId)
if (panel) {
// 检查物料组件是否已打开
if (tab?.materialId && isMaterialOpened(tab.materialId)) {
console.warn('该物料组件已打开')
return
}
const newTab: TabItem = {
id: generateId(),
title: tab?.title || `新窗口 ${panel.tabs.length + 1}`,
content: tab?.content || '新窗口内容',
materialId: tab?.materialId
}
panel.tabs.push(newTab)
panel.activeTabId = newTab.id
}
}
// 打开物料组件
const openMaterial = (materialId: string, panelId: string = 'center') => {
if (isMaterialOpened(materialId)) {
console.warn('该物料组件已打开')
return
}
const materialInfo = getMaterialInfo(materialId)
if (materialInfo) {
addTab(panelId, {
title: materialInfo.name,
materialId: materialId
})
}
}
// 关闭Tab
const closeTab = (panelId: string, tabId: string) => {
const panel = getPanel(panelId)
if (panel) {
const index = panel.tabs.findIndex(t => t.id === tabId)
if (index > -1) {
// 物料组件状态已经在 materialStates 中独立存储,不需要额外处理
panel.tabs.splice(index, 1)
// 更新激活的Tab
if (panel.activeTabId === tabId) {
panel.activeTabId = panel.tabs.length > 0
? panel.tabs[Math.max(0, index - 1)].id
: null
}
}
}
}
// 设置激活的Tab
const setActiveTab = (panelId: string, tabId: string) => {
const panel = getPanel(panelId)
if (panel) {
panel.activeTabId = tabId
}
}
// 移动Tab到另一个面板
const moveTab = (fromPanelId: string, toPanelId: string, tabId: string, toIndex?: number) => {
const fromPanel = getPanel(fromPanelId)
const toPanel = getPanel(toPanelId)
if (fromPanel && toPanel) {
const tabIndex = fromPanel.tabs.findIndex(t => t.id === tabId)
if (tabIndex > -1) {
const [tab] = fromPanel.tabs.splice(tabIndex, 1)
if (toIndex !== undefined) {
toPanel.tabs.splice(toIndex, 0, tab)
} else {
toPanel.tabs.push(tab)
}
// 更新激活状态
toPanel.activeTabId = tab.id
if (fromPanel.activeTabId === tabId && fromPanel.tabs.length > 0) {
fromPanel.activeTabId = fromPanel.tabs[0].id
} else if (fromPanel.tabs.length === 0) {
fromPanel.activeTabId = null
}
}
}
}
// 在默认面板添加新窗口
const addNewWindow = () => {
addTab('center')
}
return {
layout,
materialStates,
isLoaded,
openedMaterialIds,
availableMaterials,
isMaterialOpened,
loadConfig,
saveConfig,
getMaterialState,
updateMaterialState,
addTab,
openMaterial,
closeTab,
setActiveTab,
moveTab,
addNewWindow
}
})