23
This commit is contained in:
263
draggable-panels/src/fauto/stores/panelStore.ts
Normal file
263
draggable-panels/src/fauto/stores/panelStore.ts
Normal file
@@ -0,0 +1,263 @@
|
||||
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
|
||||
}
|
||||
})
|
||||
Reference in New Issue
Block a user