Files
cn-rdms-web/src/views/workbench/composables/use-workbench-modules.ts

129 lines
4.6 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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=7myTodo(y=0 h=25) → myWeekWorklog(y=25 h=22)
// 右列x=7 w=5shortcut(y=0 h=11) → myProject(y=11 h=17) → myExecution(y=28 h=19)
// 底部满宽x=0 w=12teamLoad(y=47 h=16)
// hiddenx/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 };
}