ERP-node/frontend/lib/v2-core/adapters/LegacyEventAdapter.ts

444 lines
12 KiB
TypeScript
Raw Normal View History

/**
* CustomEvent V2 EventBus
*
* window.dispatchEvent/addEventListener
* V2 EventBus로 릿 .
*
* :
* - 릿 ( V2, V2 )
* -
* - 릿 /
*/
import { v2EventBus, V2_EVENTS, V2EventName, V2EventPayloadMap } from "../events";
// ============================================================================
// 이벤트 매핑 정의
// ============================================================================
interface EventMapping {
legacy: string;
v2: V2EventName;
/** 레거시 → V2 페이로드 변환 함수 */
toV2?: (legacyDetail: any) => any;
/** V2 → 레거시 페이로드 변환 함수 */
toLegacy?: (v2Payload: any) => any;
}
const EVENT_MAPPINGS: EventMapping[] = [
// 테이블 관련
{
legacy: "refreshTable",
v2: V2_EVENTS.TABLE_REFRESH,
toV2: (detail) => ({
tableName: detail?.tableName,
target: detail?.target ?? "all",
screenCode: detail?.screenCode,
}),
toLegacy: (payload) => ({
tableName: payload.tableName,
target: payload.target,
screenCode: payload.screenCode,
}),
},
{
legacy: "tableListDataChange",
v2: V2_EVENTS.TABLE_DATA_CHANGE,
toV2: (detail) => ({
tableName: detail?.tableName,
data: detail?.data ?? [],
totalCount: detail?.totalCount ?? 0,
source: detail?.source ?? "legacy",
}),
toLegacy: (payload) => ({
tableName: payload.tableName,
data: payload.data,
totalCount: payload.totalCount,
source: payload.source,
}),
},
{
legacy: "tableSelectionChange",
v2: V2_EVENTS.TABLE_SELECTION_CHANGE,
toV2: (detail) => ({
tableName: detail?.tableName,
selectedRows: detail?.selectedRows ?? [],
selectedRowIds: detail?.selectedRowIds ?? [],
source: detail?.source ?? "legacy",
}),
toLegacy: (payload) => ({
tableName: payload.tableName,
selectedRows: payload.selectedRows,
selectedRowIds: payload.selectedRowIds,
source: payload.source,
}),
},
{
legacy: "selectionChange",
v2: V2_EVENTS.TABLE_SELECTION_CHANGE,
toV2: (detail) => ({
tableName: detail?.tableName ?? "",
selectedRows: detail?.selectedRows ?? [],
selectedRowIds: detail?.selectedRowIds ?? [],
source: "legacy-selectionChange",
}),
toLegacy: (payload) => ({
tableName: payload.tableName,
selectedRows: payload.selectedRows,
selectedRowIds: payload.selectedRowIds,
source: payload.source,
}),
},
// 폼 저장 관련
{
legacy: "beforeFormSave",
v2: V2_EVENTS.FORM_SAVE_COLLECT,
toV2: (detail) => ({
requestId: detail?.requestId ?? `req_${Date.now()}`,
formData: detail?.formData ?? {},
componentId: detail?.componentId ?? "legacy",
}),
toLegacy: (payload) => ({
requestId: payload.requestId,
formData: payload.formData,
componentId: payload.componentId,
}),
},
{
legacy: "saveSuccess",
v2: V2_EVENTS.FORM_SAVE_COMPLETE,
toV2: (detail) => ({
requestId: detail?.requestId ?? "",
success: true,
savedData: detail?.savedData ?? detail,
tableName: detail?.tableName ?? "",
}),
toLegacy: (payload) => ({
requestId: payload.requestId,
savedData: payload.savedData,
tableName: payload.tableName,
}),
},
// 리피터 관련
{
legacy: "repeaterSave",
v2: V2_EVENTS.REPEATER_SAVE,
toV2: (detail) => ({
repeaterId: detail?.repeaterId ?? "",
tableName: detail?.tableName ?? "",
items: detail?.items ?? [],
joinData: detail?.joinData,
}),
toLegacy: (payload) => ({
repeaterId: payload.repeaterId,
tableName: payload.tableName,
items: payload.items,
joinData: payload.joinData,
}),
},
{
legacy: "repeaterDataChange",
v2: V2_EVENTS.REPEATER_DATA_CHANGE,
toV2: (detail) => ({
repeaterId: detail?.repeaterId ?? "",
tableName: detail?.tableName ?? "",
data: detail?.data ?? [],
action: detail?.action ?? "update",
}),
toLegacy: (payload) => ({
repeaterId: payload.repeaterId,
tableName: payload.tableName,
data: payload.data,
action: payload.action,
}),
},
// 모달 관련
{
legacy: "closeEditModal",
v2: V2_EVENTS.MODAL_CLOSE,
toV2: (detail) => ({
modalId: detail?.modalId ?? "edit-modal",
reason: detail?.reason ?? "close",
}),
toLegacy: (payload) => ({
modalId: payload.modalId,
reason: payload.reason,
}),
},
{
legacy: "saveSuccessInModal",
v2: V2_EVENTS.MODAL_SAVE_SUCCESS,
toV2: (detail) => ({
modalId: detail?.modalId ?? "edit-modal",
savedData: detail?.savedData ?? {},
tableName: detail?.tableName ?? "",
}),
toLegacy: (payload) => ({
modalId: payload.modalId,
savedData: payload.savedData,
tableName: payload.tableName,
}),
},
{
legacy: "openScreenModal",
v2: V2_EVENTS.MODAL_OPEN,
toV2: (detail) => ({
modalId: detail?.modalId ?? "",
screenCode: detail?.screenCode,
data: detail?.data,
mode: detail?.mode ?? "view",
}),
toLegacy: (payload) => ({
modalId: payload.modalId,
screenCode: payload.screenCode,
data: payload.data,
mode: payload.mode,
}),
},
// 카드 디스플레이
{
legacy: "refreshCardDisplay",
v2: V2_EVENTS.CARD_REFRESH,
toV2: (detail) => ({
cardId: detail?.cardId,
tableName: detail?.tableName,
}),
toLegacy: (payload) => ({
cardId: payload.cardId,
tableName: payload.tableName,
}),
},
// 분할 패널
{
legacy: "splitPanelDataTransfer",
v2: V2_EVENTS.SPLIT_PANEL_DATA_TRANSFER,
toV2: (detail) => ({
sourcePanel: detail?.sourcePanel ?? "left",
targetPanel: detail?.targetPanel ?? "right",
data: detail?.data ?? {},
tableName: detail?.tableName ?? "",
}),
toLegacy: (payload) => ({
sourcePanel: payload.sourcePanel,
targetPanel: payload.targetPanel,
data: payload.data,
tableName: payload.tableName,
}),
},
// 컴포넌트 데이터 전송
{
legacy: "componentDataTransfer",
v2: V2_EVENTS.COMPONENT_DATA_TRANSFER,
toV2: (detail) => ({
sourceComponentId: detail?.sourceComponentId ?? "",
targetComponentId: detail?.targetComponentId,
data: detail?.data ?? {},
tableName: detail?.tableName,
}),
toLegacy: (payload) => ({
sourceComponentId: payload.sourceComponentId,
targetComponentId: payload.targetComponentId,
data: payload.data,
tableName: payload.tableName,
}),
},
// 관련 버튼
{
legacy: "related-button-register",
v2: V2_EVENTS.RELATED_BUTTON_REGISTER,
toV2: (detail) => ({
buttonId: detail?.buttonId ?? "",
targetTables: detail?.targetTables ?? [],
}),
toLegacy: (payload) => ({
buttonId: payload.buttonId,
targetTables: payload.targetTables,
}),
},
{
legacy: "related-button-unregister",
v2: V2_EVENTS.RELATED_BUTTON_UNREGISTER,
toV2: (detail) => ({
buttonId: detail?.buttonId ?? "",
}),
toLegacy: (payload) => ({
buttonId: payload.buttonId,
}),
},
{
legacy: "related-button-select",
v2: V2_EVENTS.RELATED_BUTTON_SELECT,
toV2: (detail) => ({
tableName: detail?.tableName ?? "",
selectedData: detail?.selectedData ?? [],
}),
toLegacy: (payload) => ({
tableName: payload.tableName,
selectedData: payload.selectedData,
}),
},
];
// ============================================================================
// 어댑터 클래스
// ============================================================================
class LegacyEventAdapter {
private isActive = false;
private legacyListeners: Map<string, (e: Event) => void> = new Map();
private v2Unsubscribes: Map<string, () => void> = new Map();
/** 브릿지에서 발생한 이벤트 추적 (무한 루프 방지) */
private bridgedEvents: Set<string> = new Set();
/** 브릿지 방향 설정 */
private config = {
legacyToV2: true,
v2ToLegacy: true,
};
/**
* 릿
*
* @param options - 릿
*/
init(options?: { legacyToV2?: boolean; v2ToLegacy?: boolean }): void {
if (this.isActive) {
console.warn("[LegacyEventAdapter] 이미 초기화되어 있습니다.");
return;
}
if (options) {
this.config = { ...this.config, ...options };
}
console.log("[LegacyEventAdapter] 초기화 시작", this.config);
EVENT_MAPPINGS.forEach((mapping) => {
// 레거시 → V2 브릿지
if (this.config.legacyToV2) {
this.setupLegacyToV2Bridge(mapping);
}
// V2 → 레거시 브릿지
if (this.config.v2ToLegacy) {
this.setupV2ToLegacyBridge(mapping);
}
});
this.isActive = true;
console.log(
`[LegacyEventAdapter] 초기화 완료 (${EVENT_MAPPINGS.length}개 매핑)`
);
}
private setupLegacyToV2Bridge(mapping: EventMapping): void {
const listener = (event: Event) => {
const customEvent = event as CustomEvent;
const bridgeKey = `${mapping.legacy}-${Date.now()}`;
// 무한 루프 방지: 브릿지에서 발생한 이벤트인지 확인
if (customEvent.detail?.__v2Bridged) {
return;
}
this.bridgedEvents.add(bridgeKey);
// 페이로드 변환
const v2Payload = mapping.toV2
? mapping.toV2(customEvent.detail)
: customEvent.detail;
// V2 EventBus로 발행
v2EventBus.emitSync(mapping.v2, v2Payload);
// 잠시 후 브릿지 키 정리
setTimeout(() => {
this.bridgedEvents.delete(bridgeKey);
}, 100);
};
window.addEventListener(mapping.legacy, listener);
this.legacyListeners.set(mapping.legacy, listener);
}
private setupV2ToLegacyBridge(mapping: EventMapping): void {
const unsubscribe = v2EventBus.subscribe(
mapping.v2,
(payload) => {
// 무한 루프 방지 표시 추가
const legacyPayload = mapping.toLegacy
? { ...mapping.toLegacy(payload), __v2Bridged: true }
: { ...payload, __v2Bridged: true };
// 레거시 이벤트 발행
window.dispatchEvent(
new CustomEvent(mapping.legacy, { detail: legacyPayload })
);
},
{ componentId: "legacy-adapter" }
);
this.v2Unsubscribes.set(mapping.v2, unsubscribe);
}
/**
*
*/
destroy(): void {
if (!this.isActive) {
return;
}
// 레거시 리스너 정리
this.legacyListeners.forEach((listener, eventName) => {
window.removeEventListener(eventName, listener);
});
this.legacyListeners.clear();
// V2 구독 정리
this.v2Unsubscribes.forEach((unsubscribe) => {
unsubscribe();
});
this.v2Unsubscribes.clear();
this.bridgedEvents.clear();
this.isActive = false;
console.log("[LegacyEventAdapter] 정리 완료");
}
/**
*
*/
get active(): boolean {
return this.isActive;
}
/**
*
*/
getMappings(): Array<{ legacy: string; v2: string }> {
return EVENT_MAPPINGS.map((m) => ({
legacy: m.legacy,
v2: m.v2,
}));
}
}
// 싱글톤 인스턴스
export const legacyEventAdapter = new LegacyEventAdapter();
// 개발 환경에서 window에 노출 (디버깅용)
if (typeof window !== "undefined" && process.env.NODE_ENV === "development") {
(window as any).__legacyEventAdapter = legacyEventAdapter;
}