保存
This commit is contained in:
430
src/services/windowForm/WindowFormDataManager.ts
Normal file
430
src/services/windowForm/WindowFormDataManager.ts
Normal 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
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user