fix(RepeaterTable): 조회 컬럼 헤더 라벨 개선 및 코드 정리

헤더에 "컬럼명 - 옵션라벨" 형식으로 전체 정보 표시
옵션 변경 시 컬럼 너비 자동 재계산
API 검색 시 정확한 일치 검색(equals) 적용
디버그 로그 제거
설정 UI 라벨 사용자 친화적으로 변경
This commit is contained in:
SeongHyun Kim
2025-12-19 13:43:26 +09:00
parent c86140fad3
commit 228fd33a2a
4 changed files with 59 additions and 63 deletions

View File

@@ -53,8 +53,10 @@ function convertToRepeaterColumn(col: TableColumnConfig): RepeaterColumnConfig {
enabled: true,
options: col.lookup.options.map((option) => ({
id: option.id,
// displayLabel이 있으면 그것을 사용, 없으면 원래 label 사용
// "컬럼명 - 옵션라벨" 형식으로 헤더에 표시
label: option.displayLabel || option.label,
// 헤더에 표시될 전체 라벨 (컬럼명 - 옵션라벨)
headerLabel: `${col.label} - ${option.displayLabel || option.label}`,
sourceType: "table" as const,
tableConfig: {
tableName: option.tableName,
@@ -131,9 +133,19 @@ async function transformValue(
}
try {
// 정확히 일치하는 검색
const response = await apiClient.post(
`/table-management/tables/${transform.tableName}/data`,
{ search: { [transform.matchColumn]: value }, size: 1, page: 1 }
{
search: {
[transform.matchColumn]: {
value: value,
operator: "equals"
}
},
size: 1,
page: 1
}
);
if (response.data.success && response.data.data?.data?.length > 0) {
@@ -181,11 +193,20 @@ async function fetchExternalLookupValue(
return undefined;
}
// 2. 외부 테이블에서 값 조회
// 2. 외부 테이블에서 값 조회 (정확히 일치하는 검색)
try {
const response = await apiClient.post(
`/table-management/tables/${externalLookup.tableName}/data`,
{ search: { [externalLookup.matchColumn]: matchValue }, size: 1, page: 1 }
{
search: {
[externalLookup.matchColumn]: {
value: matchValue,
operator: "equals"
}
},
size: 1,
page: 1
}
);
if (response.data.success && response.data.data?.data?.length > 0) {
@@ -218,10 +239,7 @@ async function fetchExternalValue(
sourceData: any,
formData: FormDataState
): Promise<any> {
console.log("📡 [fetchExternalValue] 시작:", { tableName, valueColumn, joinConditions });
if (joinConditions.length === 0) {
console.warn("📡 [fetchExternalValue] 조인 조건이 없습니다.");
return undefined;
}
@@ -231,40 +249,29 @@ async function fetchExternalValue(
for (const condition of joinConditions) {
let value: any;
console.log("📡 [fetchExternalValue] 조건 처리:", { condition, rowData, sourceData, formData });
// 값 출처에 따라 가져오기 (4가지 소스 타입 지원)
if (condition.sourceType === "row") {
// 현재 행 데이터 (설정된 컬럼 필드)
value = rowData[condition.sourceField];
console.log("📡 [fetchExternalValue] row에서 값 가져옴:", { field: condition.sourceField, value });
} else if (condition.sourceType === "sourceData") {
// 원본 소스 테이블 데이터 (_sourceData)
value = sourceData?.[condition.sourceField];
console.log("📡 [fetchExternalValue] sourceData에서 값 가져옴:", { field: condition.sourceField, value });
} else if (condition.sourceType === "formData") {
// formData에서 가져오기 (다른 섹션)
value = formData[condition.sourceField];
console.log("📡 [fetchExternalValue] formData에서 값 가져옴:", { field: condition.sourceField, value });
} else if (condition.sourceType === "externalTable" && condition.externalLookup) {
// 외부 테이블에서 조회하여 가져오기
console.log("📡 [fetchExternalValue] externalTable 조회 시작:", condition.externalLookup);
value = await fetchExternalLookupValue(condition.externalLookup, rowData, sourceData, formData);
console.log("📡 [fetchExternalValue] externalTable 조회 결과:", { value });
}
if (value === undefined || value === null || value === "") {
console.warn(`📡 [fetchExternalValue] 조인 조건의 필드 "${condition.sourceField}" 값이 없습니다. (sourceType: ${condition.sourceType})`);
return undefined;
}
// 값 변환이 필요한 경우 (예: 이름 → 코드) - 레거시 호환
if (condition.transform) {
console.log("📡 [fetchExternalValue] 값 변환 시작:", { originalValue: value, transform: condition.transform });
value = await transformValue(value, condition.transform);
console.log("📡 [fetchExternalValue] 값 변환 결과:", { transformedValue: value });
if (value === undefined) {
console.warn(`📡 [fetchExternalValue] 값 변환 후 결과가 없습니다. 원본 값: "${formData[condition.sourceField]}"`);
return undefined;
}
}
@@ -283,28 +290,21 @@ async function fetchExternalValue(
value: convertedValue,
operator: "equals"
};
console.log("📡 [fetchExternalValue] WHERE 조건 추가:", { targetColumn: condition.targetColumn, value: convertedValue });
}
// API 호출
console.log("📡 [fetchExternalValue] API 호출:", { tableName, whereConditions });
const response = await apiClient.post(
`/table-management/tables/${tableName}/data`,
{ search: whereConditions, size: 1, page: 1 }
);
console.log("📡 [fetchExternalValue] API 응답:", response.data);
if (response.data.success && response.data.data?.data?.length > 0) {
const result = response.data.data.data[0][valueColumn];
console.log("📡 [fetchExternalValue] 최종 결과:", { valueColumn, result });
return result;
return response.data.data.data[0][valueColumn];
}
console.warn("📡 [fetchExternalValue] 조회 결과 없음");
return undefined;
} catch (error) {
console.error("📡 [fetchExternalValue] 외부 테이블 조회 오류:", error);
console.error("외부 테이블 조회 오류:", error);
return undefined;
}
}
@@ -581,8 +581,6 @@ export function TableSectionRenderer({
// 컬럼 모드/조회 옵션 변경 핸들러
const handleDataSourceChange = useCallback(
async (columnField: string, optionId: string) => {
console.log("🔍 [handleDataSourceChange] 시작:", { columnField, optionId });
setActiveDataSources((prev) => ({
...prev,
[columnField]: optionId,
@@ -590,23 +588,19 @@ export function TableSectionRenderer({
// 해당 컬럼의 모든 행 데이터 재조회
const column = tableConfig.columns.find((col) => col.field === columnField);
console.log("🔍 [handleDataSourceChange] 컬럼 찾기:", { column: column?.field, hasLookup: column?.lookup?.enabled });
// lookup 설정이 있는 경우 (새로운 조회 기능)
if (column?.lookup?.enabled && column.lookup.options) {
const selectedOption = column.lookup.options.find((opt) => opt.id === optionId);
console.log("🔍 [handleDataSourceChange] 선택된 옵션:", { selectedOption, optionId });
if (!selectedOption) return;
// sameTable 타입: 현재 행의 소스 데이터에서 값 복사 (외부 조회 필요 없음)
if (selectedOption.type === "sameTable") {
console.log("🔍 [handleDataSourceChange] sameTable 타입 - 소스 데이터에서 복사");
const updatedData = tableData.map((row) => {
// sourceField에서 값을 가져와 해당 컬럼에 복사
// row에 _sourceData가 있으면 거기서, 없으면 row 자체에서 가져옴
const sourceData = row._sourceData || row;
const newValue = sourceData[selectedOption.valueColumn] ?? row[columnField];
console.log("🔍 [handleDataSourceChange] sameTable 값 복사:", { valueColumn: selectedOption.valueColumn, sourceData, newValue });
return { ...row, [columnField]: newValue };
});
@@ -616,16 +610,8 @@ export function TableSectionRenderer({
}
// 모든 행에 대해 새 값 조회
console.log("🔍 [handleDataSourceChange] 외부 테이블 조회 시작:", {
type: selectedOption.type,
tableName: selectedOption.tableName,
valueColumn: selectedOption.valueColumn,
conditions: selectedOption.conditions,
tableDataLength: tableData.length,
});
const updatedData = await Promise.all(
tableData.map(async (row, rowIndex) => {
tableData.map(async (row) => {
let newValue: any = row[columnField];
// 조인 조건 구성 (4가지 소스 타입 지원)
@@ -657,13 +643,6 @@ export function TableSectionRenderer({
};
});
console.log(`🔍 [handleDataSourceChange] 행 ${rowIndex} 조회:`, {
rowData: row,
sourceData: row._sourceData,
formData,
joinConditions,
});
// 외부 테이블에서 값 조회 (_sourceData 전달)
const sourceData = row._sourceData || row;
const value = await fetchExternalValue(
@@ -675,8 +654,6 @@ export function TableSectionRenderer({
formData
);
console.log(`🔍 [handleDataSourceChange] 행 ${rowIndex} 조회 결과:`, { value });
if (value !== undefined) {
newValue = value;
}
@@ -688,7 +665,6 @@ export function TableSectionRenderer({
// 계산 필드 업데이트
const calculatedData = calculateAll(updatedData);
handleDataChange(calculatedData);
console.log("🔍 [handleDataSourceChange] 완료:", { calculatedData });
return;
}