This commit is contained in:
2025-10-23 12:14:03 +08:00
parent 900a72e4c9
commit f9fdb1a6c2
49 changed files with 851 additions and 8129 deletions

View File

@@ -0,0 +1,430 @@
import { v4 as uuidv4 } from 'uuid'
import type { IEventBuilder, IEventMap } from '@/events/IEventBuilder'
/** 窗口状态枚举 */
export enum EWindowFormState {
/** 创建中 */
CREATING = 'creating',
/** 加载中 */
LOADING = 'loading',
/** 激活 */
ACTIVE = 'active',
/** 未激活 - 在后台,失去焦点 */
INACTIVE = 'inactive',
/** 最小化 */
MINIMIZED = 'minimized',
/** 最大化状态 */
MAXIMIZED = 'maximized',
/** 关闭中 */
CLOSING = 'closing',
/** 销毁 */
DESTROYED = 'destroyed',
/** 错误 */
ERROR = 'error'
}
/** 窗口系统事件接口 */
export interface IWindowFormEvents extends IEventMap {
onWindowFormDataUpdate: (data: {
id: string
state: EWindowFormState
width: number
height: number
x: number
y: number
}) => void
/**
* 窗体创建事件
*/
onCreating: (wid: string) => void
/**
* 窗体加载事件
*/
onLoading: (wid: string) => void
/**
* 窗体加载完成事件
*/
onLoaded: (wid: string) => void
/**
* 窗体聚焦事件
*/
onFocus: (wid: string) => void
/**
* 窗体失焦事件
*/
onBlur: (wid: string) => void
/**
* 窗体激活事件
*/
onActivate: (wid: string) => void
/**
* 窗体失活事件
*/
onDeactivate: (wid: string) => void
/**
* 窗体最小化事件
*/
onMinimize: (wid: string) => void
/**
* 窗体最大化事件
*/
onMaximize: (wid: string) => void
/**
* 窗体还原、恢复事件
*/
onRestore: (wid: string) => void
/**
* 窗体关闭前事件
* @param id 窗体ID
* @param cancel
*/
onBeforeClose: (id: string, cancel: () => void) => void
/**
* 窗体关闭事件
*/
onClose: (wid: string) => void
/**
* 窗体销毁事件
*/
onDestroy: (wid: string) => void
/**
* 窗体错误事件
*/
onError: (wid: string, error: Error) => void
}
/** 窗口配置参数 */
export interface IWindowFormConfig {
/**
* 窗体标题
*/
title?: string
/**
* 窗体宽度(像素)
*/
width: number
/**
* 窗体高度(像素)
*/
height: number
/**
* 窗体最小宽度(像素)
*/
minWidth?: number
/**
* 窗体最小高度(像素)
*/
minHeight?: number
/**
* 窗体最大宽度(像素)
*/
maxWidth?: number
/**
* 窗体最大高度(像素)
*/
maxHeight?: number
/**
* 是否可调整大小
*/
resizable?: boolean
/**
* 是否可移动
*/
movable?: boolean
/**
* 是否可关闭
*/
closable?: boolean
/**
* 是否可最小化
*/
minimizable?: boolean
/**
* 是否可最大化
*/
maximizable?: boolean
/**
* 是否为模态窗体
*/
modal?: boolean
/**
* 是否始终置顶
*/
alwaysOnTop?: boolean
/**
* 窗体X坐标位置
*/
x?: number
/**
* 窗体Y坐标位置
*/
y?: number
}
/** 窗口参数 */
export interface IWindowFormData {
/**
* 窗体标题
*/
title: string
/**
* 窗体宽度(像素)
*/
width: number
/**
* 窗体高度(像素)
*/
height: number
/**
* 窗体最小宽度(像素)
*/
minWidth: number
/**
* 窗体最小高度(像素)
*/
minHeight: number
/**
* 窗体最大宽度(像素)
*/
maxWidth: number
/**
* 窗体最大高度(像素)
*/
maxHeight: number
/**
* 是否可调整大小
*/
resizable: boolean
/**
* 是否可移动
*/
movable: boolean
/**
* 是否可关闭
*/
closable: boolean
/**
* 是否可最小化
*/
minimizable: boolean
/**
* 是否可最大化
*/
maximizable: boolean
/**
* 是否为模态窗体
*/
modal: boolean
/**
* 是否始终置顶
*/
alwaysOnTop: boolean
/**
* 窗体X坐标位置
*/
x: number
/**
* 窗体Y坐标位置
*/
y: number
}
/** 窗口实例对象 */
export interface IWindowFormInstance {
/** 窗口ID */
id: string
/** 应用ID */
appId: string
/** 窗口参数 */
config: IWindowFormData
/** 窗口状态 */
state: EWindowFormState
/** 窗口ZIndex */
zIndex: number
/** 创建时间 - 时间戳 */
createdAt: number
/** 更新时间 - 时间戳 */
updatedAt: number
/** 窗口DOM元素 */
element?: HTMLElement
/** 窗口iframe元素 */
iframe?: HTMLIFrameElement
/** 记录事件解绑函数 */
subscriptions: (() => void)[]
}
/**
* WindowFormDataManager
* -------------------
* 窗口数据与状态的中心管理器。
* - 管理 Map<id, IWindowFormInstance>
* - 控制 ZIndex
* - 管理状态变更与事件通知
*/
export class WindowFormDataManager {
private windowForms = new Map<string, IWindowFormInstance>()
private activeWindowId: string | null = null
private nextZIndex = 1000
private wfEventBus: IEventBuilder<IWindowFormEvents>
constructor(wfEventBus: IEventBuilder<IWindowFormEvents>) {
this.wfEventBus = wfEventBus
}
/** 创建窗口实例数据对象不含DOM */
async createWindowForm(appId: string, config: IWindowFormConfig): Promise<IWindowFormInstance> {
const id = uuidv4()
const now = new Date().getTime()
const mergeConfig: IWindowFormData = {
title: config.title ?? '窗口',
width: config.width ?? 300,
height: config.height ?? 300,
minWidth: config.minWidth ?? 0,
minHeight: config.minHeight ?? 0,
maxWidth: config.maxWidth ?? window.innerWidth,
maxHeight: config.maxHeight ?? window.innerHeight,
resizable: config.resizable ?? true,
movable: config.movable ?? true,
closable: config.closable ?? true,
minimizable: config.minimizable ?? true,
maximizable: config.maximizable ?? true,
modal: config.modal ?? false,
alwaysOnTop: config.alwaysOnTop ?? false,
x: config.x ?? 0,
y: config.y ?? 0
}
const instance: IWindowFormInstance = {
id,
appId,
config: mergeConfig,
state: EWindowFormState.CREATING,
zIndex: this.nextZIndex++,
createdAt: now,
updatedAt: now,
subscriptions: []
}
this.windowForms.set(id, instance)
return instance
}
/** 获取窗口实例 */
getWindowForm(windowId: string): IWindowFormInstance | undefined {
return this.windowForms.get(windowId)
}
/** 删除窗口实例 */
removeWindowForm(windowId: string) {
this.windowForms.delete(windowId)
}
/** 更新窗口状态 */
updateState(windowId: string, newState: EWindowFormState, error?: Error) {
const win = this.windowForms.get(windowId)
if (!win) return
const old = win.state
if (old === newState) return
win.state = newState
this.wfEventBus.notify('onStateChange', windowId, newState, old)
this.notifyUpdate(win)
this.transition(win, newState, error)
}
/** 生命周期状态分发器 */
private transition(win: IWindowFormInstance, newState: EWindowFormState, error?: Error) {
const id = win.id
switch (newState) {
case EWindowFormState.CREATING:
this.wfEventBus.notify('onCreating', id)
break
case EWindowFormState.LOADING:
this.wfEventBus.notify('onLoading', id)
break
case EWindowFormState.ACTIVE:
this.wfEventBus.notify('onActivate', id)
break
case EWindowFormState.INACTIVE:
this.wfEventBus.notify('onDeactivate', id)
break
case EWindowFormState.MINIMIZED:
this.wfEventBus.notify('onMinimize', id)
break
case EWindowFormState.MAXIMIZED:
this.wfEventBus.notify('onMaximize', id)
break
case EWindowFormState.CLOSING:
this.wfEventBus.notify('onClose', id)
break
case EWindowFormState.DESTROYED:
this.wfEventBus.notify('onDestroy', id)
break
case EWindowFormState.ERROR:
this.wfEventBus.notify('onError', id, error ?? new Error('未知错误'))
break
}
}
/** 聚焦窗口 */
focus(windowId: string) {
const win = this.windowForms.get(windowId)
if (!win) return
this.activeWindowId = windowId
win.zIndex = this.nextZIndex++
if (win.element) win.element.style.zIndex = `${win.zIndex}`
this.wfEventBus.notify('onFocus', windowId)
this.notifyUpdate(win)
}
/** 最小化窗口 */
minimize(windowId: string) {
const win = this.windowForms.get(windowId)
if (!win || !win.element) return
win.element.style.display = 'none'
this.updateState(windowId, EWindowFormState.MINIMIZED)
}
/** 最大化窗口 */
maximize(windowId: string) {
const win = this.windowForms.get(windowId)
if (!win || !win.element) return
win.element.dataset.originalWidth = win.element.style.width
win.element.dataset.originalHeight = win.element.style.height
win.element.style.position = 'fixed'
Object.assign(win.element.style, {
top: '0',
left: '0',
width: '100vw',
height: '100vh'
})
this.updateState(windowId, EWindowFormState.MAXIMIZED)
}
/** 还原窗口 */
restore(windowId: string) {
const win = this.windowForms.get(windowId)
if (!win || !win.element) return
Object.assign(win.element.style, {
position: 'absolute',
width: win.element.dataset.originalWidth,
height: win.element.dataset.originalHeight
})
this.updateState(windowId, EWindowFormState.ACTIVE)
}
/** 通知窗口数据更新 */
private notifyUpdate(win: IWindowFormInstance) {
const rect = win.element?.getBoundingClientRect()
if (!rect) return
this.wfEventBus.notify('onWindowFormDataUpdate', {
id: win.id,
state: win.state,
width: rect.width,
height: rect.height,
x: rect.left,
y: rect.top
})
}
}