import type { Component } from 'vue'; import { markRaw, shallowRef } from 'vue'; export type WorkbenchModuleKey = // 保留:现有 key 沿用(避免影响线上用户布局存储) | 'myTodo' // A1 · 我的待办 | 'myProject' // B7 · 我参与的项目 | 'shortcut' // E19 · 快捷入口 | 'projectHealth' // C15 · 产品 / 项目健康度 // 新增(蓝图 2026-05-22,原 A3 myTicket、A4 mentions、A5 approval、A6 worklogReminder、B10 personalItem、F23 projectSnapshot、C11 teamTodo、E21 favorite 已废弃,F23 已并入 B7 myProject "我负责的" tab) | 'myExecution' // B8 · 我负责的执行 | 'productSnapshot' // F24 · 产品深度快照(对象快照 / 当前对象切换) | 'teamLoad' // C13 · 团队负载(管理者) | 'myWeekWorklog'; // D16 · 工时(含「我的工时 / 团队工时」两 tab,原 C12 teamWorklog 已并入) // 扩展:action(动作型 widget)、snapshot(对象快照型 widget,需指定一个对象) export type WorkbenchModuleCategory = 'personal' | 'manager' | 'tool' | 'action' | 'snapshot'; export interface WorkbenchModuleMeta { key: WorkbenchModuleKey; component: Component; displayName: string; icon: string; category: WorkbenchModuleCategory; defaultVisible: boolean; /** 默认网格位置与尺寸(12 栅格)。hidden 项的 x/y 仅作占位,show 时动态找空位。 */ defaultGrid: { x: number; y: number; w: number; h: number; minW: number; minH: number }; } const placeholder = markRaw({ render: () => null }); // 默认布局(2026-06-01 固化用户实拍布局,对应 WORKBENCH_LAYOUT_VERSION=5): // 左列(x=0 w=7):myTodo(y=0 h=25) → myWeekWorklog(y=25 h=22) // 右列(x=7 w=5):shortcut(y=0 h=11) → myProject(y=11 h=17) → myExecution(y=28 h=19) // 底部满宽(x=0 w=12):teamLoad(y=47 h=16) // hidden(x/y 为占位,show 时动态落到网格底部):projectHealth、productSnapshot const registry: WorkbenchModuleMeta[] = [ { key: 'myTodo', component: placeholder, displayName: '我的待办', icon: 'mdi:clipboard-text-clock-outline', category: 'personal', defaultVisible: true, // minH 24 ≈ 608px:保证至少完整展示 5 条待办(头部 124 + 5×71 列表 + 余量) defaultGrid: { x: 0, y: 0, w: 7, h: 25, minW: 5, minH: 24 } }, { key: 'myExecution', component: placeholder, displayName: '我负责的执行', icon: 'mdi:flag-checkered', category: 'personal', defaultVisible: true, defaultGrid: { x: 7, y: 28, w: 5, h: 19, minW: 4, minH: 15 } }, { key: 'shortcut', component: placeholder, displayName: '快捷入口', icon: 'mdi:rocket-launch-outline', category: 'tool', defaultVisible: true, defaultGrid: { x: 7, y: 0, w: 5, h: 11, minW: 3, minH: 10 } }, { key: 'myProject', component: placeholder, displayName: '我的项目', icon: 'mdi:briefcase-outline', category: 'personal', defaultVisible: true, defaultGrid: { x: 7, y: 11, w: 5, h: 17, minW: 5, minH: 17 } }, { key: 'myWeekWorklog', component: placeholder, displayName: '工时', icon: 'mdi:timer-outline', category: 'personal', defaultVisible: true, defaultGrid: { x: 0, y: 25, w: 7, h: 22, minW: 6, minH: 18 } }, { key: 'teamLoad', component: placeholder, displayName: '团队负载', icon: 'mdi:scale-balance', category: 'manager', defaultVisible: true, defaultGrid: { x: 0, y: 47, w: 12, h: 16, minW: 4, minH: 15 } }, // === 默认隐藏(用户可从 widget 库拖回) === { key: 'projectHealth', component: placeholder, displayName: '产品 / 项目健康度', icon: 'mdi:heart-pulse', category: 'manager', defaultVisible: false, defaultGrid: { x: 0, y: 0, w: 5, h: 12, minW: 4, minH: 9 } }, { key: 'productSnapshot', component: placeholder, displayName: '产品深度快照', icon: 'mdi:image-area-close', category: 'snapshot', defaultVisible: false, defaultGrid: { x: 0, y: 0, w: 6, h: 14, minW: 4, minH: 10 } } ]; const registryRef = shallowRef(registry); export function useWorkbenchModules() { function getAllModules() { return registryRef.value; } function getModuleMeta(key: WorkbenchModuleKey) { return registryRef.value.find(m => m.key === key); } function registerModuleComponent(key: WorkbenchModuleKey, component: Component) { const target = registryRef.value.find(m => m.key === key); if (target) target.component = markRaw(component); } return { getAllModules, getModuleMeta, registerModuleComponent }; }