import { defineStore, acceptHMRUpdate } from 'pinia'; type IconSize = '1x1' | '1x2' | '2x1' | '2x2' | '2x4'; const DEFAULT_GROUP_ID = 'home'; // 模拟数据(来自截图参考) interface Icon { id: string; name: string; url: string; size?: IconSize; img?: string; // 可选:用于图片图标(如徽标) text?: string; // 可选:用于文字图标 bgColor?: string; // 可选:纯色背景 groupId?: string; } interface DragState { isDragging: boolean; itemId: string | null; itemType: 'icon' | 'widget' | null; startX: number; startY: number; currentX: number; currentY: number; } interface LayoutState { icons: Icon[]; dragState: DragState; } const defaultIcons: Icon[] = [ { id: '1', name: '淘宝', url: 'https://taobao.com', bgColor: '#ff4f00' }, { id: '2', name: '京东商城', url: 'https://jd.com', bgColor: '#e4393c' }, { id: '3', name: '百度', url: 'https://baidu.com', bgColor: '#3388ff' }, { id: '4', name: '备忘录', url: '#', bgColor: '#f9ca24' }, { id: '5', name: '爱奇艺', url: 'https://iqiyi.com', bgColor: '#00be06' }, { id: '6', name: '文件夹', url: '#', bgColor: '#4285f4' }, { id: '7', name: '抖音', url: 'https://douyin.com', bgColor: '#222' }, { id: '8', name: '小浣熊', url: '#', bgColor: '#f0932b' }, { id: '9', name: 'AiPPT', url: '#', bgColor: '#d63031' }, { id: '10', name: '电影日历', url: '#', bgColor: 'transparent', img: 'https://example.com/movie_poster.png' }, // 图片示例 { id: '11', name: '稿定设计', url: '#', bgColor: '#00aaff' }, { id: '12', name: '壁纸', url: '#', bgColor: '#1dd1a1' }, { id: '13', 'name': '即梦AI', url: '#', bgColor: '#6c5ce7' }, { id: '14', name: '码上掘金', url: '#', bgColor: '#1e80ff' }, { id: '15', name: '扩展管理', url: '#', bgColor: '#7f8c8d' }, { id: '16', name: '书签管理', url: '#', bgColor: '#f1c40f' }, ]; const defaultGroupById: Record = { '1': 'product', '2': 'product', '3': 'home', '4': 'product', '5': 'fun', '6': 'home', '7': 'fun', '8': 'fun', '9': 'ai', '10': 'fun', '11': 'design', '12': 'design', '13': 'ai', '14': 'code', '15': 'home', '16': 'home', }; const savedIcons = localStorage.getItem('itab_icons'); const normalizeIcons = (icons: Icon[]): Icon[] => icons.map(icon => ({ ...icon, size: icon.size ?? '1x1', groupId: icon.groupId ?? defaultGroupById[icon.id] ?? DEFAULT_GROUP_ID, })); const loadIcons = (): Icon[] => { if (!savedIcons) return normalizeIcons(defaultIcons); try { return normalizeIcons(JSON.parse(savedIcons) as Icon[]); } catch { return normalizeIcons(defaultIcons); } }; export const useLayoutStore = defineStore('layout', { state: (): LayoutState => ({ icons: loadIcons(), dragState: { isDragging: false, itemId: null, itemType: null, startX: 0, startY: 0, currentX: 0, currentY: 0, } }), actions: { addIcon(icon: Omit) { const nextId = `custom-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`; this.icons.push({ ...icon, id: nextId, groupId: icon.groupId ?? DEFAULT_GROUP_ID }); localStorage.setItem('itab_icons', JSON.stringify(this.icons)); }, updateIcon(iconId: string, updates: Partial>) { const icon = this.icons.find(item => item.id === iconId); if (!icon) return; Object.assign(icon, updates); localStorage.setItem('itab_icons', JSON.stringify(this.icons)); }, reorderIcons(draggedId: string, targetId: string) { const draggedIndex = this.icons.findIndex(p => p.id === draggedId); const targetIndex = this.icons.findIndex(p => p.id === targetId); if (draggedIndex !== -1 && targetIndex !== -1) { // 直接交换 const draggedItem = this.icons[draggedIndex]; this.icons[draggedIndex] = this.icons[targetIndex]; this.icons[targetIndex] = draggedItem; // 持久化顺序 localStorage.setItem('itab_icons', JSON.stringify(this.icons)); } }, setIconOrder(orderIds: string[]) { const ordered: Icon[] = []; const seen = new Set(); for (const id of orderIds) { const icon = this.icons.find(item => item.id === id); if (icon) { ordered.push(icon); seen.add(icon.id); } } for (const icon of this.icons) { if (!seen.has(icon.id)) { ordered.push(icon); } } this.icons = ordered; localStorage.setItem('itab_icons', JSON.stringify(this.icons)); }, updateIconSize(iconId: string, newSize: IconSize) { const icon = this.icons.find(item => item.id === iconId); if (icon) { icon.size = newSize; localStorage.setItem('itab_icons', JSON.stringify(this.icons)); } }, deleteIcon(itemId: string) { const index = this.icons.findIndex(p => p.id === itemId); if (index !== -1) { this.icons.splice(index, 1); // 持久化顺序 localStorage.setItem('itab_icons', JSON.stringify(this.icons)); } }, } }); if (import.meta.hot) { import.meta.hot.accept(acceptHMRUpdate(useLayoutStore, import.meta.hot)); }