분할패널 수정동작 수정

This commit is contained in:
kjs 2026-01-06 13:43:47 +09:00
parent cded99d644
commit eb61506acd
3 changed files with 242 additions and 6 deletions

View File

@ -775,7 +775,8 @@ export async function getTableData(
const userField = autoFilter?.userField || "companyCode";
const userValue = (req.user as any)[userField];
if (userValue) {
// 🆕 최고 관리자(company_code = '*')는 모든 회사 데이터 조회 가능
if (userValue && userValue !== "*") {
enhancedSearch[filterColumn] = userValue;
logger.info("🔍 현재 사용자 필터 적용:", {
@ -784,6 +785,10 @@ export async function getTableData(
userValue,
tableName,
});
} else if (userValue === "*") {
logger.info("🔓 최고 관리자 - 회사 필터 미적용 (모든 회사 데이터 조회)", {
tableName,
});
} else {
logger.warn("⚠️ 사용자 정보 필드 값 없음:", {
userField,
@ -792,6 +797,9 @@ export async function getTableData(
}
}
// 🆕 최종 검색 조건 로그
logger.info(`🔍 최종 검색 조건 (enhancedSearch):`, JSON.stringify(enhancedSearch));
// 데이터 조회
const result = await tableManagementService.getTableData(tableName, {
page: parseInt(page),

View File

@ -816,14 +816,23 @@ export function TableSectionRenderer({
// 이미 초기화되었으면 스킵
if (initialDataLoadedRef.current) return;
const tableSectionKey = `_tableSection_${sectionId}`;
const tableSectionKey = `__tableSection_${sectionId}`;
const initialData = formData[tableSectionKey];
console.log("[TableSectionRenderer] 초기 데이터 확인:", {
sectionId,
tableSectionKey,
hasInitialData: !!initialData,
initialDataLength: Array.isArray(initialData) ? initialData.length : 0,
formDataKeys: Object.keys(formData).filter(k => k.startsWith("__tableSection_")),
});
if (Array.isArray(initialData) && initialData.length > 0) {
// console.log("[TableSectionRenderer] 초기 데이터 로드:", {
// sectionId,
// itemCount: initialData.length,
// });
console.log("[TableSectionRenderer] 초기 데이터 로드:", {
sectionId,
itemCount: initialData.length,
firstItem: initialData[0],
});
setTableData(initialData);
initialDataLoadedRef.current = true;

View File

@ -588,6 +588,225 @@ export function UniversalFormModalComponent({
}
}
// 🆕 테이블 섹션(type: "table") 디테일 데이터 로드 (마스터-디테일 구조)
// 수정 모드일 때 디테일 테이블에서 데이터 가져오기
if (effectiveInitialData) {
console.log("[initializeForm] 테이블 섹션 디테일 로드 시작", {
sectionsCount: config.sections.length,
effectiveInitialDataKeys: Object.keys(effectiveInitialData),
});
for (const section of config.sections) {
if (section.type !== "table" || !section.tableConfig) {
continue;
}
const tableConfig = section.tableConfig;
const editConfig = tableConfig.editConfig;
const saveConfig = tableConfig.saveConfig;
console.log(`[initializeForm] 테이블 섹션 ${section.id} 검사:`, {
hasEditConfig: !!editConfig,
loadOnEdit: editConfig?.loadOnEdit,
hasSaveConfig: !!saveConfig,
targetTable: saveConfig?.targetTable,
linkColumn: editConfig?.linkColumn,
});
// 수정 모드 로드 설정 확인 (기본값: true)
if (editConfig?.loadOnEdit === false) {
console.log(`[initializeForm] 테이블 섹션 ${section.id}: loadOnEdit=false, 스킵`);
continue;
}
// 디테일 테이블과 연결 정보 확인
const detailTable = saveConfig?.targetTable;
let linkColumn = editConfig?.linkColumn;
if (!detailTable) {
console.log(`[initializeForm] 테이블 섹션 ${section.id}: saveConfig.targetTable 미설정, 스킵`);
continue;
}
// linkColumn이 설정되지 않았으면, 디테일 테이블 컬럼 정보 조회하여 자동 감지
if (!linkColumn?.masterField || !linkColumn?.detailField) {
try {
// 마스터 테이블명 확인 (saveConfig에서)
// 1. customApiSave.multiTable.mainTable.tableName (다중 테이블 저장)
// 2. saveConfig.tableName (단일 테이블 저장)
const masterTable = config.saveConfig?.customApiSave?.multiTable?.mainTable?.tableName
|| config.saveConfig?.tableName;
// 디테일 테이블의 컬럼 목록 조회
const columnsResponse = await apiClient.get(`/table-management/tables/${detailTable}/columns`);
if (columnsResponse.data?.success && columnsResponse.data?.data) {
// API 응답 구조: { success, data: { columns: [...], total, page, ... } }
const columnsArray = columnsResponse.data.data.columns || columnsResponse.data.data || [];
const detailColumnsData = Array.isArray(columnsArray) ? columnsArray : [];
const detailColumns = detailColumnsData.map((col: any) => col.column_name || col.columnName);
const masterKeys = Object.keys(effectiveInitialData);
console.log(`[initializeForm] 테이블 섹션 ${section.id}: 연결 필드 자동 감지`, {
masterTable,
detailTable,
detailColumnsCount: detailColumnsData.length,
});
// 방법 1: 엔티티 관계 기반 감지 (정확)
// 디테일 테이블에서 마스터 테이블을 참조하는 엔티티 컬럼 찾기
if (masterTable) {
for (const col of detailColumnsData) {
const colName = col.column_name || col.columnName;
const inputType = col.input_type || col.inputType;
// 엔티티 타입 컬럼 확인
if (inputType === "entity") {
// reference_table 또는 detail_settings에서 참조 테이블 확인
let refTable = col.reference_table || col.referenceTable;
// detail_settings에서 referenceTable 확인
if (!refTable && col.detail_settings) {
try {
const settings = typeof col.detail_settings === "string"
? JSON.parse(col.detail_settings)
: col.detail_settings;
refTable = settings.referenceTable;
} catch {
// JSON 파싱 실패 무시
}
}
// 마스터 테이블을 참조하는 컬럼 발견
if (refTable === masterTable) {
// 참조 컬럼 확인 (마스터 테이블의 어떤 컬럼을 참조하는지)
let refColumn = col.reference_column || col.referenceColumn;
if (!refColumn && col.detail_settings) {
try {
const settings = typeof col.detail_settings === "string"
? JSON.parse(col.detail_settings)
: col.detail_settings;
refColumn = settings.referenceColumn;
} catch {
// JSON 파싱 실패 무시
}
}
// 마스터 데이터에 해당 컬럼 값이 있는지 확인
if (refColumn && effectiveInitialData[refColumn]) {
console.log(`[initializeForm] 테이블 섹션 ${section.id}: 엔티티 관계 감지 - ${colName}${masterTable}.${refColumn}`);
linkColumn = { masterField: refColumn, detailField: colName };
break;
}
}
}
}
}
// 방법 2: 공통 컬럼 패턴 기반 감지 (폴백)
// 엔티티 관계가 없으면 공통 컬럼명 패턴으로 찾기
if (!linkColumn) {
const priorityPatterns = ["_no", "_number", "_code", "_id"];
for (const pattern of priorityPatterns) {
for (const masterKey of masterKeys) {
if (masterKey.endsWith(pattern) &&
detailColumns.includes(masterKey) &&
effectiveInitialData[masterKey] &&
masterKey !== "id" && masterKey !== "company_code") {
console.log(`[initializeForm] 테이블 섹션 ${section.id}: 공통 컬럼 패턴 감지 - ${masterKey}`);
linkColumn = { masterField: masterKey, detailField: masterKey };
break;
}
}
if (linkColumn) break;
}
}
// 방법 3: 일반 공통 컬럼 (마지막 폴백)
if (!linkColumn) {
for (const masterKey of masterKeys) {
if (detailColumns.includes(masterKey) &&
effectiveInitialData[masterKey] &&
masterKey !== "id" && masterKey !== "company_code" &&
!masterKey.startsWith("__")) {
console.log(`[initializeForm] 테이블 섹션 ${section.id}: 공통 컬럼 감지 - ${masterKey}`);
linkColumn = { masterField: masterKey, detailField: masterKey };
break;
}
}
}
}
} catch (error) {
console.warn(`[initializeForm] 테이블 섹션 ${section.id}: 컬럼 정보 조회 실패`, error);
}
}
if (!linkColumn?.masterField || !linkColumn?.detailField) {
console.log(`[initializeForm] 테이블 섹션 ${section.id}: linkColumn 미설정 및 자동 감지 실패, 스킵`);
continue;
}
// 마스터 테이블의 연결 필드 값 가져오기
const masterValue = effectiveInitialData[linkColumn.masterField];
if (!masterValue) {
console.log(`[initializeForm] 테이블 섹션 ${section.id}: masterField(${linkColumn.masterField}) 값 없음, 스킵`);
continue;
}
try {
console.log(`[initializeForm] 테이블 섹션 ${section.id}: 디테일 데이터 로드 시작`, {
detailTable,
linkColumn,
masterValue,
});
// 디테일 테이블에서 데이터 조회
// operator: "equals"를 사용하여 정확히 일치하는 값만 검색 (엔티티 타입 컬럼에서 중요)
const searchCondition: Record<string, any> = {
[linkColumn.detailField]: { value: masterValue, operator: "equals" },
};
console.log(`[initializeForm] 테이블 섹션 ${section.id}: API 요청 - URL: /table-management/tables/${detailTable}/data`);
console.log(`[initializeForm] 테이블 섹션 ${section.id}: API 요청 - search:`, JSON.stringify(searchCondition));
const response = await apiClient.post(`/table-management/tables/${detailTable}/data`, {
search: searchCondition, // filters가 아닌 search로 전달
page: 1,
size: 1000, // pageSize가 아닌 size로 전달
autoFilter: { enabled: true }, // 멀티테넌시 필터 적용
});
console.log(`[initializeForm] 테이블 섹션 ${section.id}: API 응답 - success: ${response.data?.success}, total: ${response.data?.data?.total}, dataLength: ${response.data?.data?.data?.length}`);
if (response.data?.success) {
// 다양한 응답 구조 처리
let items: any[] = [];
const data = response.data.data;
if (Array.isArray(data)) {
items = data;
} else if (data?.items && Array.isArray(data.items)) {
items = data.items;
} else if (data?.rows && Array.isArray(data.rows)) {
items = data.rows;
} else if (data?.data && Array.isArray(data.data)) {
items = data.data;
}
console.log(`[initializeForm] 테이블 섹션 ${section.id}: ${items.length}건 로드됨`, items);
// 테이블 섹션 데이터를 formData에 저장 (TableSectionRenderer에서 사용)
const tableSectionKey = `__tableSection_${section.id}`;
newFormData[tableSectionKey] = items;
console.log(`[initializeForm] 테이블 섹션 ${section.id}: formData[${tableSectionKey}]에 저장됨`);
}
} catch (error) {
console.error(`[initializeForm] 테이블 섹션 ${section.id}: 디테일 데이터 로드 실패`, error);
}
}
}
setFormData(newFormData);
setRepeatSections(newRepeatSections);
setCollapsedSections(newCollapsed);