fix: 멀티 레이어 화면 복제 버그 수정
- menuCopyService: 모든 레이어 순회 처리, ON CONFLICT 제약조건 수정 - screenManagementService: layer_id 하드코딩 제거, 멀티 레이어 순회 - screen_conditional_zones 복제 로직 추가 (zoneIdMap 생성) - condition_config의 zone_id 재매핑 로직 추가 - 레이어 수 변경 감지를 위한 변경 비교 로직 보강 Made-with: Cursor
This commit is contained in:
parent
e11a7b1237
commit
8d0f2dbb27
|
|
@ -1535,20 +1535,21 @@ export class MenuCopyService {
|
||||||
// === 기존 복사본이 있는 경우: 업데이트 ===
|
// === 기존 복사본이 있는 경우: 업데이트 ===
|
||||||
const existingScreenId = existingCopy.screen_id;
|
const existingScreenId = existingCopy.screen_id;
|
||||||
|
|
||||||
// 원본 V2 레이아웃 조회
|
// 원본 V2 레이아웃 조회 (모든 레이어)
|
||||||
const sourceLayoutV2Result = await client.query<{ layout_data: any }>(
|
const sourceLayoutV2Result = await client.query<{ layout_data: any }>(
|
||||||
`SELECT layout_data FROM screen_layouts_v2 WHERE screen_id = $1`,
|
`SELECT layout_data FROM screen_layouts_v2 WHERE screen_id = $1 ORDER BY layer_id`,
|
||||||
[originalScreenId]
|
[originalScreenId]
|
||||||
);
|
);
|
||||||
|
|
||||||
// 대상 V2 레이아웃 조회
|
// 대상 V2 레이아웃 조회 (모든 레이어)
|
||||||
const targetLayoutV2Result = await client.query<{ layout_data: any }>(
|
const targetLayoutV2Result = await client.query<{ layout_data: any }>(
|
||||||
`SELECT layout_data FROM screen_layouts_v2 WHERE screen_id = $1`,
|
`SELECT layout_data FROM screen_layouts_v2 WHERE screen_id = $1 ORDER BY layer_id`,
|
||||||
[existingScreenId]
|
[existingScreenId]
|
||||||
);
|
);
|
||||||
|
|
||||||
// 변경 여부 확인 (V2 레이아웃 비교)
|
// 변경 여부 확인: 레이어 수가 다르면 무조건 변경됨
|
||||||
const hasChanges = this.hasLayoutChangesV2(
|
const layerCountDiffers = sourceLayoutV2Result.rows.length !== targetLayoutV2Result.rows.length;
|
||||||
|
const hasChanges = layerCountDiffers || this.hasLayoutChangesV2(
|
||||||
sourceLayoutV2Result.rows[0]?.layout_data,
|
sourceLayoutV2Result.rows[0]?.layout_data,
|
||||||
targetLayoutV2Result.rows[0]?.layout_data
|
targetLayoutV2Result.rows[0]?.layout_data
|
||||||
);
|
);
|
||||||
|
|
@ -1652,7 +1653,7 @@ export class MenuCopyService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// === 2단계: screen_layouts_v2 처리 (이제 screenIdMap이 완성됨) ===
|
// === 2단계: screen_conditional_zones + screen_layouts_v2 처리 (멀티 레이어 지원) ===
|
||||||
logger.info(
|
logger.info(
|
||||||
`\n📐 V2 레이아웃 처리 시작 (screenIdMap 완성: ${screenIdMap.size}개)`
|
`\n📐 V2 레이아웃 처리 시작 (screenIdMap 완성: ${screenIdMap.size}개)`
|
||||||
);
|
);
|
||||||
|
|
@ -1664,23 +1665,90 @@ export class MenuCopyService {
|
||||||
isUpdate,
|
isUpdate,
|
||||||
} of screenDefsToProcess) {
|
} of screenDefsToProcess) {
|
||||||
try {
|
try {
|
||||||
// 원본 V2 레이아웃 조회
|
const sourceCompanyCode = screenDef.company_code;
|
||||||
const layoutV2Result = await client.query<{ layout_data: any }>(
|
|
||||||
`SELECT layout_data FROM screen_layouts_v2 WHERE screen_id = $1`,
|
// 원본 V2 레이아웃 전체 조회 (모든 레이어)
|
||||||
|
const layoutV2Result = await client.query<{
|
||||||
|
layout_data: any;
|
||||||
|
layer_id: number;
|
||||||
|
layer_name: string;
|
||||||
|
condition_config: any;
|
||||||
|
}>(
|
||||||
|
`SELECT layout_data, layer_id, layer_name, condition_config
|
||||||
|
FROM screen_layouts_v2
|
||||||
|
WHERE screen_id = $1 AND company_code = $2
|
||||||
|
ORDER BY layer_id`,
|
||||||
|
[originalScreenId, sourceCompanyCode]
|
||||||
|
);
|
||||||
|
|
||||||
|
if (layoutV2Result.rows.length === 0) {
|
||||||
|
logger.info(` ↳ V2 레이아웃 없음 (스킵): screen_id=${originalScreenId}`);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 모든 레이어에서 컴포넌트를 수집하여 componentIdMap 생성
|
||||||
|
const componentIdMap = new Map<string, string>();
|
||||||
|
const timestamp = Date.now();
|
||||||
|
let compIdx = 0;
|
||||||
|
for (const layer of layoutV2Result.rows) {
|
||||||
|
const components = layer.layout_data?.components || [];
|
||||||
|
for (const comp of components) {
|
||||||
|
if (!componentIdMap.has(comp.id)) {
|
||||||
|
const newId = `comp_${timestamp}_${compIdx++}_${Math.random().toString(36).substr(2, 5)}`;
|
||||||
|
componentIdMap.set(comp.id, newId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// screen_conditional_zones 복제 + zoneIdMap 생성
|
||||||
|
const zoneIdMap = new Map<number, number>();
|
||||||
|
const zonesResult = await client.query(
|
||||||
|
`SELECT * FROM screen_conditional_zones WHERE screen_id = $1`,
|
||||||
[originalScreenId]
|
[originalScreenId]
|
||||||
);
|
);
|
||||||
|
|
||||||
const layoutData = layoutV2Result.rows[0]?.layout_data;
|
if (isUpdate) {
|
||||||
|
await client.query(
|
||||||
|
`DELETE FROM screen_conditional_zones WHERE screen_id = $1 AND company_code = $2`,
|
||||||
|
[targetScreenId, targetCompanyCode]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const zone of zonesResult.rows) {
|
||||||
|
const newTriggerCompId = componentIdMap.get(zone.trigger_component_id) || zone.trigger_component_id;
|
||||||
|
const newZone = await client.query<{ zone_id: number }>(
|
||||||
|
`INSERT INTO screen_conditional_zones
|
||||||
|
(screen_id, company_code, zone_name, x, y, width, height,
|
||||||
|
trigger_component_id, trigger_operator)
|
||||||
|
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)
|
||||||
|
RETURNING zone_id`,
|
||||||
|
[targetScreenId, targetCompanyCode, zone.zone_name,
|
||||||
|
zone.x, zone.y, zone.width, zone.height,
|
||||||
|
newTriggerCompId, zone.trigger_operator]
|
||||||
|
);
|
||||||
|
zoneIdMap.set(zone.zone_id, newZone.rows[0].zone_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (zonesResult.rows.length > 0) {
|
||||||
|
logger.info(` ↳ 조건부 영역 복사: ${zonesResult.rows.length}개 (zoneIdMap: ${zoneIdMap.size}개)`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 업데이트인 경우 기존 레이아웃 삭제 (레이어 수 변경 대응)
|
||||||
|
if (isUpdate) {
|
||||||
|
await client.query(
|
||||||
|
`DELETE FROM screen_layouts_v2 WHERE screen_id = $1 AND company_code = $2`,
|
||||||
|
[targetScreenId, targetCompanyCode]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 각 레이어별 처리
|
||||||
|
let totalComponents = 0;
|
||||||
|
for (const layer of layoutV2Result.rows) {
|
||||||
|
const layoutData = layer.layout_data;
|
||||||
const components = layoutData?.components || [];
|
const components = layoutData?.components || [];
|
||||||
|
|
||||||
if (layoutData && components.length > 0) {
|
if (!layoutData || components.length === 0) continue;
|
||||||
// component_id 매핑 생성 (원본 → 새 ID)
|
totalComponents += components.length;
|
||||||
const componentIdMap = new Map<string, string>();
|
|
||||||
const timestamp = Date.now();
|
|
||||||
components.forEach((comp: any, idx: number) => {
|
|
||||||
const newComponentId = `comp_${timestamp}_${idx}_${Math.random().toString(36).substr(2, 5)}`;
|
|
||||||
componentIdMap.set(comp.id, newComponentId);
|
|
||||||
});
|
|
||||||
|
|
||||||
// V2 레이아웃 데이터 복사 및 참조 업데이트
|
// V2 레이아웃 데이터 복사 및 참조 업데이트
|
||||||
const updatedLayoutData = this.updateReferencesInLayoutDataV2(
|
const updatedLayoutData = this.updateReferencesInLayoutDataV2(
|
||||||
|
|
@ -1692,20 +1760,34 @@ export class MenuCopyService {
|
||||||
menuIdMap
|
menuIdMap
|
||||||
);
|
);
|
||||||
|
|
||||||
// V2 레이아웃 저장 (UPSERT)
|
// condition_config의 zone_id 재매핑
|
||||||
|
let updatedConditionConfig = layer.condition_config ? { ...layer.condition_config } : null;
|
||||||
|
if (updatedConditionConfig?.zone_id) {
|
||||||
|
const newZoneId = zoneIdMap.get(updatedConditionConfig.zone_id);
|
||||||
|
if (newZoneId) {
|
||||||
|
updatedConditionConfig.zone_id = newZoneId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// V2 레이아웃 저장 (레이어별 INSERT)
|
||||||
await client.query(
|
await client.query(
|
||||||
`INSERT INTO screen_layouts_v2 (screen_id, company_code, layout_data, created_at, updated_at)
|
`INSERT INTO screen_layouts_v2 (screen_id, company_code, layer_id, layer_name, layout_data, condition_config, created_at, updated_at)
|
||||||
VALUES ($1, $2, $3, NOW(), NOW())
|
VALUES ($1, $2, $3, $4, $5, $6, NOW(), NOW())
|
||||||
ON CONFLICT (screen_id, company_code)
|
ON CONFLICT (screen_id, company_code, layer_id)
|
||||||
DO UPDATE SET layout_data = $3, updated_at = NOW()`,
|
DO UPDATE SET layout_data = $5, layer_name = $4, condition_config = $6, updated_at = NOW()`,
|
||||||
[targetScreenId, targetCompanyCode, JSON.stringify(updatedLayoutData)]
|
[
|
||||||
|
targetScreenId,
|
||||||
|
targetCompanyCode,
|
||||||
|
layer.layer_id,
|
||||||
|
layer.layer_name,
|
||||||
|
JSON.stringify(updatedLayoutData),
|
||||||
|
updatedConditionConfig ? JSON.stringify(updatedConditionConfig) : null,
|
||||||
|
]
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const action = isUpdate ? "업데이트" : "복사";
|
const action = isUpdate ? "업데이트" : "복사";
|
||||||
logger.info(` ↳ V2 레이아웃 ${action}: ${components.length}개 컴포넌트`);
|
logger.info(` ↳ V2 레이아웃 ${action}: ${layoutV2Result.rows.length}개 레이어, ${totalComponents}개 컴포넌트`);
|
||||||
} else {
|
|
||||||
logger.info(` ↳ V2 레이아웃 없음 (스킵): screen_id=${originalScreenId}`);
|
|
||||||
}
|
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
logger.error(
|
logger.error(
|
||||||
`❌ V2 레이아웃 처리 실패: screen_id=${originalScreenId}`,
|
`❌ V2 레이아웃 처리 실패: screen_id=${originalScreenId}`,
|
||||||
|
|
|
||||||
|
|
@ -4210,39 +4210,65 @@ export class ScreenManagementService {
|
||||||
|
|
||||||
const newScreen = newScreenResult.rows[0];
|
const newScreen = newScreenResult.rows[0];
|
||||||
|
|
||||||
// 4. 원본 화면의 V2 레이아웃 조회
|
// 4. 원본 화면의 V2 레이아웃 전체 조회 (모든 레이어)
|
||||||
let sourceLayoutV2Result = await client.query<{ layout_data: any }>(
|
let sourceLayoutV2Result = await client.query<{
|
||||||
`SELECT layout_data FROM screen_layouts_v2
|
layout_data: any;
|
||||||
WHERE screen_id = $1 AND company_code = $2`,
|
layer_id: number;
|
||||||
|
layer_name: string;
|
||||||
|
condition_config: any;
|
||||||
|
}>(
|
||||||
|
`SELECT layout_data, layer_id, layer_name, condition_config
|
||||||
|
FROM screen_layouts_v2
|
||||||
|
WHERE screen_id = $1 AND company_code = $2
|
||||||
|
ORDER BY layer_id`,
|
||||||
[sourceScreenId, sourceScreen.company_code],
|
[sourceScreenId, sourceScreen.company_code],
|
||||||
);
|
);
|
||||||
|
|
||||||
// 없으면 공통(*) 레이아웃 조회
|
// 없으면 공통(*) 레이아웃 조회
|
||||||
let layoutData = sourceLayoutV2Result.rows[0]?.layout_data;
|
if (sourceLayoutV2Result.rows.length === 0 && sourceScreen.company_code !== "*") {
|
||||||
if (!layoutData && sourceScreen.company_code !== "*") {
|
sourceLayoutV2Result = await client.query<{
|
||||||
const fallbackResult = await client.query<{ layout_data: any }>(
|
layout_data: any;
|
||||||
`SELECT layout_data FROM screen_layouts_v2
|
layer_id: number;
|
||||||
WHERE screen_id = $1 AND company_code = '*'`,
|
layer_name: string;
|
||||||
|
condition_config: any;
|
||||||
|
}>(
|
||||||
|
`SELECT layout_data, layer_id, layer_name, condition_config
|
||||||
|
FROM screen_layouts_v2
|
||||||
|
WHERE screen_id = $1 AND company_code = '*'
|
||||||
|
ORDER BY layer_id`,
|
||||||
[sourceScreenId],
|
[sourceScreenId],
|
||||||
);
|
);
|
||||||
layoutData = fallbackResult.rows[0]?.layout_data;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const components = layoutData?.components || [];
|
// 모든 레이어에서 컴포넌트를 수집하여 componentIdMap 생성
|
||||||
|
const componentIdMap = new Map<string, string>();
|
||||||
|
for (const layer of sourceLayoutV2Result.rows) {
|
||||||
|
const components = layer.layout_data?.components || [];
|
||||||
|
for (const comp of components) {
|
||||||
|
if (!componentIdMap.has(comp.id)) {
|
||||||
|
componentIdMap.set(comp.id, generateId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const hasComponents = componentIdMap.size > 0;
|
||||||
|
// 첫 번째 레이어의 layoutData (flowId/ruleId 수집용 - 모든 레이어에서 수집)
|
||||||
|
const allLayoutDatas = sourceLayoutV2Result.rows.map((r: any) => r.layout_data).filter(Boolean);
|
||||||
|
|
||||||
// 5. 노드 플로우 복사 (회사가 다른 경우)
|
// 5. 노드 플로우 복사 (회사가 다른 경우)
|
||||||
let flowIdMap = new Map<number, number>();
|
let flowIdMap = new Map<number, number>();
|
||||||
if (
|
if (
|
||||||
components.length > 0 &&
|
hasComponents &&
|
||||||
sourceScreen.company_code !== targetCompanyCode
|
sourceScreen.company_code !== targetCompanyCode
|
||||||
) {
|
) {
|
||||||
// V2 레이아웃에서 flowId 수집
|
const flowIds = new Set<number>();
|
||||||
const flowIds = this.collectFlowIdsFromLayoutData(layoutData);
|
for (const ld of allLayoutDatas) {
|
||||||
|
const ids = this.collectFlowIdsFromLayoutData(ld);
|
||||||
|
ids.forEach((id: number) => flowIds.add(id));
|
||||||
|
}
|
||||||
|
|
||||||
if (flowIds.size > 0) {
|
if (flowIds.size > 0) {
|
||||||
console.log(`🔍 화면 복사 - flowId 수집: ${flowIds.size}개`);
|
console.log(`🔍 화면 복사 - flowId 수집: ${flowIds.size}개`);
|
||||||
|
|
||||||
// 노드 플로우 복사 및 매핑 생성
|
|
||||||
flowIdMap = await this.copyNodeFlowsForScreen(
|
flowIdMap = await this.copyNodeFlowsForScreen(
|
||||||
flowIds,
|
flowIds,
|
||||||
sourceScreen.company_code,
|
sourceScreen.company_code,
|
||||||
|
|
@ -4255,16 +4281,17 @@ export class ScreenManagementService {
|
||||||
// 5.1. 채번 규칙 복사 (회사가 다른 경우)
|
// 5.1. 채번 규칙 복사 (회사가 다른 경우)
|
||||||
let ruleIdMap = new Map<string, string>();
|
let ruleIdMap = new Map<string, string>();
|
||||||
if (
|
if (
|
||||||
components.length > 0 &&
|
hasComponents &&
|
||||||
sourceScreen.company_code !== targetCompanyCode
|
sourceScreen.company_code !== targetCompanyCode
|
||||||
) {
|
) {
|
||||||
// V2 레이아웃에서 채번 규칙 ID 수집
|
const ruleIds = new Set<string>();
|
||||||
const ruleIds = this.collectNumberingRuleIdsFromLayoutData(layoutData);
|
for (const ld of allLayoutDatas) {
|
||||||
|
const ids = this.collectNumberingRuleIdsFromLayoutData(ld);
|
||||||
|
ids.forEach((id: string) => ruleIds.add(id));
|
||||||
|
}
|
||||||
|
|
||||||
if (ruleIds.size > 0) {
|
if (ruleIds.size > 0) {
|
||||||
console.log(`🔍 화면 복사 - 채번 규칙 ID 수집: ${ruleIds.size}개`);
|
console.log(`🔍 화면 복사 - 채번 규칙 ID 수집: ${ruleIds.size}개`);
|
||||||
|
|
||||||
// 채번 규칙 복사 및 매핑 생성
|
|
||||||
ruleIdMap = await this.copyNumberingRulesForScreen(
|
ruleIdMap = await this.copyNumberingRulesForScreen(
|
||||||
ruleIds,
|
ruleIds,
|
||||||
sourceScreen.company_code,
|
sourceScreen.company_code,
|
||||||
|
|
@ -4274,15 +4301,50 @@ export class ScreenManagementService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 6. V2 레이아웃이 있다면 복사
|
// 5.2. screen_conditional_zones 복제 + zoneIdMap 생성
|
||||||
if (layoutData && components.length > 0) {
|
const zoneIdMap = new Map<number, number>();
|
||||||
|
if (hasComponents) {
|
||||||
try {
|
try {
|
||||||
// componentId 매핑 생성
|
const zonesResult = await client.query(
|
||||||
const componentIdMap = new Map<string, string>();
|
`SELECT * FROM screen_conditional_zones WHERE screen_id = $1`,
|
||||||
for (const comp of components) {
|
[sourceScreenId]
|
||||||
componentIdMap.set(comp.id, generateId());
|
);
|
||||||
|
|
||||||
|
for (const zone of zonesResult.rows) {
|
||||||
|
const newTriggerCompId = componentIdMap.get(zone.trigger_component_id) || zone.trigger_component_id;
|
||||||
|
const newZone = await client.query<{ zone_id: number }>(
|
||||||
|
`INSERT INTO screen_conditional_zones
|
||||||
|
(screen_id, company_code, zone_name, x, y, width, height,
|
||||||
|
trigger_component_id, trigger_operator)
|
||||||
|
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)
|
||||||
|
RETURNING zone_id`,
|
||||||
|
[newScreen.screen_id, targetCompanyCode, zone.zone_name,
|
||||||
|
zone.x, zone.y, zone.width, zone.height,
|
||||||
|
newTriggerCompId, zone.trigger_operator]
|
||||||
|
);
|
||||||
|
zoneIdMap.set(zone.zone_id, newZone.rows[0].zone_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (zonesResult.rows.length > 0) {
|
||||||
|
console.log(` ↳ 조건부 영역 복사: ${zonesResult.rows.length}개`);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("조건부 영역 복사 중 오류:", error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 6. V2 레이아웃 복사 (모든 레이어 순회)
|
||||||
|
if (sourceLayoutV2Result.rows.length > 0 && hasComponents) {
|
||||||
|
try {
|
||||||
|
let totalComponents = 0;
|
||||||
|
|
||||||
|
for (const layer of sourceLayoutV2Result.rows) {
|
||||||
|
const layoutData = layer.layout_data;
|
||||||
|
const components = layoutData?.components || [];
|
||||||
|
|
||||||
|
if (!layoutData || components.length === 0) continue;
|
||||||
|
totalComponents += components.length;
|
||||||
|
|
||||||
// V2 레이아웃 데이터 복사 및 참조 업데이트
|
// V2 레이아웃 데이터 복사 및 참조 업데이트
|
||||||
const updatedLayoutData = this.updateReferencesInLayoutData(
|
const updatedLayoutData = this.updateReferencesInLayoutData(
|
||||||
layoutData,
|
layoutData,
|
||||||
|
|
@ -4290,23 +4352,38 @@ export class ScreenManagementService {
|
||||||
componentIdMap,
|
componentIdMap,
|
||||||
flowIdMap: flowIdMap.size > 0 ? flowIdMap : undefined,
|
flowIdMap: flowIdMap.size > 0 ? flowIdMap : undefined,
|
||||||
ruleIdMap: ruleIdMap.size > 0 ? ruleIdMap : undefined,
|
ruleIdMap: ruleIdMap.size > 0 ? ruleIdMap : undefined,
|
||||||
// screenIdMap은 모든 화면 복제 완료 후 updateTabScreenReferences에서 일괄 처리
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
// V2 레이아웃 저장 (UPSERT) - layer_id 포함
|
// condition_config의 zone_id 재매핑
|
||||||
|
let updatedConditionConfig = layer.condition_config ? { ...layer.condition_config } : null;
|
||||||
|
if (updatedConditionConfig?.zone_id) {
|
||||||
|
const newZoneId = zoneIdMap.get(updatedConditionConfig.zone_id);
|
||||||
|
if (newZoneId) {
|
||||||
|
updatedConditionConfig.zone_id = newZoneId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// V2 레이아웃 저장 (레이어별 INSERT)
|
||||||
await client.query(
|
await client.query(
|
||||||
`INSERT INTO screen_layouts_v2 (screen_id, company_code, layer_id, layout_data, created_at, updated_at)
|
`INSERT INTO screen_layouts_v2 (screen_id, company_code, layer_id, layer_name, layout_data, condition_config, created_at, updated_at)
|
||||||
VALUES ($1, $2, 1, $3, NOW(), NOW())
|
VALUES ($1, $2, $3, $4, $5, $6, NOW(), NOW())
|
||||||
ON CONFLICT (screen_id, company_code, layer_id)
|
ON CONFLICT (screen_id, company_code, layer_id)
|
||||||
DO UPDATE SET layout_data = $3, updated_at = NOW()`,
|
DO UPDATE SET layout_data = $5, layer_name = $4, condition_config = $6, updated_at = NOW()`,
|
||||||
[newScreen.screen_id, targetCompanyCode, JSON.stringify(updatedLayoutData)],
|
[
|
||||||
|
newScreen.screen_id,
|
||||||
|
targetCompanyCode,
|
||||||
|
layer.layer_id,
|
||||||
|
layer.layer_name,
|
||||||
|
JSON.stringify(updatedLayoutData),
|
||||||
|
updatedConditionConfig ? JSON.stringify(updatedConditionConfig) : null,
|
||||||
|
],
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(` ↳ V2 레이아웃 복사: ${sourceLayoutV2Result.rows.length}개 레이어, ${totalComponents}개 컴포넌트`);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("V2 레이아웃 복사 중 오류:", error);
|
console.error("V2 레이아웃 복사 중 오류:", error);
|
||||||
// 레이아웃 복사 실패해도 화면 생성은 유지
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue