129 lines
4.6 KiB
TypeScript
129 lines
4.6 KiB
TypeScript
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 };
|
||
}
|