POP 레이아웃 v3.0 아키텍처로 전환 - Section 요소 완전 제거

디자이너/뷰어 렌더링 통일 - react-grid-layout 제거, CSS Grid 1fr 단위 사용
반응형 모드 자동 전환 - useResponsiveMode 훅 추가
디자이너 UI 개선 - 컴포넌트 헤더/삭제 아이콘 제거, 전체 영역 드래그
This commit is contained in:
SeongHyun Kim
2026-02-03 19:11:03 +09:00
parent 368d641ae8
commit de2163bcef
17 changed files with 2991 additions and 2194 deletions

View File

@@ -4894,7 +4894,8 @@ export class ScreenManagementService {
/**
* POP 레이아웃 저장
* - screen_layouts_pop 테이블에 화면당 1개 레코드 저장
* - v2 형식으로 저장 (version: "pop-2.0")
* - v3 형식 지원 (version: "pop-3.0", 섹션 제거)
* - v2/v1 하위 호환
*/
async saveLayoutPop(
screenId: number,
@@ -4905,11 +4906,16 @@ export class ScreenManagementService {
console.log(`=== POP 레이아웃 저장 시작 ===`);
console.log(`화면 ID: ${screenId}, 회사: ${companyCode}`);
// v2 구조 확인
// 버전 감지
const isV3 = layoutData.version === "pop-3.0" ||
(layoutData.layouts && layoutData.components && !layoutData.sections);
const isV2 = layoutData.version === "pop-2.0" ||
(layoutData.layouts && layoutData.sections && layoutData.components);
if (isV2) {
if (isV3) {
const componentCount = Object.keys(layoutData.components || {}).length;
console.log(`v3 레이아웃: ${componentCount}개 컴포넌트 (섹션 없음)`);
} else if (isV2) {
const sectionCount = Object.keys(layoutData.sections || {}).length;
const componentCount = Object.keys(layoutData.components || {}).length;
console.log(`v2 레이아웃: ${sectionCount}개 섹션, ${componentCount}개 컴포넌트`);
@@ -4933,13 +4939,50 @@ export class ScreenManagementService {
throw new Error("이 화면의 POP 레이아웃을 저장할 권한이 없습니다.");
}
// 버전 정보 보장 (v2 우선, v1은 프론트엔드에서 마이그레이션 후 저장 권장)
// SUPER_ADMIN인 경우: 화면 정의의 company_code로 저장 (로드와 동일하게)
const targetCompanyCode = companyCode === "*"
? (existingScreen.company_code || "*")
: companyCode;
console.log(`저장 대상 company_code: ${targetCompanyCode} (사용자: ${companyCode}, 화면: ${existingScreen.company_code})`);
// 버전 정보 보장
let dataToSave: any;
if (isV2) {
if (isV3) {
dataToSave = {
...layoutData,
version: "pop-3.0",
};
// canvasGrid.rows 검증 및 보정
if (dataToSave.settings?.canvasGrid) {
if (!dataToSave.settings.canvasGrid.rows) {
console.warn("canvasGrid.rows 없음, 기본값 24로 설정");
dataToSave.settings.canvasGrid.rows = 24;
}
// 구버전 rowHeight 필드 제거
if (dataToSave.settings.canvasGrid.rowHeight) {
console.warn("구버전 rowHeight 필드 제거");
delete dataToSave.settings.canvasGrid.rowHeight;
}
}
} else if (isV2) {
dataToSave = {
...layoutData,
version: "pop-2.0",
};
// canvasGrid.rows 검증 및 보정
if (dataToSave.settings?.canvasGrid) {
if (!dataToSave.settings.canvasGrid.rows) {
console.warn("canvasGrid.rows 없음, 기본값 24로 설정");
dataToSave.settings.canvasGrid.rows = 24;
}
if (dataToSave.settings.canvasGrid.rowHeight) {
console.warn("구버전 rowHeight 필드 제거");
delete dataToSave.settings.canvasGrid.rowHeight;
}
}
} else {
// v1 형식으로 저장 (하위 호환)
dataToSave = {
@@ -4954,10 +4997,10 @@ export class ScreenManagementService {
VALUES ($1, $2, $3, NOW(), NOW(), $4, $4)
ON CONFLICT (screen_id, company_code)
DO UPDATE SET layout_data = $3, updated_at = NOW(), updated_by = $4`,
[screenId, companyCode, JSON.stringify(dataToSave), userId || null],
[screenId, targetCompanyCode, JSON.stringify(dataToSave), userId || null],
);
console.log(`POP 레이아웃 저장 완료 (version: ${dataToSave.version})`);
console.log(`POP 레이아웃 저장 완료 (version: ${dataToSave.version}, company: ${targetCompanyCode})`);
}
/**